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 2013/11/04 13:08:32 UTC

svn commit: r1538572 - in /db/derby/code/branches/10.10: ./ java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/AutoGenJDBC30Test.java

Author: kahatlen
Date: Mon Nov  4 12:08:32 2013
New Revision: 1538572

URL: http://svn.apache.org/r1538572
Log:
DERBY-5823: Multi-row insert fails on table without generated keys with RETURN_GENERATED_KEYS

Merged revision 1537888 from trunk.

Modified:
    db/derby/code/branches/10.10/   (props changed)
    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/jdbcapi/AutoGenJDBC30Test.java

Propchange: db/derby/code/branches/10.10/
------------------------------------------------------------------------------
  Merged /db/derby/code/trunk:r1537888

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=1538572&r1=1538571&r2=1538572&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 Mon Nov  4 12:08:32 2013
@@ -21,6 +21,7 @@
 
 package org.apache.derby.impl.sql.execute;
 
+import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
@@ -96,6 +97,7 @@ class InsertResultSet extends DMLWriteRe
 	//following is for jdbc3.0 feature auto generated keys resultset
 	private  ResultSet			autoGeneratedKeysResultSet;
 	private	TemporaryRowHolderImpl	autoGeneratedKeysRowsHolder;
+    private int[]                   autoGeneratedKeysColumnIndexes;
 
 	// divined at run time
 
@@ -607,10 +609,8 @@ class InsertResultSet extends DMLWriteRe
 		int size = td.getMaxColumnID();
 
 		int[] generatedColumnPositionsArray = new int[size];
+        Arrays.fill(generatedColumnPositionsArray, -1);
 		int generatedColumnNumbers = 0;
-		for (int i=0; i<size; i++) {
-			generatedColumnPositionsArray[i] = -1;
-		}
 
 		for (int i=0; i<size; i++) {
 			cd = td.getColumnDescriptor(i+1);
@@ -988,23 +988,29 @@ class InsertResultSet extends DMLWriteRe
 			rowChanger.setRowHolder(rowHolder);
 		}
 
-		int[] columnIndexes = null;
 		if (firstExecute && activation.getAutoGeneratedKeysResultsetMode())
 		{
 			ResultDescription rd;
 			Properties properties = new Properties();
-			columnIndexes = activation.getAutoGeneratedKeysColumnIndexes();
+            autoGeneratedKeysColumnIndexes =
+                    activation.getAutoGeneratedKeysColumnIndexes();
 
 			// Get the properties on the old heap
 			rowChanger.getHeapConglomerateController().getInternalTablePropertySet(properties);
 
-			if ( columnIndexes != null) {//use user provided column positions array
-				columnIndexes = uniqueColumnPositionArray(columnIndexes);
-			} else { //prepare array of auto-generated keys for the table since user didn't provide any
-				columnIndexes = generatedColumnPositionsArray();
-			}
+            if (autoGeneratedKeysColumnIndexes != null) {
+                // Use user-provided column positions array.
+                autoGeneratedKeysColumnIndexes =
+                    uniqueColumnPositionArray(autoGeneratedKeysColumnIndexes);
+            } else {
+                // Prepare array of auto-generated keys for the table since
+                // user didn't provide any.
+                autoGeneratedKeysColumnIndexes =
+                        generatedColumnPositionsArray();
+            }
 
-			rd = lcc.getLanguageFactory().getResultDescription(resultDescription,columnIndexes);
+            rd = lcc.getLanguageFactory().getResultDescription(
+                    resultDescription, autoGeneratedKeysColumnIndexes);
 			autoGeneratedKeysRowsHolder =
 				new TemporaryRowHolderImpl(activation, properties, rd);
 		}
@@ -1012,8 +1018,14 @@ class InsertResultSet extends DMLWriteRe
 
 		while ( row != null )
 		{
-			if (activation.getAutoGeneratedKeysResultsetMode())
-				autoGeneratedKeysRowsHolder.insert(getCompactRow(row, columnIndexes));
+            // Collect auto-generated keys if requested.
+            // DERBY-5823: No need to collect them if there are no
+            // auto-generated key columns.
+            if (activation.getAutoGeneratedKeysResultsetMode() &&
+                    autoGeneratedKeysColumnIndexes.length > 0) {
+                autoGeneratedKeysRowsHolder.insert(
+                        getCompactRow(row, autoGeneratedKeysColumnIndexes));
+            }
 
             // fill in columns that are computed from expressions on other columns
             evaluateGenerationClauses( generationClauses, activation, sourceResultSet, row, false );

Modified: db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/AutoGenJDBC30Test.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/AutoGenJDBC30Test.java?rev=1538572&r1=1538571&r2=1538572&view=diff
==============================================================================
--- db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/AutoGenJDBC30Test.java (original)
+++ db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/AutoGenJDBC30Test.java Mon Nov  4 12:08:32 2013
@@ -30,7 +30,6 @@ import java.sql.Statement;
 import java.sql.SQLException;
 
 import org.apache.derbyTesting.junit.BaseJDBCTestCase;
-import org.apache.derbyTesting.junit.BaseJDBCTestSetup;
 import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
 import org.apache.derbyTesting.junit.JDBC;
 import org.apache.derbyTesting.junit.TestConfiguration;
@@ -79,6 +78,9 @@ public class AutoGenJDBC30Test extends B
 
         { "t21_noAutoGen",
           "create table t21_noAutoGen (c21 int not null unique, c22 char(5))" },
+
+        { "t21_feed_table",
+          "create table t21_feed_table (c21 int not null unique, c22 char(5))"},
     };
 
     /**
@@ -300,6 +302,50 @@ public class AutoGenJDBC30Test extends B
     }
 
     /**
+     * <p>
+     * Regression test for DERBY-5823 where the temporary row holder code
+     * failed when switching from an in-memory to an on-disk representation.
+     * </p>
+     *
+     * <p>
+     * Note that ideally the transition should never have happened in the first
+     * place, so this test verifies that either the transition logic can deal
+     * with the degenerate case where the row template is zero-length, or the
+     * insert code is smart enough to understand that there are no
+     * auto-generated keys for the query.
+     * </p>
+     */
+    public void testDerby5823() throws SQLException {
+        setAutoCommit(false);
+        PreparedStatement ps = prepareStatement(
+                "insert into t21_feed_table values (?,?)");
+        ps.setString(2, "false");
+        // Just make sure we exceed the threshold for when the temporary row
+        // holder overflows to disk (implementation detail).
+        // When this test was written the threshold was five (5).
+        for (int i=0; i < 250; i++) {
+            ps.setInt(1, i);
+            ps.executeUpdate();
+        }
+        commit();
+        setAutoCommit(true);
+        final String insertSql =
+                "insert into t21_noAutoGen select * from t21_feed_table";
+        // No keys will be auto-generated by the insert query.
+        Statement s = createStatement();
+        s.execute(insertSql,
+                Statement.RETURN_GENERATED_KEYS
+                );
+        verifyNullKey("s.execute()", s.getGeneratedKeys());
+        // For good measure we also test with a prepared statement.
+        s.execute("delete from t21_noAutoGen");
+        // Again, no keys will be auto-generated by the insert query.
+        ps = prepareStatement(insertSql, Statement.RETURN_GENERATED_KEYS);
+        ps.executeUpdate();
+        verifyNullKey("ps.executeUpdate()", ps.getGeneratedKeys());
+    }
+
+    /**
      * Requests generated keys after doing a one-row insert into a table that 
      * has a generated column, but the insert is via a subquery with no where
      * clause.