| /* |
| Derby - Class org.apache.derbyTesting.functionTests.tests.jdbcapi.AutoGenJDBC30Test |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| */ |
| |
| package org.apache.derbyTesting.functionTests.tests.jdbcapi; |
| |
| import java.sql.Connection; |
| import java.sql.DriverManager; |
| import java.sql.PreparedStatement; |
| import java.sql.ResultSet; |
| import java.sql.ResultSetMetaData; |
| import java.sql.SQLException; |
| import java.sql.Savepoint; |
| import java.sql.Statement; |
| import junit.framework.Test; |
| import org.apache.derbyTesting.junit.BaseJDBCTestCase; |
| import org.apache.derbyTesting.junit.BaseTestSuite; |
| import org.apache.derbyTesting.junit.CleanDatabaseTestSetup; |
| import org.apache.derbyTesting.junit.JDBC; |
| import org.apache.derbyTesting.junit.TestConfiguration; |
| |
| /** |
| * Tests the JDBC 3.0 ability to establish a result set of auto-generated keys. |
| * <p> |
| * Converts the old jdbcapi/autoGeneratedJdbc30.java test to JUnit. |
| * The old harness test number is preserved in the comment for each fixture. |
| */ |
| public class AutoGenJDBC30Test extends BaseJDBCTestCase { |
| |
| /** |
| * Routines that should be created before the tests are run. |
| */ |
| private static final String[] ROUTINES = { |
| // Used by testInsertNoAutoGenExecuteSQLfunc |
| "CREATE FUNCTION MMWNI() RETURNS VARCHAR(20) " + |
| "READS SQL DATA LANGUAGE JAVA PARAMETER STYLE JAVA EXTERNAL NAME '" + |
| AutoGenJDBC30Test.class.getName() + ".MyMethodWithNoInsert'", |
| |
| // Used by testInsertAutoGenExecuteSQLfunc |
| "CREATE FUNCTION AddMe(P1 INT) RETURNS INT " + |
| "READS SQL DATA LANGUAGE JAVA PARAMETER STYLE JAVA EXTERNAL NAME '" + |
| AutoGenJDBC30Test.class.getName() + ".addMe'", |
| }; |
| |
| /** |
| * Tables that should be created before the tests are run. |
| * The first element in each row is the name of the table and the second |
| * element is the SQL text that creates it. |
| */ |
| private static final String[][] TABLES = { |
| |
| { "t11_AutoGen", |
| "create table t11_AutoGen (c11 int, " + |
| "c12 int generated always as identity (increment by 1))" }, |
| |
| { "t31_AutoGen", |
| "create table t31_AutoGen (c31 int, " + |
| "c32 int generated always as identity (increment by 1), " + |
| "c33 int default 2)" }, |
| |
| { "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))"}, |
| }; |
| |
| /** |
| * Creates a new AutoGenJDBC30Test instance. |
| * |
| * @param name name of the test |
| */ |
| public AutoGenJDBC30Test(String name) { |
| super(name); |
| } |
| |
| /** |
| * Implements suite() to run in embedded and client configurations. |
| */ |
| public static Test suite() { |
| BaseTestSuite suite = new BaseTestSuite("AutoGenJDBC30Test"); |
| |
| suite.addTest(baseSuite("AutoGenJDBC30Test:embedded")); |
| |
| suite.addTest(TestConfiguration.clientServerDecorator( |
| baseSuite("AutoGenJDBC30Test:client"))); |
| return suite; |
| } |
| |
| /** |
| * Tests are only run if JDBC 3.0 available, and database objects get |
| * created only once for the suite run. |
| * |
| * @param name name of the test |
| */ |
| private static Test baseSuite(String name) { |
| |
| BaseTestSuite suite = new BaseTestSuite(name); |
| |
| if (!JDBC.vmSupportsJDBC3()) { |
| // empty suite |
| return suite; |
| } |
| |
| suite.addTestSuite(AutoGenJDBC30Test.class); |
| |
| // Create database objects only once for entire test run |
| return new CleanDatabaseTestSetup(suite) |
| { |
| /** |
| * Creates the database objects used in the test cases. |
| * @throws SQLException |
| */ |
| protected void decorateSQL(Statement s) throws SQLException |
| { |
| for (int i = 0; i < ROUTINES.length; i++) { |
| s.execute(ROUTINES[i]); |
| } |
| for (int i = 0; i < TABLES.length; i++) { |
| s.execute(TABLES[i][1]); |
| } |
| } |
| }; |
| } // End baseSuite |
| |
| /** |
| * Sets up the connection for a test case, clears all tables and resets |
| * all auto-generated keys used by the test fixtures. |
| * @throws SQLException |
| */ |
| public void setUp() throws SQLException |
| { |
| Connection conn = getConnection(); |
| conn.setAutoCommit(false); |
| Statement s = createStatement(); |
| for (int i = 0; i < TABLES.length; i++) { |
| s.execute("DELETE FROM " + TABLES[i][0]); |
| } |
| s.execute("ALTER TABLE t11_AutoGen ALTER COLUMN c12 RESTART WITH 1"); |
| s.execute("ALTER TABLE t31_AutoGen ALTER COLUMN c32 RESTART WITH 1"); |
| s.close(); |
| conn.commit(); |
| } |
| |
| // TESTS |
| |
| /** |
| * Requests generated keys for a new statement that hasn't executed any |
| * SQL yet. |
| * Old harness Test 1. |
| * Expected result: a NULL ResultSet. |
| * @throws SQLException |
| */ |
| public void testNoSql() throws SQLException |
| { |
| Statement s = createStatement(); |
| assertNull("Expected NULL ResultSet", s.getGeneratedKeys()); |
| s.close(); |
| } |
| |
| /** |
| * Requests generated keys for a Select statement (non-insert). |
| * Old harness Test 2. |
| * Expected result: a NULL ResultSet. |
| * @throws SQLException |
| */ |
| public void testSelect() throws SQLException |
| { |
| String sql="select * from t11_AutoGen"; |
| |
| Statement s = createStatement(); |
| s.execute(sql, Statement.RETURN_GENERATED_KEYS); |
| assertNull("Expected NULL ResultSet after s.execute()", |
| s.getGeneratedKeys()); |
| |
| s.close(); |
| |
| PreparedStatement ps = |
| prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); |
| ps.execute(); |
| assertNull("Expected NULL ResultSet after ps.execute()", |
| ps.getGeneratedKeys()); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Requests generated keys for a multi-row insert statement. |
| * Old harness Test 3. |
| * Expected result: ResultSet has one row with a NULL key because it |
| * inserts more than one row and there was no prior one-row insert into |
| * a table with an auto-generated key. |
| * @throws SQLException |
| */ |
| public void testInsertManyRowsNoPriorKey() throws SQLException |
| { |
| String sqlStmt="insert into t31_AutoGen(c31) values (99), (98), (97)"; |
| runInsertFourWaysKeyIsNull (sqlStmt); |
| } |
| |
| /** |
| * Requests generated keys for a multi-row update statement after a |
| * one-row update into a table with an auto-generated key. |
| * Expected result: ResultSet has one row with a non-NULL key for the |
| * one-row update. |
| * @throws SQLException |
| */ |
| public void testUpdateManyRowsAfterOneRowKey() throws SQLException |
| { |
| // Do a one-row insert into a table with an auto-generated key. |
| Statement s = createStatement(); |
| s.execute("insert into t11_AutoGen(c11) values (99)", Statement.RETURN_GENERATED_KEYS); |
| int expected=1; |
| int keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", expected, keyval); |
| |
| // Do a one-row update of a table with an auto-generated key. |
| s.execute("update t11_AutoGen set c12=default where c11=99", Statement.RETURN_GENERATED_KEYS); |
| expected=2; |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", expected, keyval); |
| |
| String sql="insert into t11_AutoGen(c11) values (99), (98), (97)"; |
| s.execute(sql, Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", expected, keyval); |
| |
| // Do a one-row update of a table with an auto-generated key. |
| s.execute("update t11_AutoGen set c12=default where c11=97", Statement.RETURN_GENERATED_KEYS); |
| expected=6; |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", expected, keyval); |
| |
| // Do a multi-row update of a table with an auto-generated key. |
| s.execute("update t11_AutoGen set c12=default where c11=99", Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", expected, keyval); |
| } |
| |
| /** |
| * Requests generated keys for a multi-row insert statement after a |
| * one-row insert into a table with an auto-generated key. |
| * Old harness Test 7. |
| * Expected result: ResultSet has one row with a non-NULL key for the |
| * one-row insert. |
| * @throws SQLException |
| */ |
| public void testInsertManyRowsAfterOneRowKey() throws SQLException |
| { |
| // Do a one-row insert into a table with an auto-generated key. |
| Statement s = createStatement(); |
| s.execute("insert into t11_AutoGen(c11) values (99)"); |
| |
| /* Although the insert into t31_AutoGen below inserts into a table |
| * with an auto-generated column, it won't increment the key from 1 |
| * to 2 because it's a multi-row insert. Instead, the key it fetches |
| * will be for the previous insert into t11_AutoGen. |
| */ |
| int expected=1; |
| String sql="insert into t31_AutoGen(c31) values (99), (98), (97)"; |
| |
| s.execute(sql, Statement.RETURN_GENERATED_KEYS); |
| int keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", expected, keyval); |
| |
| s.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.executeUpdate()", expected, keyval); |
| |
| s.close(); |
| |
| PreparedStatement ps = |
| prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); |
| ps.execute(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.execute()", expected, keyval); |
| |
| ps = prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); |
| ps.executeUpdate(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.executeUpdate()", expected, keyval); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Requests generated keys after doing an insert into a table that doesn't |
| * have a generated column (and there hasn't been a one row insert into |
| * a table with auto-generated keys yet). |
| * Old harness Test 4. |
| * Expected result: ResultSet has one row with a NULL key. |
| * @throws SQLException |
| */ |
| public void testInsertNoAutoGen() throws SQLException |
| { |
| // The original test inserted 21 and 22. |
| Statement s = createStatement(); |
| s.execute("insert into t21_noAutoGen values(21, 'true')"); |
| s.execute("insert into t21_noAutoGen values(22, 'true')"); |
| |
| s.execute("insert into t21_noAutoGen values(23, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| verifyNullKey("s.execute()", s.getGeneratedKeys()); |
| |
| s.executeUpdate("insert into t21_noAutoGen values(24, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| verifyNullKey("s.executeUpdate()", s.getGeneratedKeys()); |
| |
| s.close(); |
| |
| PreparedStatement ps = prepareStatement( |
| "insert into t21_noAutoGen values(25, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| ps.execute(); |
| verifyNullKey("PreparedStatement.execute()", ps.getGeneratedKeys()); |
| |
| ps = prepareStatement("insert into t21_noAutoGen values(26, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| ps.executeUpdate(); |
| verifyNullKey("ps.executeUpdate()", ps.getGeneratedKeys()); |
| |
| ps.close(); |
| } |
| |
| /** |
| * <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. |
| * Old harness Test 5a. |
| * Expected result: ResultSet has one row with a NULL key. |
| * @throws SQLException |
| */ |
| public void testInsertSubqueryNoWhereClause() throws SQLException |
| { |
| // Setup |
| Statement s = createStatement(); |
| s.execute("insert into t21_noAutoGen values(21, 'true')"); |
| s.close(); |
| |
| String sql="insert into t11_AutoGen(c11) select c21 from t21_noAutoGen"; |
| runInsertFourWaysKeyIsNull (sql); |
| } |
| |
| /** |
| * 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 |
| * a "where 1=2" clause. |
| * Old harness Test 5B. |
| * Expected result: ResultSet has one row with a NULL key. |
| * @throws SQLException |
| */ |
| public void testInsertSubqueryWhere1is2() throws SQLException |
| { |
| // Setup |
| Statement s = createStatement(); |
| s.execute("insert into t21_noAutoGen values(21, 'true')"); |
| s.close(); |
| |
| String sql = |
| "insert into t11_AutoGen(c11) select c21 from t21_noAutoGen " + |
| "where 1=2"; |
| runInsertFourWaysKeyIsNull (sql); |
| } |
| |
| /** |
| * 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 |
| * a "where c21=23" clause. |
| * Old harness Test 5c. |
| * Expected result: ResultSet with one row with a NULL key. |
| * @throws SQLException |
| */ |
| public void testInsertSubqueryWhereClause() throws SQLException |
| { |
| // Setup |
| Statement s = createStatement(); |
| s.execute("insert into t21_noAutoGen(c21,c22) values(23, 'true')"); |
| s.close(); |
| |
| String sql= |
| "insert into t11_AutoGen(c11) select c21 from t21_noAutoGen " + |
| "where c21=23"; |
| runInsertFourWaysKeyIsNull (sql); |
| } |
| |
| /** |
| * Requests generated keys after doing a one-row insert into a table |
| * that has an auto-generated column. |
| * Old harness Test 6. |
| * Expected result: ResultSet has one row with a non-NULL key. |
| * @throws SQLException |
| */ |
| public void testInsertOneRowKey() throws SQLException |
| { |
| String sql="insert into t11_AutoGen(c11) values (99)"; |
| |
| Statement s = createStatement(); |
| |
| s.execute(sql, Statement.RETURN_GENERATED_KEYS); |
| int keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", 1, keyval); |
| |
| s.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.executeUpdate()", 2, keyval); |
| |
| s.close(); |
| |
| PreparedStatement ps = |
| prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); |
| ps.execute(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.execute()", 3, keyval); |
| |
| ps = prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); |
| ps.executeUpdate(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.executeUpdate()", 4, keyval); |
| |
| ps.close(); |
| |
| /* |
| DERBY-3249 - Returned generated key result sets have the wrong |
| concurrency. Test should be expanded to handle all concurrencies/types. |
| |
| // Test the type of the Statement object does not affect the |
| // type of the generated key ResultSet (checked in getKeyValue) |
| s = this.createStatement(ResultSet.CONCUR_UPDATABLE, ResultSet.TYPE_SCROLL_INSENSITIVE); |
| s.execute(sql, Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue(s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", 5, keyval); |
| */ |
| } |
| |
| |
| /** |
| * After a one-row insert into a table with an auto-generated key, next |
| * inserts into a table that does not have an auto-generated key, then |
| * requests generated keys. |
| * Old harness Test 8. |
| * Expected result: ResultSet has one row with a non-NULL key. All four |
| * queries in this test return the same result because they fetch the |
| * key generated for the previous insert, not the current one. |
| * @throws SQLException |
| */ |
| public void testInsertNoGenColAfterOneRowKey() throws SQLException |
| { |
| // Do a one-row insert into a table with an auto-generated key. |
| Statement s = createStatement(); |
| s.execute("insert into t11_AutoGen(c11) values (99)"); |
| |
| /* The insert into t21_noAutoGen below doesn't insert into a table |
| * with an auto-generated column, so it won't increment the key from |
| * 1 to 2. The key it fetches will be for the previous insert into |
| * t11_AutoGen. |
| */ |
| int expected=1; |
| |
| s.execute("insert into t21_noAutoGen values(27, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| int keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", expected, keyval); |
| |
| s.executeUpdate("insert into t21_noAutoGen values(28, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.executeUpdate()", expected, keyval); |
| |
| s.close(); |
| |
| PreparedStatement ps = prepareStatement( |
| "insert into t21_noAutoGen values(29, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| ps.execute(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.execute()", expected, keyval); |
| |
| ps = prepareStatement("insert into t21_noAutoGen values(30, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| ps.executeUpdate(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.executeUpdate()", expected, keyval); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Requests generated keys for an UPDATE statement. |
| * Old harness Test 9. |
| * Expected result: a NULL ResultSet. |
| * @throws SQLException |
| */ |
| public void testUpdateOneRowKey() throws SQLException |
| { |
| Statement s = createStatement(); |
| s.execute("insert into t11_AutoGen(c11) values(999)"); |
| |
| String sqlStmt="update t11_AutoGen set c12=default where c11=999"; |
| s.execute(sqlStmt, Statement.RETURN_GENERATED_KEYS); |
| int keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", 2, keyval); |
| |
| s.executeUpdate(sqlStmt, Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.executeUpdate()", 3, keyval); |
| |
| s.close(); |
| |
| PreparedStatement ps = prepareStatement( |
| sqlStmt, Statement.RETURN_GENERATED_KEYS); |
| ps.execute(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.execute()", 4, keyval); |
| |
| ps = prepareStatement(sqlStmt, Statement.RETURN_GENERATED_KEYS); |
| ps.executeUpdate(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.executeUpdate()", 5, keyval); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Requests generated keys for an DELETE statement. |
| * Old master Test 10. |
| * Expected result: a NULL ResultSet. |
| * @throws SQLException |
| */ |
| public void testDelete() throws SQLException |
| { |
| Statement s = createStatement(); |
| s.execute("insert into t11_AutoGen(c11) values(999)"); |
| |
| String sqlStmt="delete from t11_AutoGen"; |
| s.execute(sqlStmt, Statement.RETURN_GENERATED_KEYS); |
| assertNull("Expected NULL ResultSet after s.execute()", |
| s.getGeneratedKeys()); |
| |
| s.executeUpdate(sqlStmt, Statement.RETURN_GENERATED_KEYS); |
| assertNull("Expected NULL ResultSet after s.executeUpdate()", |
| s.getGeneratedKeys()); |
| |
| s.close(); |
| |
| PreparedStatement ps = prepareStatement( |
| sqlStmt, Statement.RETURN_GENERATED_KEYS); |
| ps.execute(); |
| assertNull("Expected NULL ResultSet after ps.execute()", |
| ps.getGeneratedKeys()); |
| |
| ps.executeUpdate(); |
| assertNull("Expected NULL ResultSet after ps.executeUpdate()", |
| ps.getGeneratedKeys()); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Does a one-row insert into a table with a generated column, commits, |
| * then requests generated keys for an insert into a table without a |
| * generated column. |
| * Old master Test 11. |
| * Expected result: ResultSet has one row with a non-NULL key. |
| * The original code output this message: "expected to see resultset with |
| * one row of NULL value but instead get one row of non-NULL value from |
| * getGeneratedKeys". |
| * @throws SQLException |
| */ |
| public void testGetKeyAfterCommit() throws SQLException |
| { |
| // Setup transaction |
| Statement s = createStatement(); |
| s.execute("insert into t11_AutoGen(c11) values(999)"); |
| |
| Connection conn = getConnection(); |
| conn.commit(); |
| |
| /* The insert into t21_noAutoGen below doesn't insert into a table |
| * with an auto-generated column, so it won't increment the key from |
| * 1 to 2. The key it fetches will be for the previous insert into |
| * t11_AutoGen. |
| */ |
| int expected=1; |
| s.execute("insert into t21_noAutoGen values(31, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| int keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", expected, keyval); |
| |
| s.executeUpdate("insert into t21_noAutoGen values(32, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.executeUpdate()", expected, keyval); |
| |
| s.close(); |
| |
| PreparedStatement ps = prepareStatement( |
| "insert into t21_noAutoGen values(33, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| ps.execute(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.execute()", expected, keyval); |
| |
| ps = prepareStatement("insert into t21_noAutoGen values(34, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| ps.executeUpdate(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.executeUpdate()", expected, keyval); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Does a one-row insert into a table with a generated column, next does |
| * a rollback, then requests generated keys for an insert into a table |
| * without a generated column. |
| * Old master Test 12. |
| * Expected result: ResultSet has one row with a non-NULL key. |
| * The original code output this message: "had expected to see resultset |
| * with one row of NULL value but instead get one row of non-NULL value |
| * from getGeneratedKeys". |
| * @throws SQLException |
| */ |
| public void testGetKeyAfterRollback() throws SQLException |
| { |
| Connection conn = getConnection(); |
| Statement s = createStatement(); |
| |
| s.execute("insert into t11_AutoGen(c11) values(999)"); |
| conn.rollback(); |
| |
| /* The insert into t21_noAutoGen below doesn't insert into a table |
| * with an auto-generated column, so it won't increment the key from |
| * 1 to 2. The key it fetches will be for the previous insert into |
| * t11_AutoGen, a value that never changes in this fixture. |
| */ |
| int expected=1; |
| |
| s.execute("insert into t21_noAutoGen values(35, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| int keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", expected, keyval); |
| |
| s.executeUpdate("insert into t21_noAutoGen values(36, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.executeUpdate()", expected, keyval); |
| |
| s.close(); |
| |
| PreparedStatement ps = prepareStatement( |
| "insert into t21_noAutoGen values(37, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| ps.execute(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.execute()", expected, keyval); |
| |
| ps = prepareStatement("insert into t21_noAutoGen values(38, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| ps.executeUpdate(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("key value after ps.executeUpdate()", expected, keyval); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Inserts one row into a table with an auto-generated column while inside |
| * a savepoint unit, does a rollback, then gets keys after an insert |
| * into a table without an auto-generated column. |
| * Old master Test 13. |
| * Expected result: ResultSet has one row with a non-NULL key, and the |
| * key value should be the same before and after the rollback. |
| * @throws SQLException |
| */ |
| public void testGetKeyAfterSavepointRollback() throws SQLException |
| { |
| Connection conn = getConnection(); |
| Statement s = createStatement(); |
| Savepoint savepoint1 = conn.setSavepoint(); |
| |
| int expected=1; |
| |
| s.execute("insert into t11_AutoGen(c11) values(99)", |
| Statement.RETURN_GENERATED_KEYS); |
| int keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value before rollback", expected, keyval); |
| |
| conn.rollback(savepoint1); |
| |
| s.execute("insert into t21_noAutoGen values(39, 'true')", |
| Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after rollback", expected, keyval); |
| |
| s.close(); |
| } |
| |
| /** |
| * Inserts one row into a table with an auto-generated column, then |
| * examines the metadata for the generatedKeys ResultSet. |
| * Old master Test 14. |
| * @throws SQLException |
| */ |
| public void testGetKeyMetadataAfterInsert() throws SQLException |
| { |
| Statement s = createStatement(); |
| |
| s.execute("insert into t31_AutoGen(c31) values (99)", |
| Statement.RETURN_GENERATED_KEYS); |
| ResultSet rs = s.getGeneratedKeys(); |
| ResultSetMetaData rsmd = rs.getMetaData(); |
| assertEquals("ResultSet column count", 1, rsmd.getColumnCount()); |
| assertEquals("Column type", "DECIMAL", rsmd.getColumnTypeName(1)); |
| assertEquals("Column precision", 31, rsmd.getPrecision(1)); |
| assertEquals("Column scale", 0, rsmd.getScale(1)); |
| int keyval = getKeyValue (rs); |
| assertEquals("Key value", 1, keyval); |
| |
| rs.close(); |
| s.close(); |
| } |
| |
| /** |
| * Inserts one row into a table with an auto-generated column, but |
| * with NO_GENERATED_KEYS. |
| * Old master Test 15. |
| * Expected result: NULL ResultSet. |
| * @throws SQLException |
| */ |
| public void testInsertNoGenKeys() throws SQLException |
| { |
| Statement s = createStatement(); |
| |
| String sql="insert into t31_AutoGen(c31) values (99)"; |
| |
| s.execute(sql, Statement.NO_GENERATED_KEYS); |
| assertNull("Expected NULL ResultSet after s.execute()", |
| s.getGeneratedKeys()); |
| |
| s.executeUpdate(sql, Statement.NO_GENERATED_KEYS); |
| assertNull("Expected NULL ResultSet after s.executeUpdate", |
| s.getGeneratedKeys()); |
| |
| s.close(); |
| |
| PreparedStatement ps = |
| prepareStatement(sql, Statement.NO_GENERATED_KEYS); |
| ps.execute(); |
| assertNull("Expected NULL ResultSet after ps.execute()", |
| ps.getGeneratedKeys()); |
| |
| ps = prepareStatement(sql, Statement.NO_GENERATED_KEYS); |
| ps.executeUpdate(); |
| assertNull("Expected NULL ResultSet after ps.executeUpdate", |
| ps.getGeneratedKeys()); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Inserts one row into a table with an auto-generated column, but |
| * in the JDBC 2.0 way (with no generated key feature). |
| * Old master Test 16. |
| * Expected result: NULL ResultSet. |
| * @throws SQLException |
| */ |
| public void testInsertJDBC20syntax() throws SQLException |
| { |
| Statement s = createStatement(); |
| |
| String sql="insert into t31_AutoGen(c31) values (99)"; |
| |
| s.execute(sql); |
| assertNull("Expected NULL ResultSet after s.execute()", |
| s.getGeneratedKeys()); |
| |
| s.executeUpdate(sql); |
| assertNull("Expected NULL ResultSet after s.executeUpdate", |
| s.getGeneratedKeys()); |
| |
| s.close(); |
| |
| PreparedStatement ps = prepareStatement(sql); |
| ps.execute(); |
| assertNull("Expected NULL ResultSet after ps.execute()", |
| ps.getGeneratedKeys()); |
| |
| ps = prepareStatement(sql); |
| ps.executeUpdate(); |
| assertNull("Expected NULL ResultSet after ps.executeUpdate", |
| ps.getGeneratedKeys()); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Updates a row in a table with an auto-generated column and |
| * NO_GENERATED_KEYS, then fetches key. |
| * Old master Test 17. |
| * Expected result: NULL ResultSet. |
| * @throws SQLException |
| */ |
| public void testUpdateAutoGenNoGenKeys() throws SQLException |
| { |
| Statement s = createStatement(); |
| |
| // Insert a row for us to update |
| s.execute("insert into t31_AutoGen(c31) values (99)"); |
| |
| String sql="update t31_AutoGen set c31=98"; |
| |
| s.execute(sql, Statement.NO_GENERATED_KEYS); |
| assertNull("Expected NULL ResultSet after s.execute()", |
| s.getGeneratedKeys()); |
| |
| s.executeUpdate(sql, Statement.NO_GENERATED_KEYS); |
| assertNull("Expected NULL ResultSet after s.executeUpdate", |
| s.getGeneratedKeys()); |
| |
| s.close(); |
| |
| PreparedStatement ps=prepareStatement(sql, Statement.NO_GENERATED_KEYS); |
| ps.execute(); |
| assertNull("Expected NULL ResultSet after ps.execute()", |
| ps.getGeneratedKeys()); |
| |
| ps = prepareStatement(sql, Statement.NO_GENERATED_KEYS); |
| ps.executeUpdate(); |
| assertNull("Expected NULL ResultSet after ps.executeUpdate", |
| ps.getGeneratedKeys()); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Deletes rows from a table with an auto-generated column in the JDBC 2.0 |
| * way (with no generated key feature), then fetches key. |
| * Old master Test 18. |
| * Expected result: NULL ResultSet. |
| * @throws SQLException |
| */ |
| public void testDeleteAutoGenNoGenKeysJDBC20syntax() throws SQLException |
| { |
| Statement s = createStatement(); |
| |
| String sql="delete from t31_AutoGen"; |
| |
| s.execute(sql); |
| assertNull("Expected NULL ResultSet after s.execute()", |
| s.getGeneratedKeys()); |
| |
| s.executeUpdate(sql); |
| assertNull("Expected NULL ResultSet after s.executeUpdate", |
| s.getGeneratedKeys()); |
| |
| s.close(); |
| |
| PreparedStatement ps=prepareStatement(sql); |
| ps.execute(); |
| assertNull("Expected NULL ResultSet after ps.execute()", |
| ps.getGeneratedKeys()); |
| |
| ps = prepareStatement(sql); |
| ps.executeUpdate(); |
| assertNull("Expected NULL ResultSet after ps.executeUpdate", |
| ps.getGeneratedKeys()); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Inserts a row into a table with a SQL function in the VALUES clause; |
| * the table does not have an auto-generated column. |
| * Old master Test 19. |
| * Expected result: ResultSet has one row. The key value is NULL if |
| * there has been no prior insert into a table with an auto-generated |
| * column; otherwise, the value is not NULL. |
| * The old master referenced an old issue for which this test was added. |
| * getGeneratedKeys() threw an exception if an insert statement included a |
| * SQL routine and set the flag to generate a generatedKeys ResultSet. |
| * @throws SQLException |
| */ |
| public void testInsertNoAutoGenExecuteSQLfunc() throws SQLException |
| { |
| Statement s = createStatement(); |
| |
| // Insert into a table that does not have an auto-gen column. |
| s.execute("insert into t21_noAutoGen values(40, MMWNI())", |
| Statement.RETURN_GENERATED_KEYS); |
| verifyNullKey("First insert", s.getGeneratedKeys()); |
| assertTableRowCount("T21_NOAUTOGEN", 1); |
| |
| // Now insert into a table that has an auto-gen column. |
| s.execute("insert into t31_AutoGen(c31) values (99)", |
| Statement.RETURN_GENERATED_KEYS); |
| int keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after insert into t31_AutoGen", 1, keyval); |
| |
| // Insert again into the table that does not have an auto-gen column. |
| s.execute("insert into t21_noAutoGen values(42, MMWNI())", |
| Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after insert into t21_noAutoGen", 1, keyval); |
| assertTableRowCount("T21_NOAUTOGEN", 2); |
| |
| s.close(); |
| } |
| |
| /** |
| * Inserts a row into a table with a SQL function in the VALUES clause; |
| * the table has an auto-generated column. |
| * Old master: no test, but this seemed a natural addition given |
| * testInsertNoAutoGenExecuteSQLfunc(). |
| * Expected result: ResultSet has one row with a non-NULL key value. |
| * @throws SQLException |
| */ |
| public void testInsertAutoGenExecuteSQLfunc() throws SQLException |
| { |
| String sql="insert into t31_AutoGen(c31) values (AddMe(1))"; |
| |
| Statement s = createStatement(); |
| |
| s.execute(sql, Statement.RETURN_GENERATED_KEYS); |
| int keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", 1, keyval); |
| |
| s.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS); |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.executeUpdate()", 2, keyval); |
| |
| s.close(); |
| |
| PreparedStatement ps = |
| prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); |
| ps.execute(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.execute()", 3, keyval); |
| |
| ps = prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); |
| ps.executeUpdate(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.executeUpdate()", 4, keyval); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Verifies fix for an old issue in which the ResultSet returned by |
| * getGenerateKeys was incorrectly tied to the activation of the |
| * PreparedStatement; so, when the ResultSet was garbage collected, the |
| * activation was closed, resulting in an "Activation closed, operation |
| * execute not permitted" exception on subsequent executes (warning: |
| * this fixture takes a noticeable time to run). |
| * Old master Test 20. |
| * Expected result: no exceptions should occur. |
| * @throws SQLException |
| */ |
| public void testResultSetGarbageCollection() throws SQLException |
| { |
| Connection conn = getConnection(); |
| |
| PreparedStatement ps = |
| prepareStatement("insert into t11_AutoGen(c11) values(?)", |
| Statement.RETURN_GENERATED_KEYS); |
| |
| for (int i = 0; i < 100; i++) |
| { |
| ps.setInt(1, 100+i); |
| ps.executeUpdate(); |
| |
| ResultSet rs = ps.getGeneratedKeys(); |
| while (rs.next()) { |
| rs.getInt(1); |
| } |
| rs.close(); |
| conn.commit(); |
| |
| System.runFinalization(); |
| System.gc(); |
| System.runFinalization(); |
| System.gc(); |
| } |
| } |
| |
| /** |
| * Test that use of columnIndexes to indicate which keys should be |
| * made available works as expected. |
| * |
| * @throws SQLException |
| */ |
| public void testColumnIndexes() throws SQLException |
| { |
| |
| // Valid (typical) usage. |
| |
| int [] colIndexes = new int [] { 2 }; |
| testUserGivenColumns(colIndexes, null, 1); |
| |
| |
| // Mulitple columns. one not an identity column. |
| colIndexes = new int[] {1,2}; |
| testUserGivenColumnsError(colIndexes, null); |
| |
| |
| // Derby client can't differentiate between |
| // valid and invalid identity columns. So the |
| // other tests do not apply. |
| if (usingDerbyNetClient()) |
| return; |
| |
| // Non-existent column index. |
| colIndexes = new int[] {100}; |
| testUserGivenColumnsError(colIndexes, null); |
| |
| // Valid column index but not an auto-gen column. |
| |
| colIndexes[0] = 1; |
| testUserGivenColumnsError(colIndexes, null); |
| |
| /* If user specifies the same column index multiple times, |
| * things should still work. We effectively just take the |
| * one and ignore the rest. |
| */ |
| |
| colIndexes = new int [] { 2, 2, 2 }; |
| testUserGivenColumns(colIndexes, null, 5); |
| |
| // Multiple col indexes, one of which is invalid. |
| |
| colIndexes[1] = 100; |
| testUserGivenColumnsError(colIndexes, null); |
| |
| |
| /* Multiple col indexes, one of which is invalid and another |
| * of which is not an auto-gen column. |
| */ |
| |
| colIndexes[2] = 100; |
| testUserGivenColumnsError(colIndexes, null); |
| |
| // Same as previous but with "bad" indexes switched. |
| |
| colIndexes[1] = 100; |
| colIndexes[2] = 1; |
| testUserGivenColumnsError(colIndexes, null); |
| } |
| |
| /** |
| * Test that use of columnNames to indicate which keys should be |
| * made available works as expected. |
| * |
| * @throws SQLException |
| */ |
| public void testColumnNames() throws SQLException |
| { |
| |
| // 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= new String[] {"NOTTHERE"}; |
| testUserGivenColumnsError(null, colNames); |
| |
| // Valid column name but not an auto-gen column. |
| |
| colNames[0] = "C11"; |
| testUserGivenColumnsError(null, colNames); |
| |
| // "null" column name. |
| |
| colNames[0] = null; |
| testUserGivenColumnsError(null, colNames); |
| |
| /* If user specifies the same column name multiple times, |
| * things should still work. We effectively just take the |
| * one and ignore the rest. |
| */ |
| |
| colNames = new String [] { "C12", "C12", "C12" }; |
| testUserGivenColumns(null, colNames, 5); |
| |
| // Multiple col names, one of which is invalid. |
| |
| colNames[1] = "NOTTHERE"; |
| testUserGivenColumnsError(null, colNames); |
| |
| // Multiple col names, one of which is not an auto-gen column. |
| |
| colNames[1] = "C11"; |
| testUserGivenColumnsError(null, colNames); |
| |
| // Multiple col names, one of which is null. |
| |
| colNames[1] = null; |
| testUserGivenColumnsError(null, colNames); |
| |
| /* Multiple col names, one of which is invalid and another |
| * of which is not an auto-gen column. |
| */ |
| |
| colNames[1] = "C11"; |
| colNames[2] = "NOTTHERE"; |
| testUserGivenColumnsError(null, colNames); |
| |
| // Same as previous but with "bad" names switched. |
| |
| colNames[1] = "NOTTHERE"; |
| colNames[2] = "C11"; |
| testUserGivenColumnsError(null, colNames); |
| } |
| |
| /** |
| * Verify that if user specifies an empty array for columNames or columnIndexes, |
| * it is the same as NO_GENERATED_KEYS |
| * @throws SQLException |
| */ |
| public void testUserGivenColumnsEmpty() throws SQLException |
| { |
| Statement s = createStatement(); |
| |
| String sql="insert into t11_AutoGen(c11) values (99)"; |
| |
| |
| s.execute(sql, new String[] {}); |
| assertNull("Expected NULL ResultSet after s.execute()", |
| s.getGeneratedKeys()); |
| |
| s.executeUpdate(sql, new String[] {}); |
| assertNull("Expected NULL ResultSet after s.executeUpdate()", |
| s.getGeneratedKeys()); |
| |
| PreparedStatement ps = null; |
| |
| ps = prepareStatement(sql, new String[] {}); |
| ps.execute(); |
| assertNull("Expected NULL ResultSet after ps.execute()", |
| ps.getGeneratedKeys()); |
| |
| ps = prepareStatement(sql, new String[] {}); |
| ps.executeUpdate(); |
| assertNull("Expected NULL ResultSet after ps.executeUpdate()", |
| ps.getGeneratedKeys()); |
| // No columnIndexes yet for derby client. |
| if (usingDerbyNetClient()) |
| return; |
| |
| s.execute(sql, new int[] {}); |
| assertNull("Expected NULL ResultSet after s.execute()", |
| s.getGeneratedKeys()); |
| |
| s.executeUpdate(sql, new int[] {}); |
| assertNull("Expected NULL ResultSet after s.executeUpdate()", |
| s.getGeneratedKeys()); |
| |
| if (!usingEmbedded()) |
| { |
| // Can't run these with embedded now because of DERBY-3430 |
| ps = prepareStatement(sql, new int[] {}); |
| ps.execute(); |
| assertNull("Expected NULL ResultSet after ps.execute()", |
| ps.getGeneratedKeys()); |
| |
| ps = prepareStatement(sql, new int[] {}); |
| ps.executeUpdate(); |
| assertNull("Expected NULL ResultSet after ps.executeUpdate()", |
| ps.getGeneratedKeys()); |
| |
| } |
| |
| |
| |
| } |
| |
| /** |
| * Verify that if a user specifies a *NULL* column index or column |
| * name array to indicate which keys should be made available, Derby will |
| * effectively disable autogenerated keys (i.e. same as if user passed |
| * NO_GENERATED_KEYS). |
| * |
| * Expected result: a NULL result set. |
| * @throws SQLException |
| */ |
| public void testUserGivenColumnsNull() throws SQLException |
| { |
| |
| Statement s = createStatement(); |
| |
| String sql="insert into t11_AutoGen(c11) values (99)"; |
| |
| |
| s.execute(sql, (String[]) null); |
| assertNull("Expected NULL ResultSet after s.execute()", |
| s.getGeneratedKeys()); |
| |
| s.executeUpdate(sql, (String[]) null); |
| assertNull("Expected NULL ResultSet after s.executeUpdate()", |
| s.getGeneratedKeys()); |
| |
| |
| PreparedStatement ps; |
| ps = prepareStatement(sql, (String[]) null); |
| ps.execute(); |
| assertNull("Expected NULL ResultSet after ps.execute()", |
| ps.getGeneratedKeys()); |
| |
| 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()); |
| |
| 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, (int[]) null); |
| ps.executeUpdate(); |
| assertNull("Expected NULL ResultSet after ps.executeUpdate()", |
| ps.getGeneratedKeys()); |
| |
| |
| ps.close(); |
| |
| } |
| |
| // Local utility methods. |
| |
| /** |
| * Verify that if user specifies *valid* column indexes or column |
| * names to indicate which keys should be made available, Derby will |
| * return the correct results. |
| * |
| * Expected result: one row with a non-NULL key. |
| * |
| * @param colIndexes Array of column indexes indicating which keys |
| * should be made available. Must be null if colNames is non-null. |
| * @param colNames Array of column names indicating which keys should |
| * be made available. Must be null if colIndexes is non-null. |
| * @param expectedVal First expected autogenerated key; will be |
| * incremented for each successful INSERT statement. |
| * |
| * @throws SQLException |
| */ |
| private void testUserGivenColumns(int [] colIndexes, String [] colNames, |
| int expectedVal) throws SQLException |
| { |
| assertTrue("Exactly one of colIndexes or colNames should be null", |
| ((colIndexes != null) ^ (colNames != null))); |
| |
| boolean useIndexes = (colIndexes != null); |
| Statement s = createStatement(); |
| |
| String sql="insert into t11_AutoGen(c11) values (99)"; |
| |
| if (useIndexes) |
| s.execute(sql, colIndexes); |
| else |
| s.execute(sql, colNames); |
| |
| int keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.execute()", expectedVal++, keyval); |
| |
| if (useIndexes) |
| s.executeUpdate(sql, colIndexes); |
| else |
| s.executeUpdate(sql, colNames); |
| |
| keyval = getKeyValue (s.getGeneratedKeys()); |
| assertEquals("Key value after s.executeUpdate()", |
| expectedVal++, keyval); |
| |
| s.close(); |
| |
| PreparedStatement ps = null; |
| if (useIndexes) |
| ps = prepareStatement(sql, colIndexes); |
| else |
| ps = prepareStatement(sql, colNames); |
| |
| ps.execute(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.execute()", expectedVal++, keyval); |
| |
| if (useIndexes) |
| ps = prepareStatement(sql, colIndexes); |
| else |
| ps = prepareStatement(sql, colNames); |
| |
| ps.executeUpdate(); |
| keyval = getKeyValue (ps.getGeneratedKeys()); |
| assertEquals("Key value after ps.executeUpdate()", |
| expectedVal++, keyval); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Verify that if user specifies *INvalid* column indexes or column |
| * names to indicate which keys should be made available, Derby will |
| * throw an appropriate error. |
| * |
| * Expected result: Execution-time error: X0X0E or X0X0F. |
| * |
| * @param colIndexes Array of column indexes indicating which keys |
| * should be made available. Must be null if colNames is non-null. |
| * @param colNames Array of column names indicating which keys should |
| * be made available. Must be null if colIndexes is non-null. |
| * |
| * @throws SQLException |
| */ |
| private void testUserGivenColumnsError(int [] colIndexes, |
| String [] colNames) throws SQLException |
| { |
| assertTrue("Exactly one of colIndexes or colNames should be null.", |
| ((colIndexes != null) ^ (colNames != null))); |
| |
| 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)"; |
| |
| try { |
| |
| if (useIndexes) |
| s.execute(sql, colIndexes); |
| else |
| s.execute(sql, colNames); |
| |
| fail("Expected s.execute() to fail, but it did not."); |
| |
| } catch (SQLException se) { |
| assertSQLState(expectedSQLState, se.getSQLState(), se); |
| } |
| |
| try { |
| |
| if (useIndexes) |
| s.executeUpdate(sql, colIndexes); |
| else |
| s.executeUpdate(sql, colNames); |
| |
| fail("Expected s.executeUpdate() to fail, but it did not."); |
| |
| } catch (SQLException se) { |
| assertSQLState(expectedSQLState, se.getSQLState(), se); |
| } |
| |
| s.close(); |
| |
| PreparedStatement ps = null; |
| if (useIndexes) |
| ps = prepareStatement(sql, colIndexes); |
| else |
| ps = prepareStatement(sql, colNames); |
| |
| try { |
| ps.execute(); |
| fail("Expected ps.execute() to fail, but it did not."); |
| } catch (SQLException se) { |
| assertSQLState(expectedSQLState, se.getSQLState(), se); |
| } |
| |
| try { |
| ps.executeUpdate(); |
| fail("Expected ps.executeUpdate() to fail, but it did not."); |
| } catch (SQLException se) { |
| assertSQLState(expectedSQLState, se.getSQLState(), se); |
| } |
| |
| ps.close(); |
| } |
| |
| /** |
| * Runs the same SQL INSERT statement four ways: |
| * Statement.execute, |
| * Statement.executeUpdate, |
| * PreparedStatement.execute, and |
| * PreparedStatement.executeUpdate, |
| * and expects the resulting key value to be NULL. |
| * |
| * @param sql The SQL statement to be executed |
| * @exception SQLException if a database error occurs |
| */ |
| public void runInsertFourWaysKeyIsNull (String sql) |
| throws SQLException |
| { |
| Statement s = createStatement(); |
| s.execute(sql, Statement.RETURN_GENERATED_KEYS); |
| verifyNullKey("After s.execute()", s.getGeneratedKeys()); |
| |
| s.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS); |
| verifyNullKey("After s.executeUpdate()", s.getGeneratedKeys()); |
| |
| s.close(); |
| |
| PreparedStatement ps = |
| prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); |
| ps.execute(); |
| verifyNullKey("After ps.execute()", ps.getGeneratedKeys()); |
| |
| ps = prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); |
| ps.executeUpdate(); |
| verifyNullKey("ps.executeUpdate()", ps.getGeneratedKeys()); |
| |
| ps.close(); |
| } |
| |
| /** |
| * Verifies that the generated key in a result set is null. |
| * |
| * @param description Text to be output for the assertion |
| * @param r ResultSet |
| * @exception SQLException if a database error occurs |
| */ |
| public void verifyNullKey (String description, ResultSet r) |
| throws SQLException |
| { |
| JDBC.assertGeneratedKeyResultSet(description, r); |
| |
| int i = 0; |
| while(r.next()) |
| { |
| assertNull(description, r.getString(1)); |
| i++; |
| } |
| assertEquals(description, 1, i); |
| } |
| |
| /** |
| * Gets the key value from the result set. |
| * |
| * @param r ResultSet |
| * @exception SQLException if a database error occurs |
| */ |
| public int getKeyValue (ResultSet r) throws SQLException |
| {if(r==null) System.out.println("it is null"); |
| JDBC.assertGeneratedKeyResultSet("AutoGenJDBC30Test.getKeyValue", r); |
| |
| int i = 0; |
| int retval = 0; |
| while(r.next()) |
| { |
| assertNotNull("Key value is NULL", r.getString(1)); |
| retval = r.getInt(1); |
| i++; |
| } |
| assertEquals("ResultSet rows", 1, i); |
| return retval; |
| } |
| |
| // SQL ROUTINES (functions and procedures) |
| |
| /** |
| * External code for the MMWNI() SQL function, which is called by |
| * the testInsertNoAutoGenExecuteSQLfunc fixture. |
| * @exception SQLException if a database error occurs |
| */ |
| |
| public static String MyMethodWithNoInsert() throws SQLException |
| { |
| Connection conn = |
| DriverManager.getConnection("jdbc:default:connection"); |
| Statement s = conn.createStatement(); |
| s.executeQuery("select * from t11_AutoGen"); |
| s.close(); |
| conn.close(); |
| return "true"; |
| } |
| |
| /** |
| * External code for the AddMe SQL function, which is called by |
| * the testInsertAutoGenExecuteSQLfunc fixture. |
| * @param p1 integer input argument to be used in calculation |
| * @exception SQLException if a database error occurs |
| */ |
| public static int addMe (int p1) throws SQLException |
| { |
| Connection conn = |
| DriverManager.getConnection("jdbc:default:connection"); |
| Statement s = conn.createStatement(); |
| s.executeQuery("select * from t11_AutoGen"); |
| s.close(); |
| conn.close(); |
| return (p1 + p1); |
| } |
| } |