db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d..@apache.org
Subject svn commit: r1579737 - in /db/derby/code/branches/10.10/java: engine/org/apache/derby/impl/sql/execute/InsertResultSet.java testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java
Date Thu, 20 Mar 2014 21:03:45 GMT
Author: dag
Date: Thu Mar 20 21:03:44 2014
New Revision: 1579737

URL: http://svn.apache.org/r1579737
Log:
DERBY-6374 Bulk insert of data with nullable UNIQUE constraint fails to detect duplicates

Backported to 10.10, had to do major surgery since the original fix
was part of a DERBY-532 patch.


Modified:
    db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
    db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java

Modified: db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java?rev=1579737&r1=1579736&r2=1579737&view=diff
==============================================================================
--- db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
(original)
+++ db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
Thu Mar 20 21:03:44 2014
@@ -27,7 +27,6 @@ import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Properties;
 import java.util.Vector;
-
 import org.apache.derby.catalog.types.StatisticsImpl;
 import org.apache.derby.iapi.db.TriggerExecutionContext;
 import org.apache.derby.iapi.error.StandardException;
@@ -48,8 +47,8 @@ import org.apache.derby.iapi.sql.depend.
 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
-import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
+import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
 import org.apache.derby.iapi.sql.dictionary.StatisticsDescriptor;
 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
 import org.apache.derby.iapi.sql.dictionary.TriggerDescriptor;
@@ -60,6 +59,7 @@ import org.apache.derby.iapi.sql.execute
 import org.apache.derby.iapi.sql.execute.NoPutResultSet;
 import org.apache.derby.iapi.sql.execute.RowChanger;
 import org.apache.derby.iapi.sql.execute.TargetResultSet;
+import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
 import org.apache.derby.iapi.store.access.ColumnOrdering;
 import org.apache.derby.iapi.store.access.ConglomerateController;
 import org.apache.derby.iapi.store.access.GroupFetchScanController;
@@ -1763,29 +1763,24 @@ class InsertResultSet extends DMLWriteRe
 			boolean[] isAscending     = constants.irgs[index].isAscending();
            
 			int numColumnOrderings;
-			SortObserver sortObserver = null;
+            SortObserver sortObserver;
 
 			/* We can only reuse the wrappers when doing an
 			 * external sort if there is only 1 index.  Otherwise,
 			 * we could get in a situation where 1 sort reuses a
 			 * wrapper that is still in use in another sort.
 			 */
