Index: java/build/org/apache/derbyBuild/splitmessages.java =================================================================== --- java/build/org/apache/derbyBuild/splitmessages.java (revision 628487) +++ java/build/org/apache/derbyBuild/splitmessages.java (working copy) @@ -117,6 +117,7 @@ clientMessageIds.add(SQLState.NET_PGNAMCSN_INVALID_AT_SQLAM); clientMessageIds.add(SQLState.NET_VCM_VCS_LENGTHS_INVALID); clientMessageIds.add(SQLState.LANG_STRING_TOO_LONG); + clientMessageIds.add(SQLState.INVALID_COLUMN_ARRAY_LENGTH); } public static void main(String[] args) throws Exception { Index: java/engine/org/apache/derby/loc/messages.xml =================================================================== --- java/engine/org/apache/derby/loc/messages.xml (revision 628487) +++ java/engine/org/apache/derby/loc/messages.xml (working copy) @@ -2775,6 +2775,12 @@ + X0X0D.S + Invalid column array length '{0}'. Column array must be of length 1 and contain only the identity column. + columnArrayLength + + + X0X0E.S Table '{1}' does not have an auto-generated column at column position '{0}'. columnPosition Index: java/shared/org/apache/derby/shared/common/reference/SQLState.java =================================================================== --- java/shared/org/apache/derby/shared/common/reference/SQLState.java (revision 628487) +++ java/shared/org/apache/derby/shared/common/reference/SQLState.java (working copy) @@ -1273,6 +1273,7 @@ String LANG_CANT_INVALIDATE_OPEN_RESULT_SET = "X0X95.S"; String LANG_CANT_CHANGE_ISOLATION_HOLD_CURSOR = "X0X03.S"; //following three for auto-generated keys feature in JDBC3.0 + String INVALID_COLUMN_ARRAY_LENGTH = "X0X0D.S"; String LANG_INVALID_AUTOGEN_COLUMN_POSITION = "X0X0E.S"; String LANG_INVALID_AUTOGEN_COLUMN_NAME = "X0X0F.S"; Index: java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/StatementJdbc30Test.java =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/StatementJdbc30Test.java (revision 628487) +++ java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/StatementJdbc30Test.java (working copy) @@ -255,13 +255,10 @@ * @param ex */ private void assertFailedExecuteUpdateForColumnName(SQLException ex) { - /* - * DERBY-2943 -- execute() and executeUpdate() return different - * SQLState in embedded and network client - * - */ + // Derby client complains that the array is too long. + // Embedded is smart enough to know which column caused the problem. if (usingDerbyNetClient()) { - assertSQLState("0A000", ex); + assertSQLState("X0X0D", ex); } else { assertSQLState("X0X0F", ex); } Index: java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/AutoGenJDBC30Test.java =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/AutoGenJDBC30Test.java (revision 628487) +++ java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/AutoGenJDBC30Test.java (working copy) @@ -1011,58 +1011,6 @@ } /** - * Verifies that an exception is raised if a columnNames array is passed, - * which signals the driver that the auto-generated keys indicated in the - * given array should be made available for retrieval (feature not - * supported). - * Old master Test22, Test22ps - * Expected result: Exception 0A000 should occur. - * @throws SQLException - */ - public void testColumnNamesNotImpl() throws SQLException - { - /* As of DERBY-2631 we support this with embedded. So do nothing - * for this test fixture; we'll test the functionality as part - * of a separate fixture. - */ - if (usingEmbedded()) - return; - - Statement s = createStatement(); - String colNames[] = new String[1]; - colNames[0] = "C11"; - - String sql="insert into t11_AutoGen(c11) " + - "select c21 from t21_noAutoGen"; - - try { - s.execute(sql, colNames); - fail("Expected s.execute to fail"); - } catch (SQLException se) { - assertSQLState("0A000", se.getSQLState(), se); - } - - try { - s.executeUpdate(sql, colNames); - fail("Expected s.executeUpdate to fail"); - } catch (SQLException se) { - assertSQLState("0A000", se.getSQLState(), se); - } - - try { - /* Deliberately not adding this prepareStatement wrapper to - * BaseJDBCTestCase.java because Derby doesn't support passing - * the array. - */ - Connection conn = getConnection(); - PreparedStatement ps=conn.prepareStatement(sql, colNames); - fail("Expected prepareStatement to fail"); - } catch (SQLException se) { - assertSQLState("0A000", se.getSQLState(), se); - } - } - - /** * Test that use of columnIndexes to indicate which keys should be * made available works as expected. * @@ -1131,22 +1079,24 @@ */ public void testColumnNames() throws SQLException { - /* Not supported for Derby client. We check the "not supported" - * error message as part of a different fixture. - */ - if (usingDerbyNetClient()) - return; - + // Valid (typical) usage. String [] colNames = new String [] { "C12" }; testUserGivenColumns(null, colNames, 1); + // column name array is of length > 1 + colNames = new String[] {"C12","C13"}; + testUserGivenColumnsError(null, colNames); + + if (usingDerbyNetClient()) + return; + // Non-existent column name. - colNames[0] = "NOTTHERE"; + colNames= new String[] {"NOTTHERE"}; testUserGivenColumnsError(null, colNames); - + // Valid column name but not an auto-gen column. colNames[0] = "C11"; @@ -1206,24 +1156,12 @@ */ public void testUserGivenColumnsNull() throws SQLException { - /* Not supported for Derby client. We check the "not supported" - * error message as part of a different fixture. - */ - if (usingDerbyNetClient()) - return; - + Statement s = createStatement(); String sql="insert into t11_AutoGen(c11) values (99)"; - s.execute(sql, (int[]) null); - assertNull("Expected NULL ResultSet after s.execute()", - s.getGeneratedKeys()); - - s.executeUpdate(sql, (int[]) null); - assertNull("Expected NULL ResultSet after s.executeUpdate()", - s.getGeneratedKeys()); - + s.execute(sql, (String[]) null); assertNull("Expected NULL ResultSet after s.execute()", s.getGeneratedKeys()); @@ -1232,29 +1170,43 @@ assertNull("Expected NULL ResultSet after s.executeUpdate()", s.getGeneratedKeys()); - s.close(); - PreparedStatement ps = prepareStatement(sql, (int[]) null); + PreparedStatement ps; + ps = prepareStatement(sql, (String[]) null); ps.execute(); assertNull("Expected NULL ResultSet after ps.execute()", ps.getGeneratedKeys()); - ps = prepareStatement(sql, (int[]) null); + ps = prepareStatement(sql, (String[]) null); ps.executeUpdate(); assertNull("Expected NULL ResultSet after ps.executeUpdate()", ps.getGeneratedKeys()); + + // No columnIndexes yet for derby client. + if (usingDerbyNetClient()) + return; + + s.execute(sql, (int[]) null); + assertNull("Expected NULL ResultSet after s.execute()", + s.getGeneratedKeys()); - ps = prepareStatement(sql, (String[]) null); + s.executeUpdate(sql, (int[]) null); + assertNull("Expected NULL ResultSet after s.executeUpdate()", + s.getGeneratedKeys()); + + ps = prepareStatement(sql, (int[]) null); ps.execute(); assertNull("Expected NULL ResultSet after ps.execute()", ps.getGeneratedKeys()); - ps = prepareStatement(sql, (String[]) null); + ps = prepareStatement(sql, (int[]) null); ps.executeUpdate(); assertNull("Expected NULL ResultSet after ps.executeUpdate()", ps.getGeneratedKeys()); + ps.close(); + } // Local utility methods. @@ -1350,7 +1302,11 @@ boolean useIndexes = (colIndexes != null); String expectedSQLState = (useIndexes ? "X0X0E" : "X0X0F"); - + // Derby client will only give an error if colNames array is not of length 1. + if (usingDerbyNetClient() && colNames != null && + colNames.length != 1) + expectedSQLState = "X0X0D"; + Statement s = createStatement(); String sql="insert into t11_AutoGen(c11) values (99)"; Index: java/client/org/apache/derby/client/am/Connection.java =================================================================== --- java/client/org/apache/derby/client/am/Connection.java (revision 628487) +++ java/client/org/apache/derby/client/am/Connection.java (working copy) @@ -1635,7 +1635,6 @@ int autoGeneratedKeys, String[] columnNames) throws SqlException { checkForClosedConnection(); - checkAutoGeneratedKeysParameters(autoGeneratedKeys, columnNames); resultSetType = downgradeResultSetType(resultSetType); PreparedStatement ps = newPreparedStatement_(sql, resultSetType, resultSetConcurrency, resultSetHoldability, autoGeneratedKeys, columnNames); ps.cursorAttributesToSendOnPrepare_ = ps.cacheCursorAttributesToSendOnPrepare(); @@ -1741,11 +1740,13 @@ if (agent_.loggingEnabled()) { agent_.logWriter_.traceEntry(this, "prepareStatement", sql, columnNames); } + int genKeys = (columnNames == null ? Statement.NO_GENERATED_KEYS: + Statement.RETURN_GENERATED_KEYS); PreparedStatement ps = prepareStatementX(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, holdability(), - java.sql.Statement.RETURN_GENERATED_KEYS, + genKeys, columnNames); if (agent_.loggingEnabled()) { agent_.logWriter_.traceExit(this, "prepareStatement", ps); @@ -2070,22 +2071,6 @@ } } - void checkAutoGeneratedKeysParameters(int autoGeneratedKeys, String[] columnNames) throws SqlException { - if (autoGeneratedKeys != java.sql.Statement.NO_GENERATED_KEYS && - autoGeneratedKeys != java.sql.Statement.RETURN_GENERATED_KEYS) { - throw new SqlException(agent_.logWriter_, - new ClientMessageId(SQLState.BAD_AUTO_GEN_KEY_VALUE), - new Integer (autoGeneratedKeys)); - } - - if (columnNames != null) { - throw new SqlException(agent_.logWriter_, - new ClientMessageId (SQLState.NOT_IMPLEMENTED), - "getAutoGeneratedKeys(columnNames == null)"); - } - - } - public boolean isXAConnection() { return isXAConnection_; } Index: java/client/org/apache/derby/client/am/Statement.java =================================================================== --- java/client/org/apache/derby/client/am/Statement.java (revision 628780) +++ java/client/org/apache/derby/client/am/Statement.java (working copy) @@ -1211,6 +1211,8 @@ if (agent_.loggingEnabled()) { agent_.logWriter_.traceEntry(this, "executeUpdate", sql, columnNames); } + if (columnNames != null) + autoGeneratedKeys_ = Statement.RETURN_GENERATED_KEYS; generatedKeysColumnNames_ = columnNames; int updateValue = executeUpdateX(sql); if (agent_.loggingEnabled()) { @@ -1270,6 +1272,8 @@ if (agent_.loggingEnabled()) { agent_.logWriter_.traceEntry(this, "execute", sql, columnNames); } + if (columnNames != null) + autoGeneratedKeys_ = Statement.RETURN_GENERATED_KEYS; generatedKeysColumnNames_ = columnNames; boolean b = executeX(sql); if (agent_.loggingEnabled()) { @@ -1854,12 +1858,11 @@ } private void flowExecute(int executeType, String sql) throws SqlException { - checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc) - checkAutoGeneratedKeysParameters(); + checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc) clearWarningsX(); // Per jdbc spec 0.7, and getWarnings() javadoc - sql = escape(sql); parseSqlAndSetSqlModes(sql); + checkAutoGeneratedKeysParameters(); if (sqlMode_ == isUpdate__) { updateCount_ = 0; } else { @@ -2688,11 +2691,15 @@ "Statement.execute()/executeQuery()"); } - if (generatedKeysColumnNames_ != null) { - throw new SqlException(agent_.logWriter_, - new ClientMessageId(SQLState.NOT_IMPLEMENTED), - "Connection.prepareStatement(String sql, String[] columnNames)"); - } + + if (sqlUpdateMode_ == isInsertSql__ && + generatedKeysColumnNames_ != null && + generatedKeysColumnNames_.length !=1) { + throw new SqlException(agent_.logWriter_, + new ClientMessageId(SQLState.INVALID_COLUMN_ARRAY_LENGTH), + new Integer(generatedKeysColumnNames_.length)); + } + } public ColumnMetaData getGuessedResultSetMetaData() { Index: java/client/org/apache/derby/client/am/PreparedStatement.java =================================================================== --- java/client/org/apache/derby/client/am/PreparedStatement.java (revision 628780) +++ java/client/org/apache/derby/client/am/PreparedStatement.java (working copy) @@ -1943,6 +1943,7 @@ private void flowExecute(int executeType) throws SqlException { checkForClosedStatement(); + checkAutoGeneratedKeysParameters(); clearWarningsX(); checkForAppropriateSqlMode(executeType, sqlMode_); checkThatAllParametersAreSet();