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 2011/06/06 10:31:52 UTC

svn commit: r1132546 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/BasicSetup.java

Author: kahatlen
Date: Mon Jun  6 08:31:51 2011
New Revision: 1132546

URL: http://svn.apache.org/viewvc?rev=1132546&view=rev
Log:
DERBY-3870: Concurrent Inserts of rows with XML data results in an exception

Allow databases that contain triggers with XML operators to be
upgraded from a version without the fix for this issue to a fixed
version. It used to fail because it couldn't deserialize the old plan
for the trigger. Fix it by not trying to deserialize the plan before
invalidating it.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/BasicSetup.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java?rev=1132546&r1=1132545&r2=1132546&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java Mon Jun  6 08:31:51 2011
@@ -4580,6 +4580,9 @@ public final class	DataDictionaryImpl
 	/**
 	 * Get every statement in this database.
 	 * Return the SPSDescriptors in an list.
+     * The returned descriptors don't contain the compiled statement, so it
+     * it safe to call this method during upgrade when it isn't known if the
+     * saved statement can still be deserialized with the new version.
 	 *
 	 * @return the list of descriptors
 	 *
@@ -4592,7 +4595,23 @@ public final class	DataDictionaryImpl
 
 		List list = newSList();
 
+        // DERBY-3870: The compiled plan may not be possible to deserialize
+        // during upgrade. Skip the column that contains the compiled plan to
+        // prevent deserialization errors when reading the rows. We don't care
+        // about the value in that column, since this method is only called
+        // when we want to drop or invalidate rows in SYSSTATEMENTS.
+        FormatableBitSet cols = new FormatableBitSet(
+                ti.getCatalogRowFactory().getHeapColumnCount());
+        for (int i = 0; i < cols.size(); i++) {
+            if (i + 1 == SYSSTATEMENTSRowFactory.SYSSTATEMENTS_CONSTANTSTATE) {
+                cols.clear(i);
+            } else {
+                cols.set(i);
+            }
+        }
+
 		getDescriptorViaHeap(
+                        cols,
 						(ScanQualifier[][]) null,
 						ti,
 						(TupleDescriptor) null,
@@ -4647,6 +4666,7 @@ public final class	DataDictionaryImpl
 		GenericDescriptorList list = new GenericDescriptorList();
 
 		getDescriptorViaHeap(
+                        null,
 						(ScanQualifier[][]) null,
 						ti,
 						(TupleDescriptor) null,
@@ -7039,10 +7059,7 @@ public final class	DataDictionaryImpl
   				false);
 
 		ConglomerateDescriptorList cdl = new ConglomerateDescriptorList();
-		getDescriptorViaHeap(scanQualifier,
-								 ti,
-								 null,
-								 cdl);
+		getDescriptorViaHeap(null, scanQualifier, ti, null, cdl);
 
 		int size = cdl.size();
 		ConglomerateDescriptor[] cda = new ConglomerateDescriptor[size];
@@ -9475,6 +9492,8 @@ public final class	DataDictionaryImpl
 	 * Return a (single or list of) catalog row descriptor(s) from a
 	 * system table where the access a heap scan
 	 *
+     * @param columns                   which columns to fetch from the system
+     *                                  table, or null to fetch all columns
 	 * @param scanQualifiers			qualifiers
 	 * @param ti						The TabInfoImpl to use
 	 * @param parentTupleDescriptor		The parentDescriptor, if applicable.
@@ -9486,6 +9505,7 @@ public final class	DataDictionaryImpl
 	 * @exception StandardException		Thrown on error
 	 */
 	protected TupleDescriptor getDescriptorViaHeap(
+                        FormatableBitSet columns,
 						ScanQualifier [][] scanQualifiers,
 						TabInfoImpl ti,
 						TupleDescriptor parentTupleDescriptor,
@@ -9513,7 +9533,7 @@ public final class	DataDictionaryImpl
 				0, 							// for read
 				TransactionController.MODE_TABLE,
                 TransactionController.ISOLATION_REPEATABLE_READ,
-				(FormatableBitSet) null,         // all fields as objects
+				columns,
 				(DataValueDescriptor[]) null,		// start position - first row
 				0,      				// startSearchOperation - none
 				scanQualifiers, 		// scanQualifier,

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/BasicSetup.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/BasicSetup.java?rev=1132546&r1=1132545&r2=1132546&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/BasicSetup.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/BasicSetup.java Mon Jun  6 08:31:51 2011
@@ -29,6 +29,7 @@ import java.util.ArrayList;
 
 import org.apache.derbyTesting.junit.JDBC;
 import org.apache.derbyTesting.junit.TestConfiguration;
+import org.apache.derbyTesting.junit.XML;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -43,7 +44,13 @@ public class BasicSetup extends UpgradeC
         TestSuite suite = new TestSuite("Upgrade basic setup");
         
         suite.addTestSuite(BasicSetup.class);
-        
+
+        if (XML.classpathMeetsXMLReqs()) {
+            // Only test XML operators if they are supported by the version
+            // we upgrade to.
+            suite.addTest(new BasicSetup("xmlTestTriggerWithXMLOperators"));
+        }
+
         return suite;
     }
 
@@ -772,4 +779,62 @@ public class BasicSetup extends UpgradeC
         return buffer.toString();
     }
     //End of helper methods for testExhuastivePermutationOfTriggerColumns
+
+    /**
+     * Test that triggers that use XML operators work after upgrade. The
+     * first fix for DERBY-3870 broke upgrade of such triggers because the
+     * old execution plans failed to deserialize on the new version.
+     */
+    public void xmlTestTriggerWithXMLOperators() throws SQLException {
+        if (!oldAtLeast(10, 3)) {
+            // Before 10.3, the CREATE TRIGGER statement used in the test
+            // failed with a syntax error. Skip the test for older versions.
+            return;
+        }
+
+        Statement s = createStatement();
+
+        if (getPhase() == PH_CREATE) {
+            // Create test tables and a trigger that uses XML operators with
+            // the old version.
+            s.execute("create table d3870_t1(i int, x varchar(100))");
+            s.execute("create table d3870_t2(i int)");
+            try {
+                s.execute("create trigger d3870_tr after insert on d3870_t1 " +
+                          "for each statement insert into d3870_t2 " +
+                          "select i from d3870_t1 where " +
+                          "xmlexists('//a' passing by ref " +
+                          "xmlparse(document x preserve whitespace))");
+            } catch (SQLException sqle) {
+                // The CREATE TRIGGER statement will fail if the XML classpath
+                // requirements aren't satisfied for the old version. That's
+                // OK, but we'll have to skip the test for this combination.
+                assertSQLState("XML00", sqle);
+                return;
+            }
+        } else {
+            // Delete the rows to start the test from a known state in each
+            // of the phases.
+            s.executeUpdate("delete from d3870_t1");
+            s.executeUpdate("delete from d3870_t2");
+        }
+
+        // Check if the trigger exists. It won't exist if the XML requirements
+        // weren't satisfied for the old version. If we don't have the trigger,
+        // we skip the rest of the test.
+        ResultSet rs = s.executeQuery(
+            "select 1 from sys.systriggers where triggername = 'D3870_TR'");
+        boolean hasTrigger = rs.next();
+        rs.close();
+
+        // Verify that the trigger works both before and after upgrade.
+        if (hasTrigger) {
+            s.execute("insert into d3870_t1 values " +
+                      "(1, '<a/>'), (2, '<b/>'), (3, '<c/>')");
+
+            JDBC.assertSingleValueResultSet(
+                    s.executeQuery("select * from d3870_t2"), "1");
+        }
+    }
+
 }