-			boolean reuseWrappers = (numIndexes == 1);
-			if (cd.getIndexDescriptor().isUnique())
-			{
-				numColumnOrderings = baseColumnPositions.length;
-				String[] columnNames = getColumnNames(baseColumnPositions);
-
-				String indexOrConstraintName = cd.getConglomerateName();
-				if (cd.isConstraint()) 
-				{
-                    // so, the index is backing up a constraint
+            final boolean reuseWrappers = (numIndexes == 1);
+            final IndexRowGenerator indDes = cd.getIndexDescriptor();
+            final String indexOrConstraintName = cd.getConglomerateName();
+            Properties sortProperties = null;
 
-					ConstraintDescriptor conDesc = 
-                        dd.getConstraintDescriptor(td, cd.getUUID());
+            if (indDes.isUnique())
+            {
+                numColumnOrderings =
+                        indDes.isUnique() ? baseColumnPositions.length :
+                        baseColumnPositions.length + 1;
 
-					indexOrConstraintName = conDesc.getConstraintName();
-				}
 				sortObserver = 
                     new UniqueIndexSortObserver(
                             false, // don't clone rows
@@ -1794,7 +1789,26 @@ class InsertResultSet extends DMLWriteRe
                             indexRows[index],
                             reuseWrappers,
                             td.getName());
-			}
+            } else if (indDes.isUniqueWithDuplicateNulls())
+            {
+                numColumnOrderings = baseColumnPositions.length + 1;
+                // tell transaction controller to use the unique with
+                // duplicate nulls sorter, when making createSort() call.
+                sortProperties = new Properties();
+                sortProperties.put(
+                   AccessFactoryGlobals.IMPL_TYPE,
+                   AccessFactoryGlobals.SORT_UNIQUEWITHDUPLICATENULLS_EXTERNAL);
+                //use sort operator which treats nulls unequal
+                sortObserver =
+                        new UniqueWithDuplicateNullsIndexSortObserver(
+                                false, // don't clone rows
+                                cd.isConstraint(),
+                                indexOrConstraintName,
+                                indexRows[index],
+                                reuseWrappers,
+                                td.getName());
+
+            }
 			else
 			{
 				numColumnOrderings = baseColumnPositions.length + 1;
@@ -1822,7 +1836,7 @@ class InsertResultSet extends DMLWriteRe
 			// create the sorters
 			sortIds[index] = 
                 tc.createSort(
-                    (Properties)null, 
+                    sortProperties,
                     indexRows[index].getRowArrayClone(),
                     ordering[index],
                     sortObserver,

Modified: db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java?rev=1579737&r1=1579736&r2=1579737&view=diff
==============================================================================
--- db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java
(original)
+++ db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullableUniqueConstraintTest.java
Thu Mar 20 21:03:44 2014
@@ -45,6 +45,11 @@ import org.apache.derbyTesting.junit.Tes
  */
 public class NullableUniqueConstraintTest extends BaseJDBCTestCase {
     
+    private static final String LANG_DUPLICATE_KEY_CONSTRAINT = "23505";
+    static String expImpDataFile;          // file used to perform
+                                           // import/export
+    static boolean exportFilesCreated = false;
+
     /**
      * Basic constructor.
      */
@@ -62,7 +67,7 @@ public class NullableUniqueConstraintTes
         TestSuite suite = new TestSuite("NullableUniqueConstraintTest");
         suite.addTest(TestConfiguration.defaultSuite(
                             NullableUniqueConstraintTest.class));
-        return suite;
+        return new SupportFilesSetup(suite);
     }
     
     /**
@@ -73,6 +78,21 @@ public class NullableUniqueConstraintTes
         Statement stmt = con.createStatement();
         stmt.executeUpdate("create table constraintest (val1 varchar (20), " +
                 "val2 varchar (20), val3 varchar (20), val4 varchar (20))");
+        expImpDataFile =
+                SupportFilesSetup.getReadWrite("t.data").getPath();
+
+        if (!exportFilesCreated) {
+            exportFilesCreated = true;
+
+            Statement s = createStatement();
+            s.executeUpdate("create table t(i int)");
+            s.executeUpdate("insert into t values 1,2,2,3");
+            s.executeUpdate(
+                    "call SYSCS_UTIL.SYSCS_EXPORT_TABLE (" +
+                            "    'APP' , 'T' , '" + expImpDataFile + "'," +
+                            "    null, null , null)");
+            s.executeUpdate("drop table t");
+        }
     }
     
     protected void tearDown() throws Exception {
@@ -584,6 +604,42 @@ public class NullableUniqueConstraintTes
         assertTableRowCount("D4081", 0);
     }
 
+    public void testDerby6374() throws SQLException {
+        Statement s = createStatement();
+
+        s.executeUpdate("create table t(i int)");
+
+         try {
+            // Try the test cases below with both "replace" and not with
+            // the import statement:
+            for (int addOrReplace = 0; addOrReplace < 2; addOrReplace++) {
+
+                // Import duplicate data into a table a nullable
+                // UNIQUE constraint
+                s.executeUpdate("alter table t add constraint c unique(i)");
+                commit();
+
+                try {
+                    s.executeUpdate(
+                            "call SYSCS_UTIL.SYSCS_IMPORT_TABLE (" +
+                            "    'APP' , 'T' , '" + expImpDataFile + "'," +
+                            "    null, null , null, " + addOrReplace + ")");
+                    fail("expected duplicates error on commit");
+                } catch (SQLException e) {
+                    assertSQLState(LANG_DUPLICATE_KEY_CONSTRAINT, e);
+                }
+                s.executeUpdate("alter table t drop constraint c");
+            }
+        } finally {
+            try {
+                s.executeUpdate("drop table t");
+                commit();
+            } catch (SQLException e) {
+                e.printStackTrace(System.out);
+            }
+        }
+    }
+
     public static void main(String [] args) {
         TestResult tr = new TestResult();
         Test t = suite();



Mime
View raw message