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.