You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ka...@apache.org on 2014/03/05 08:57:04 UTC
svn commit: r1574389 - in /db/derby/code/branches/10.10: ./
java/engine/org/apache/derby/iapi/sql/dictionary/
java/engine/org/apache/derby/impl/sql/catalog/
java/storeless/org/apache/derby/impl/storeless/
java/testing/org/apache/derbyTesting/functionTe...
Author: kahatlen
Date: Wed Mar 5 07:57:03 2014
New Revision: 1574389
URL: http://svn.apache.org/r1574389
Log:
DERBY-4160: getMetaData().getIndexInfo crashes with "ERROR X0Y68: Column 'PARAM1' already exists."
Merged revision 1570488 from trunk.
Modified:
db/derby/code/branches/10.10/ (props changed)
db/derby/code/branches/10.10/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java
db/derby/code/branches/10.10/java/engine/org/apache/derby/iapi/sql/dictionary/SPSDescriptor.java
db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
db/derby/code/branches/10.10/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java
db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DatabaseMetaDataTest.java
Propchange: db/derby/code/branches/10.10/
------------------------------------------------------------------------------
Merged /db/derby/code/trunk:r1570488
Modified: db/derby/code/branches/10.10/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java?rev=1574389&r1=1574388&r2=1574389&view=diff
==============================================================================
--- db/derby/code/branches/10.10/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java (original)
+++ db/derby/code/branches/10.10/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java Wed Mar 5 07:57:03 2014
@@ -1124,18 +1124,13 @@ public interface DataDictionary
* @param spsd The descriptor to add
* @param tc The transaction controller
* @param recompile whether to recompile or invalidate
- * @param updateSYSCOLUMNS indicate whether syscolumns needs to be updated
- * or not.
- * @param firstCompilation first time SPS is getting compiled.
*
* @exception StandardException Thrown on error
*/
public void updateSPS(
SPSDescriptor spsd,
TransactionController tc,
- boolean recompile,
- boolean updateSYSCOLUMNS,
- boolean firstCompilation)
+ boolean recompile)
throws StandardException;
/**
Modified: db/derby/code/branches/10.10/java/engine/org/apache/derby/iapi/sql/dictionary/SPSDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/engine/org/apache/derby/iapi/sql/dictionary/SPSDescriptor.java?rev=1574389&r1=1574388&r2=1574389&view=diff
==============================================================================
--- db/derby/code/branches/10.10/java/engine/org/apache/derby/iapi/sql/dictionary/SPSDescriptor.java (original)
+++ db/derby/code/branches/10.10/java/engine/org/apache/derby/iapi/sql/dictionary/SPSDescriptor.java Wed Mar 5 07:57:03 2014
@@ -134,7 +134,7 @@ public class SPSDescriptor extends Tuple
* Old code - never used.
*/
private Object paramDefaults[];
- private boolean initiallyCompilable;
+ private final boolean initiallyCompilable;
private boolean lookedUpParams;
private UUIDFactory uuidFactory;
@@ -691,6 +691,8 @@ public class SPSDescriptor extends Tuple
if (!lcc.getDataDictionary().isReadOnlyUpgrade()) {
+ final String savepoint = lcc.getUniqueSavepointName();
+
// First try compiling in a nested transaction so we can
// release the locks after the compilation, and not have them
// sit around in the parent transaction. But if we get lock
@@ -714,6 +716,11 @@ public class SPSDescriptor extends Tuple
// When retrying in the user transaction, we'll wait for
// locks if necessary.
nestedTC.setNoLockWait(true);
+
+ // Set a savepoint so that the work in the nested
+ // transaction can be rolled back on error without
+ // aborting the parent transaction.
+ nestedTC.setSavePoint(savepoint, null);
}
catch (StandardException se)
{
@@ -722,12 +729,6 @@ public class SPSDescriptor extends Tuple
nestedTC = null;
}
- // DERBY-2584: If the first attempt to compile the query fails,
- // we need to reset initiallyCompilable to make sure the
- // prepared plan is fully stored to disk. Save the initial
- // value here.
- final boolean compilable = initiallyCompilable;
-
try
{
prepareAndRelease(lcc, null, nestedTC);
@@ -735,7 +736,16 @@ public class SPSDescriptor extends Tuple
}
catch (StandardException se)
{
- if (se.isLockTimeout())
+ if (nestedTC != null)
+ {
+ // Roll back to savepoint to undo any work done by
+ // the nested transaction. We cannot abort the nested
+ // transaction in order to achieve the same, since
+ // that would also abort the parent transaction.
+ nestedTC.rollbackToSavePoint(savepoint, false, null);
+ }
+
+ if (nestedTC != null && se.isLockTimeout())
{
// Locks were set nowait, so a lock timeout here
// means that some lock request in the nested
@@ -743,18 +753,14 @@ public class SPSDescriptor extends Tuple
// with a parent lock would lead to a undetected
// deadlock so must give up trying in the nested
// transaction and retry with parent transaction.
- if (nestedTC != null)
- {
- nestedTC.commit();
- nestedTC.destroy();
- nestedTC = null;
- }
+ nestedTC.commit();
+ nestedTC.destroy();
+ nestedTC = null;
// if we couldn't do this with a nested transaction,
// retry with parent-- we need to wait this time!
// Lock conflicts at this point are with other
// transactions, so must wait.
- initiallyCompilable = compilable;
prepareAndRelease(lcc, null, null);
updateSYSSTATEMENTS(lcc, RECOMPILE, null);
}
@@ -1099,24 +1105,6 @@ public class SPSDescriptor extends Tuple
private void updateSYSSTATEMENTS(LanguageConnectionContext lcc, int mode, TransactionController tc)
throws StandardException
{
- boolean updateSYSCOLUMNS, recompile;
- boolean firstCompilation = false;
- if (mode == RECOMPILE)
- {
- recompile = true;
- updateSYSCOLUMNS = true;
- if(!initiallyCompilable)
- {
- firstCompilation = true;
- initiallyCompilable = true;
- }
- }
- else
- {
- recompile = false;
- updateSYSCOLUMNS = false;
- }
-
DataDictionary dd = getDataDictionary();
if (dd.isReadOnlyUpgrade())
@@ -1132,11 +1120,7 @@ public class SPSDescriptor extends Tuple
tc = lcc.getTransactionExecute();
}
- dd.updateSPS(this,
- tc,
- recompile,
- updateSYSCOLUMNS,
- firstCompilation);
+ dd.updateSPS(this, tc, (mode == RECOMPILE));
}
/**
Modified: db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java?rev=1574389&r1=1574388&r2=1574389&view=diff
==============================================================================
--- db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java (original)
+++ db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java Wed Mar 5 07:57:03 2014
@@ -4432,19 +4432,13 @@ public final class DataDictionaryImpl
* @param spsd The descriptor to add
* @param tc The transaction controller
* @param recompile Whether to recompile or invalidate
- * @param updateParamDescriptors If true, will update the
- * parameter descriptors in SYS.SYSCOLUMNS.
- * @param firstCompilation true, if Statement is getting compiled for first
- * time and SPS was created with NOCOMPILE option.
*
* @exception StandardException Thrown on error
*/
public void updateSPS(
SPSDescriptor spsd,
TransactionController tc,
- boolean recompile,
- boolean updateParamDescriptors,
- boolean firstCompilation)
+ boolean recompile)
throws StandardException
{
ExecIndexRow keyRow1 = null;
@@ -4455,23 +4449,13 @@ public final class DataDictionaryImpl
int[] updCols;
if (recompile)
{
- if(firstCompilation)
- {
- updCols = new int[] {SYSSTATEMENTSRowFactory.SYSSTATEMENTS_VALID,
- SYSSTATEMENTSRowFactory.SYSSTATEMENTS_TEXT,
- SYSSTATEMENTSRowFactory.SYSSTATEMENTS_LASTCOMPILED,
- SYSSTATEMENTSRowFactory.SYSSTATEMENTS_USINGTEXT,
- SYSSTATEMENTSRowFactory.SYSSTATEMENTS_CONSTANTSTATE,
- SYSSTATEMENTSRowFactory.SYSSTATEMENTS_INITIALLY_COMPILABLE};
- }else
- {
-
- updCols = new int[] {SYSSTATEMENTSRowFactory.SYSSTATEMENTS_VALID,
- SYSSTATEMENTSRowFactory.SYSSTATEMENTS_TEXT,
- SYSSTATEMENTSRowFactory.SYSSTATEMENTS_LASTCOMPILED,
- SYSSTATEMENTSRowFactory.SYSSTATEMENTS_USINGTEXT,
- SYSSTATEMENTSRowFactory.SYSSTATEMENTS_CONSTANTSTATE };
- }
+ updCols = new int[] {
+ SYSSTATEMENTSRowFactory.SYSSTATEMENTS_VALID,
+ SYSSTATEMENTSRowFactory.SYSSTATEMENTS_TEXT,
+ SYSSTATEMENTSRowFactory.SYSSTATEMENTS_LASTCOMPILED,
+ SYSSTATEMENTSRowFactory.SYSSTATEMENTS_USINGTEXT,
+ SYSSTATEMENTSRowFactory.SYSSTATEMENTS_CONSTANTSTATE,
+ };
}
else
{
@@ -4507,11 +4491,9 @@ public final class DataDictionaryImpl
tc);
- /*
- ** If we don't need to update the parameter
- ** descriptors, we are done.
- */
- if (!updateParamDescriptors)
+ // If this is an invalidation request, we don't need to update the
+ // parameter descriptors, so we are done.
+ if (!recompile)
{
return;
}
@@ -4526,58 +4508,11 @@ public final class DataDictionaryImpl
return;
}
- if(firstCompilation)
- {
- /*beetle:5119, reason for doing add here instead of update
- *is with NOCOMPILE option of create statement/boot time SPS,
- *SPS statement is not compiled to find out the parameter info.
- *Because of the parameter info was not inserted at SPSDescriptor
- *creation time. As this is the first time we are compiling parameter
- *infor should be inserted instead of the update.
- */
- addSPSParams(spsd, tc);
- }
- else
- {
- Object[] parameterDefaults = spsd.getParameterDefaults();
-
- /*
- ** Update each column with the new defaults and with
- ** the new datatypes. It is possible that someone has
- ** done a drop/create on the underlying table and
- ** changed the type of a column, which has changed
- ** the type of a parameter to our statement.
- */
- int[] columnsToSet = new int[2];
- columnsToSet[0] = SYSCOLUMNSRowFactory.SYSCOLUMNS_COLUMNDATATYPE;
- columnsToSet[1] = SYSCOLUMNSRowFactory.SYSCOLUMNS_COLUMNDEFAULT;
-
- UUID uuid = spsd.getUUID();
-
- for (int index = 0; index < params.length; index++)
- {
- int parameterId = index + 1;
-
- //RESOLVEAUTOINCREMENT
- ColumnDescriptor cd = new ColumnDescriptor("PARAM" + parameterId,
- parameterId, // position
- params[index],
- ((parameterDefaults == null) || // default
- (index >= parameterDefaults.length)) ?
- (DataValueDescriptor)null :
- (DataValueDescriptor)parameterDefaults[index],
- (DefaultInfo) null,
- uuid,
- (UUID) null,
- 0, 0, 0);
-
- updateColumnDescriptor(cd,
- cd.getReferencingUUID(),
- cd.getColumnName(),
- columnsToSet,
- tc);
- }
- }
+ // Update the parameter descriptors by dropping the existing ones
+ // and recreating them. If this is the first time the SPS is being
+ // compiled, the drop operation will be a no-op.
+ dropAllColumnDescriptors(spsd.getUUID(), tc);
+ addSPSParams(spsd, tc);
}
/**
Modified: db/derby/code/branches/10.10/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java?rev=1574389&r1=1574388&r2=1574389&view=diff
==============================================================================
--- db/derby/code/branches/10.10/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java (original)
+++ db/derby/code/branches/10.10/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java Wed Mar 5 07:57:03 2014
@@ -478,8 +478,7 @@ public class EmptyDictionary implements
}
public void updateSPS(SPSDescriptor spsd, TransactionController tc,
- boolean recompile, boolean updateSYSCOLUMNS,
- boolean firstCompilation) throws StandardException {
+ boolean recompile) throws StandardException {
// Auto-generated method stub
}
Modified: db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DatabaseMetaDataTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DatabaseMetaDataTest.java?rev=1574389&r1=1574388&r2=1574389&view=diff
==============================================================================
--- db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DatabaseMetaDataTest.java (original)
+++ db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DatabaseMetaDataTest.java Wed Mar 5 07:57:03 2014
@@ -63,6 +63,7 @@ import org.apache.derbyTesting.junit.JDB
import org.apache.derbyTesting.junit.TestConfiguration;
//import org.apache.derby.shared.common.reference.JDBC40Translation;
import org.apache.derbyTesting.functionTests.tests.upgradeTests.Version;
+import org.apache.derbyTesting.functionTests.util.Barrier;
/**
* Test the DatabaseMetaData api.
@@ -236,6 +237,11 @@ public class DatabaseMetaDataTest extend
TestConfiguration.singleUseDatabaseDecorator(
new DatabaseMetaDataTest("initialCompilationTest")));
+ // The test for DERBY-4160 needs a fresh database to ensure that the
+ // meta-data queries haven't already been compiled.
+ suite.addTest(TestConfiguration.singleUseDatabaseDecorator(
+ new DatabaseMetaDataTest("concurrentCompilationTest")));
+
// Test for DERBY-3693 needs a fresh database to ensure that the size
// of SYSTABLES is so small that creating a relatively small number of
// tables will cause the query plan for getTables() to be invalidated.
@@ -332,6 +338,66 @@ public class DatabaseMetaDataTest extend
}
/**
+ * Test that a meta-data query is compiled and stored correctly even when
+ * there's a lock conflict that causes the first attempt to store it to
+ * stop midway (DERBY-4160). This test needs a fresh database so that the
+ * meta-data calls are not already compiled.
+ */
+ public void concurrentCompilationTest() throws Exception {
+ // Create a barrier that can be used to synchronize the two threads
+ // so they perform the meta-data compilation at the same time.
+ final Barrier barrier = new Barrier(2);
+
+ // Create a thread thread that attempts to compile meta-data queries.
+ final DatabaseMetaData dmd = getDMD();
+ final Exception[] exception = new Exception[1];
+ Thread th = new Thread() {
+ public void run() {
+ try {
+ concurrentCompilationTestHelper(barrier, dmd);
+ } catch (Exception e) {
+ exception[0] = e;
+ }
+ }
+ };
+ th.start();
+
+ // At the same time, in the main thread, attempt to compile the same
+ // meta-data queries.
+ Connection c2 = openDefaultConnection();
+ concurrentCompilationTestHelper(barrier, c2.getMetaData());
+ c2.close();
+
+ // Wait until both threads are done.
+ th.join();
+
+ // Check if the helper thread got any exceptions.
+ if (exception[0] != null) {
+ fail("Exception in other thread", exception[0]);
+ }
+
+ // Finally, verify that the two meta-data methods used in the test
+ // are working.
+ testGetBestRowIdentifier();
+ testGetIndexInfo();
+ }
+
+ private void concurrentCompilationTestHelper(
+ Barrier barrier, DatabaseMetaData dmd) throws Exception {
+ // Wait until the other thread is ready to start, so that the
+ // compilation happens at the same time in both threads.
+ barrier.await();
+
+ // Often, but not always, the getIndexInfo() call would fail
+ // in one of the threads with the following error message:
+ // ERROR X0Y68: Column 'PARAM1' already exists.
+ ResultSet rs1 = dmd.getBestRowIdentifier(null, null, "", 0, true);
+ ResultSet rs2 = dmd.getIndexInfo(null, null, "", true, true);
+ JDBC.assertDrainResults(rs1);
+ JDBC.assertDrainResults(rs2);
+ }
+
+ /**
* Tests that we don't get an internal timeout when a meta-data statement
* is recompiled because the size of the tables it queries has changed
* (DERBY-3693). The test must be run on a fresh database, to ensure that