| /* |
| |
| Derby - Class org.apache.derbyTesting.functionTests.tests.lang.ResultSetsFromPreparedStatementTest |
| |
| 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.lang; |
| |
| import java.sql.Connection; |
| import java.sql.Statement; |
| import java.sql.PreparedStatement; |
| import java.sql.CallableStatement; |
| import java.sql.ResultSet; |
| import java.sql.ResultSetMetaData; |
| |
| import java.sql.SQLException; |
| |
| import java.io.PrintStream; |
| |
| import junit.extensions.TestSetup; |
| import junit.framework.Test; |
| import org.apache.derbyTesting.junit.BaseTestSuite; |
| |
| import org.apache.derbyTesting.junit.BaseJDBCTestCase; |
| import org.apache.derbyTesting.junit.CleanDatabaseTestSetup; |
| import org.apache.derbyTesting.junit.JDBC; |
| import org.apache.derbyTesting.junit.RuntimeStatisticsParser; |
| import org.apache.derbyTesting.junit.SQLUtilities; |
| |
| // TODO: |
| // - Add parameters to all PreparedStatements that support it |
| // - special name for the ps being tested? |
| |
| /** |
| * Tests repeated instantiation of internal ResultSet types from |
| * PreparedStatements. This test will be a good sanity check when |
| * experimenting with re-use of internal ResultSet objects. |
| */ |
| public class ResultSetsFromPreparedStatementTest extends BaseJDBCTestCase |
| { |
| // --------------------------------------------------------------- |
| // Data model (taken from lang/refActions1.sql) |
| public static final Integer i1 = 1; |
| public static final Integer i2 = 2; |
| public static final Integer i3 = 3; |
| public static final Integer i4 = 4; |
| public static final Integer i5 = 5; |
| public static final Integer i6 = 6; |
| public static final Integer i7 = 7; |
| public static final Integer i8 = 8; |
| public static final Integer i9 = 9; |
| public static final Integer i10 = 10; |
| public static final Integer i11 = 11; |
| public static final Integer i12 = 12; |
| public static final Integer i13 = 13; |
| public static final Integer i14 = 14; |
| public static final Integer i15 = 15; |
| public static final Integer i16 = 16; |
| public static final Integer i17 = 17; |
| public static final Integer i18 = 18; |
| public static final Integer i19 = 19; |
| public static final Integer i20 = 20; |
| |
| public static final String k55 = "K55"; |
| public static final String k52 = "K52"; |
| public static final String k51 = "K51"; |
| |
| public static final String ashok = "ASHOK "; |
| public static final String john = "JOHN "; |
| public static final String robin = "ROBIN "; |
| public static final String joe1 = "JOE1 "; |
| public static final String joe2 = "JOE2 "; |
| public static final String hamid = "HAMID "; |
| public static final String truong = "TRUONG "; |
| public static final String larry1 = "LARRY1 "; |
| public static final String larry2 = "LARRY2 "; |
| public static final String bobbie = "BOBBIE "; |
| public static final String roger = "ROGER "; |
| public static final String jim = "JIM "; |
| public static final String dan = "DAN "; |
| public static final String sam1 = "SAM1 "; |
| public static final String sam2 = "SAM2 "; |
| public static final String guy = "GUY "; |
| public static final String don = "DON "; |
| public static final String monica = "MONICA "; |
| public static final String lily1 = "LILY1 "; |
| public static final String lily2 = "LILY2 "; |
| |
| // dept rows |
| public static final Object[] db_dept = { i1, k55, "DB " }; |
| public static final Object[] ofc_dept = { i2, k52, "OFC " }; |
| public static final Object[] cs_dept = { i3, k51, "CS " }; |
| |
| // dept table |
| public static final Object[][] dept = { db_dept, ofc_dept, cs_dept }; |
| |
| // emp rows |
| public static final Object[] ashok_emp = { i1, ashok, null, k51 }; |
| public static final Object[] john_emp = { i2, john, ashok, k51 }; |
| public static final Object[] robin_emp = { i3, robin, ashok, k51}; |
| public static final Object[] joe1_emp = { i4, joe1, ashok, k51}; |
| public static final Object[] joe2_emp = { i5, joe2, ashok, k51}; |
| public static final Object[] hamid_emp = { i6, hamid, john, k55 }; |
| public static final Object[] truong_emp = { i7, truong, hamid, k55 }; |
| public static final Object[] larry1_emp = { i8, larry1, hamid, k55 }; |
| public static final Object[] larry2_emp = { i9, larry2, hamid, k55 }; |
| public static final Object[] bobbie_emp = { i10, bobbie, hamid, k55 }; |
| public static final Object[] roger_emp = { i11, roger, robin, k52 }; |
| public static final Object[] jim_emp = { i12, jim, roger, k52 }; |
| public static final Object[] dan_emp = { i13, dan, roger, k52 }; |
| public static final Object[] sam1_emp = { i14, sam1, roger, k52 }; |
| public static final Object[] sam2_emp = { i15, sam2, roger, k52 }; |
| public static final Object[] guy_emp = { i16, guy, john, k55 }; |
| public static final Object[] don_emp = { i17, don, guy, k55 }; |
| public static final Object[] monica_emp = { i18, monica, guy, k55 }; |
| public static final Object[] lily1_emp = { i19, lily1, guy, k55 }; |
| public static final Object[] lily2_emp = { i20, lily2, guy, k55 }; |
| |
| // emp table |
| public static final Object[][] emp = { |
| ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp, hamid_emp, |
| truong_emp, larry1_emp, larry2_emp, bobbie_emp, roger_emp, jim_emp, |
| dan_emp, sam1_emp, sam2_emp, guy_emp, don_emp, monica_emp, lily1_emp, |
| lily2_emp |
| }; |
| |
| private static final String[] mgrs = { |
| ashok, john, hamid, robin, roger, guy |
| }; |
| |
| private static final String[] non_mgrs = { |
| joe1, joe2, truong, larry1, larry2, bobbie, jim, dan, |
| sam1, sam2, don, monica, lily1, lily2 |
| }; |
| |
| // --------------------------------------------------------------- |
| // Utility methods (and constants). Some are public to make them |
| // accessible to the decorator |
| public static final String SCHEMA = "db2test"; |
| public static final String CT = "create table "; |
| public static final String DS = |
| " (c0 int, dno char(3) not null primary key, dname char(10))"; |
| public static final String ES = |
| " (c0 int, name char(10) not null primary key, mgrname char(10)"; |
| public static final String DNO = " dno char(3)"; |
| |
| public static String ref(String table) { |
| return " references "+table; |
| } |
| |
| public static final String CAS = " on delete cascade"; |
| public static final String SETN = " on delete set null"; |
| |
| /** Secondary connection. Used if something needs to be executed in a |
| * separate transaction. */ |
| private Connection c2; |
| private Connection c3; |
| |
| |
| private static final long DERBY_DEFAULT_TIMEOUT = 60; |
| |
| private static final String SQLSTATE_NULL_INTO_NON_NULL = "23502"; |
| |
| /** |
| * Creates a String containing an insert statement for the |
| * specified table containing the specified number of '?' |
| * characters. |
| * @param table the name of the table |
| * @param params the number of params to insert |
| * @return an insert statement (as String) |
| */ |
| public static String insertInto(String table, int params) { |
| StringBuffer tmp = new StringBuffer("insert into "+table+" values ( ?"); |
| while (--params > 0) { |
| tmp.append(", ?"); |
| } |
| tmp.append(")"); |
| return tmp.toString(); |
| } |
| |
| private static String insertFrom(String dst, String src) { |
| return ("insert into "+dst+" select * from "+src); |
| } |
| |
| /** |
| * Create table for this fixture. The table is filled with data |
| * from the specified source table. |
| * @param name the table to create |
| * @param signature the signature (columns) of the new table |
| * @param src the name of the source table (used to fill the new table) |
| */ |
| private void createTestTable(String name, String signature, |
| String src) throws SQLException { |
| Statement s = createStatement(); |
| s.execute(CT+name+signature); |
| s.execute(insertFrom(name, src)); |
| s.close(); |
| } |
| |
| /** |
| * Apply a PreparedStatement repeatedly with the set of parameter |
| * vectors. (Any null params are assumed to be of type CHAR). |
| * @param action the ps to execute |
| * @param table an array of parameter vectors to use for each |
| * execution of the PreparedStatement |
| */ |
| public static void apply(PreparedStatement action, Object[][] table) |
| throws SQLException { |
| for (int row = 0; row < table.length; ++row) { |
| for (int col = 0; col < table[row].length; ++col) { |
| Object obj = table[row][col]; |
| if (obj == null) { |
| action.setNull(col+1,java.sql.Types.CHAR); |
| continue; |
| } |
| action.setObject(col+1, obj); |
| } |
| action.execute(); |
| } |
| } |
| |
| /** |
| * Iterates over an array of row vectors, comparing each to the |
| * data in the RS using assertRow. Always closes the RS, even when |
| * an exception is thrown. Assertion failures are intercepted and |
| * 'dumpDiff' is used to print the differences between the RS and |
| * the expected values to System.err. |
| * @param message a message from the caller |
| * @param expected array of row vectors |
| * @param returned the resultset to verify |
| */ |
| private static void assertResultSet(String message, |
| Object[][] expected, |
| ResultSet returned) |
| throws SQLException |
| { |
| int i = 0; |
| boolean moreRows = false; |
| try { |
| for (; i < expected.length && (moreRows=returned.next()); ++i) { |
| assertRow(message + "(row " +(i+1)+", ", |
| expected[i], |
| returned); |
| } |
| assertEquals(message+" too few rows, ", expected.length, i); |
| moreRows = returned.next(); ++i; |
| assertFalse(message+" too many rows, expected:<"+expected.length+ |
| "> but was at least:<"+i+">", moreRows); |
| } |
| catch (junit.framework.AssertionFailedError af) { |
| System.err.println(af); |
| dumpDiff(expected, i, returned, moreRows, System.err); |
| throw af; |
| } |
| finally { |
| returned.close(); |
| } |
| } |
| |
| /** |
| * Iterates over a row vector, comparing each to the corrsponding |
| * column in the ResultSet. The i'th entry in the row vector is |
| * compared (using assertEquals) to the return value from |
| * getObject(i) on the ResultSet. |
| * @param message info from the caller |
| * @param expected the expected row vector |
| * @param returned the resultset to verify |
| */ |
| private static void assertRow(String message, |
| Object[] expected, |
| ResultSet returned) throws SQLException { |
| final ResultSetMetaData rmd = returned.getMetaData(); |
| assertEquals(message+" columns:", expected.length, |
| rmd.getColumnCount()); |
| for (int i = 0; i < expected.length; ++i) { |
| assertEquals(message+ |
| rmd.getColumnLabel(i+1)+") ", |
| expected[i], |
| returned.getObject(i+1)); |
| } |
| } |
| |
| /** |
| * Prints a ResultSet to a PrintStream. The first line is a |
| * heading with name and type of each column. Each row is printed |
| * as a comma-separated list of columns. The printed value of a |
| * column is getObject(i).toString(). Closes the RS when |
| * done. Intended for debugging purposes. |
| * @param dumpee the ResultSet to dump |
| * @param stream the stream to dump the ResultSet to |
| */ |
| private static void dump(ResultSet dumpee, |
| PrintStream stream) throws SQLException { |
| final ResultSetMetaData rm = dumpee.getMetaData(); |
| final int colCount = rm.getColumnCount(); |
| for (int c = 1; c <= colCount; ++c) { |
| stream.print("" + rm.getColumnLabel(c) + " " + |
| rm.getColumnTypeName(c) + ", "); |
| } |
| stream.println(""); |
| while (dumpee.next()) { |
| for (int c = 1; c <= colCount; ++c) { |
| stream.print("" + dumpee.getObject(c) + ", "); |
| } |
| stream.println(""); |
| } |
| dumpee.close(); |
| } |
| |
| /** |
| * Prints a diff between a ResultSet and an expected Object[][] |
| * value to a PrintStream. The first line is a heading with name |
| * and type of each column. Each row is printed as a |
| * comma-separated list of columns. The printed value of a column |
| * is getObject(i).toString(). <p> |
| * |
| * If the expected value does not match the value from the RS, the |
| * expected value is printed followed by the actual value in angle |
| * brackets. The comparion starts from 'fromRow' (zero-based row |
| * index). Unmatched rows are printed with 'null' for the missing |
| * values. <p> |
| * |
| * dumpee must be positioned on a valid row, or moreRows must be |
| * false. Closes the RS when done. |
| * @param expected the expected value of the RS |
| * @param fromRow row to start comparison from |
| * @param dumpee the ResultSet to dump |
| * @param moreRows true if there are more rows in the RS |
| * @param stream the stream to dump the ResultSet to |
| */ |
| private static void dumpDiff(Object[][] expected, int fromRow, |
| ResultSet dumpee, boolean moreRows, |
| PrintStream stream) throws SQLException { |
| final ResultSetMetaData rm = dumpee.getMetaData(); |
| final int colCount = rm.getColumnCount(); |
| for (int c = 1; c <= colCount; ++c) { |
| stream.print("" + rm.getColumnLabel(c) + " " + |
| rm.getColumnTypeName(c) + ", "); |
| } |
| stream.println(""); |
| |
| for (; moreRows || fromRow < expected.length; ++fromRow) { |
| for (int c = 1; c <= colCount; ++c) { |
| final Object e = |
| (fromRow<expected.length?expected[fromRow][c-1]:null); |
| final Object ret = (moreRows?dumpee.getObject(c):null); |
| stream.print(e); |
| if (e == null || ret == null || !ret.equals(e)) { |
| stream.print("<" + ret +">"); |
| } |
| stream.print(", "); |
| } |
| stream.println(""); |
| moreRows = dumpee.next(); |
| } |
| dumpee.close(); |
| } |
| |
| /** |
| * Prints a ResultSet to a PrintStream in the form of an |
| * Object[][] constant that can be used as "expected outcome" in |
| * assertions. Closes the ResultSet when done. Experimental and |
| * not tested for data types other than String and Integer. |
| * @param dumpee the ResultSet to dump |
| * @param stream the stream to dump the ResultSet to |
| */ |
| private static void dumpObjectArray(ResultSet dumpee, |
| PrintStream stream) |
| throws SQLException { |
| final ResultSetMetaData rm = dumpee.getMetaData(); |
| final int colCount = rm.getColumnCount(); |
| int rows = 0; |
| String rowPrefix = ""; |
| while (dumpee.next()) { |
| ++rows; |
| stream.print(rowPrefix+"{ "); |
| rowPrefix = ",\n"; |
| String colPrefix = ""; |
| for (int c = 1; c <= colCount; ++c) { |
| stream.print(colPrefix); colPrefix = ", "; |
| final Object theObject = dumpee.getObject(c); |
| if (theObject == null) { |
| stream.print("null"); |
| continue; |
| } |
| if (theObject instanceof String) { |
| stream.print("\""+theObject+"\""); |
| continue; |
| } |
| stream.print("new " + rm.getColumnClassName(c) + |
| "("+ theObject + ")"); |
| } |
| stream.print(" }"); |
| } |
| if (rows > 0) stream.println(""); |
| else stream.println("<empty ResultSet>"); |
| dumpee.close(); |
| } |
| |
| /** |
| * Check whether a table is locked exclusively. |
| * |
| * @param table name of the table |
| * @return whether the table is locked exclusively |
| */ |
| private boolean hasTableXLock(String table) throws SQLException { |
| PreparedStatement ps = prepareStatement( |
| "select count(*) from syscs_diag.lock_table where tablename=? " + |
| "and CAST(type AS CHAR(5))='TABLE' and CAST(mode AS CHAR(1))='X'"); |
| ps.setString(1, table); |
| ResultSet rs = ps.executeQuery(); |
| assertTrue(rs.next()); |
| int count = rs.getInt(1); |
| rs.close(); |
| ps.close(); |
| return count != 0; |
| } |
| |
| // --------------------------------------------------------------- |
| // Framework methods |
| protected void setUp() throws Exception { |
| Statement s1 = createStatement(); |
| s1.executeUpdate("set schema " + SCHEMA); |
| s1.close(); |
| getConnection().setAutoCommit(false); |
| |
| c2 = openDefaultConnection(); |
| Statement s2 = c2.createStatement(); |
| s2.executeUpdate("set schema " + SCHEMA); |
| s2.close(); |
| c2.setAutoCommit(false); |
| } |
| |
| protected void tearDown() throws Exception { |
| rollback(); |
| c2.rollback(); |
| c2.close(); |
| c2 = null; |
| |
| // Some fixtures create tables named emp or dept, or views on |
| // them. Drop them, but ignore errors since they might not exist. |
| Statement s = createStatement(); |
| try { s.executeUpdate("drop view vemp"); } catch (SQLException e) {} |
| try { s.executeUpdate("drop view vdept"); } catch (SQLException e) {} |
| try { s.executeUpdate("drop table emp"); } catch (SQLException e) {} |
| try { s.executeUpdate("drop table emp2"); } catch (SQLException e) {} |
| try { s.executeUpdate("drop table dept"); } catch (SQLException e) {} |
| |
| // DERBY-4330 tables: |
| try { |
| if (c3 != null && !c3.isClosed()) { |
| c3.rollback(); |
| c3.close(); |
| } |
| } catch (SQLException e) { |
| } |
| c3 = null; |
| |
| try { s.executeUpdate( |
| "drop table APP.FILECHANGES"); } catch (SQLException e) {} |
| try { s.executeUpdate( |
| "drop table APP.CHANGESETS"); } catch (SQLException e) {} |
| try { s.executeUpdate( |
| "drop table APP.AUTHORS"); } catch (SQLException e) {} |
| try { s.executeUpdate( |
| "drop table APP.FILES"); } catch (SQLException e) {} |
| try { s.executeUpdate( |
| "drop table APP.REPOSITORIES"); } catch (SQLException e) {} |
| try { s.executeUpdate( |
| "drop table APP.FILECHANGES_2"); } catch (SQLException e) {} |
| |
| try { setTimeout(DERBY_DEFAULT_TIMEOUT); } catch (SQLException e) {} |
| |
| s.close(); |
| commit(); |
| |
| super.tearDown(); |
| } |
| |
| /** |
| * Set up a common environment for all fixtures. Creates the |
| * schema and the raw data tables 'dept_data' and 'emp_data'. |
| * @return a suite containing all tests |
| */ |
| public static Test suite() |
| { |
| BaseTestSuite suite = new BaseTestSuite |
| ("Create ResultSets from PreparedStatements"); |
| suite.addTestSuite(ResultSetsFromPreparedStatementTest.class); |
| |
| TestSetup wrapper = new CleanDatabaseTestSetup(suite) { |
| protected void decorateSQL(Statement s) throws SQLException |
| { |
| Connection c = s.getConnection(); |
| s.execute("create schema " + |
| ResultSetsFromPreparedStatementTest.SCHEMA); |
| s.execute("set schema " + |
| ResultSetsFromPreparedStatementTest.SCHEMA); |
| s.execute(ResultSetsFromPreparedStatementTest.CT+"dept_data"+ |
| ResultSetsFromPreparedStatementTest.DS); |
| |
| s.execute(ResultSetsFromPreparedStatementTest.CT+"emp_data"+ |
| ResultSetsFromPreparedStatementTest.ES+","+ |
| ResultSetsFromPreparedStatementTest.DNO+")"); |
| |
| c.commit(); |
| |
| PreparedStatement ps = c.prepareStatement |
| (ResultSetsFromPreparedStatementTest.insertInto |
| ("dept_data",3)); |
| |
| ResultSetsFromPreparedStatementTest.apply(ps, dept); |
| c.commit(); |
| ps.close(); |
| |
| ps = c.prepareStatement |
| (ResultSetsFromPreparedStatementTest.insertInto |
| ("emp_data",4)); |
| |
| ResultSetsFromPreparedStatementTest.apply(ps, emp); |
| c.commit(); |
| ps.close(); |
| |
| // No, cannot do this here. Will crash |
| // CleanDatabaseTestSetup.setUp() |
| // c.close(); |
| } |
| }; |
| return wrapper; |
| } |
| |
| /** |
| * Standard JUnit constructor |
| */ |
| public ResultSetsFromPreparedStatementTest(String name) |
| { |
| super(name); |
| } |
| |
| |
| // --------------------------------------------------------------- |
| // Fixtures for special ResultSets |
| /** |
| * Test SetTransactionResultSet |
| */ |
| public void testSetTransactionResultSet() throws Exception { |
| // SetTransactionResultSet |
| PreparedStatement[] setIsoLevel = new PreparedStatement[] { |
| prepareStatement("set current isolation = read uncommitted"), |
| prepareStatement("set current isolation = read committed"), |
| prepareStatement("set current isolation = rs"), |
| prepareStatement("set current isolation = serializable") |
| }; |
| int[] expectedIsoLevel = new int[] { |
| Connection.TRANSACTION_READ_UNCOMMITTED, |
| Connection.TRANSACTION_READ_COMMITTED, |
| Connection.TRANSACTION_REPEATABLE_READ, |
| Connection.TRANSACTION_SERIALIZABLE |
| }; |
| Connection c = getConnection(); |
| |
| for (int i = 0; i < 20; ++i) { |
| for (int iso = 0; iso < setIsoLevel.length; ++iso) { |
| setIsoLevel[iso].execute(); |
| assertEquals("i="+i+" iso="+iso,expectedIsoLevel[iso], |
| c.getTransactionIsolation()); |
| } |
| } |
| for (int iso = 0; iso < setIsoLevel.length; ++iso) { |
| setIsoLevel[iso].close(); |
| } |
| } |
| |
| /** |
| * Test CallStatementResultSet |
| */ |
| public void testCallStatementResultSet() throws Exception { |
| // CallStatementResultSet |
| CallableStatement cs = prepareCall |
| ("call SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY(?, ?)"); |
| cs.setString(1, "some.property.name"); |
| PreparedStatement ps = prepareStatement |
| ("values SYSCS_UTIL.SYSCS_GET_DATABASE_PROPERTY"+ |
| "('some.property.name')"); |
| for (int i = 0; i < 20; ++i) { |
| final Integer I = i; |
| cs.setObject(2, I); |
| cs.execute(); |
| ResultSet rs = ps.executeQuery(); |
| assertResultSet("i=?="+i, new Object[][] { |
| { I.toString() } |
| }, rs); |
| // Re-execute cs with the same parameter |
| cs.execute(); |
| rs = ps.executeQuery(); |
| assertResultSet("Ri=?="+i, new Object[][] { |
| { I.toString() } |
| }, rs); |
| |
| } |
| cs.close(); |
| ps.close(); |
| } |
| |
| /** |
| * Test VTIResultSet |
| */ |
| public void testVTIResultSet() throws Exception { |
| PreparedStatement ps = prepareStatement |
| ("select tablename, schemaname from sys.systables "+ |
| "inner join sys.sysschemas on "+ |
| "sys.systables.schemaid = sys.sysschemas.schemaid"); |
| ResultSet rs = ps.executeQuery(); |
| // VTIResultSet, ScrollInsensitiveResultSet, |
| ps = prepareStatement |
| ("select st.conglomeratename from "+ |
| "TABLE(SYSCS_DIAG.SPACE_TABLE(?,?)) st where st.isindex = 0"); |
| while (rs.next()) { |
| ps.setString(1, rs.getString(2)); |
| ps.setString(2, rs.getString(1)); |
| ResultSet rs2 = ps.executeQuery(); |
| assertResultSet("BooHoo", new Object[][] { |
| { rs.getString(1) } |
| }, rs2); |
| // Re-execute ps with the same parameters |
| rs2 = ps.executeQuery(); |
| assertResultSet("Re-exec", new Object[][] { |
| { rs.getString(1) } |
| }, rs2); |
| |
| } |
| rs.close(); |
| ps.close(); |
| } |
| |
| // /** |
| // * Test InsertVTIResultSet TODO |
| // */ |
| // public void testInsertVTIResultSet() throws Exception { |
| // } |
| // /** |
| // * Test DeleteVTIResultSet TODO |
| // */ |
| // public void testDeleteVTIResultSet() throws Exception { |
| // } |
| // /** |
| // * Test UpdateVTIResultSet TODO |
| // */ |
| // public void testUpdateVTIResultSet() throws Exception { |
| // } |
| // /** |
| // * Test MaterializedResultSet TODO |
| // */ |
| // public void testMaterializedResultSet() throws Exception { |
| // } |
| |
| |
| // Fixtures for distinct/aggregate ResultSets |
| /** |
| * Test ScalarAggregateResultSet |
| */ |
| public void testScalarAggregateResultSet() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| PreparedStatement del = |
| prepareStatement("delete from emp where mgrname = ?"); |
| |
| // BulkTableScanResultSet, ProjectRestrictResultSet, |
| // ScalarAggregateResultSet, ScrollInsensitiveResultSet |
| PreparedStatement ps = prepareStatement |
| ("select max(c0) from emp where mgrname = ?"); |
| |
| testScalarAggregateResultSet(ps, del); |
| |
| Statement s = createStatement(); |
| s.executeUpdate("drop table emp"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // re-run test on the new table (statements will be re-prepared) |
| testScalarAggregateResultSet(ps, del); |
| |
| // restore data |
| s.executeUpdate("delete from emp"); |
| s.executeUpdate(insertFrom("emp", "emp_data")); |
| commit(); |
| |
| // make sure another transaction has exclusive locks |
| Statement s2 = c2.createStatement(); |
| s2.executeUpdate("update emp set c0 = c0"); |
| |
| // re-run test with different isolation level (will get lock timeout |
| // with other isolation levels) |
| getConnection(). |
| setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); |
| // don't execute the delete statement since it would try to obtain |
| // exclusive locks and time out |
| testScalarAggregateResultSet(ps, null); |
| |
| ps.close(); |
| del.close(); |
| s.close(); |
| s2.close(); |
| } |
| |
| private void testScalarAggregateResultSet(PreparedStatement ps, |
| PreparedStatement del) |
| throws SQLException |
| { |
| for (int i = 0; i < non_mgrs.length; ++i) { |
| ps.setObject(1,non_mgrs[i]); |
| ResultSet rs = ps.executeQuery(); |
| rs.next(); |
| assertNull(rs.getObject(1)); |
| assertFalse(rs.next()); |
| // Re-execute ps with the same parameters |
| rs = ps.executeQuery(); |
| rs.next(); |
| assertNull(rs.getObject(1)); |
| assertFalse(rs.next()); |
| rs.close(); |
| } |
| |
| if (del == null) { |
| return; |
| } |
| |
| Object [][][] m = new Object[][][] { |
| {{i5}}, {{i16}}, {{i10}}, {{i11}}, {{i15}}, {{i20}} |
| }; |
| for (int i = 0; i < mgrs.length; ++i) { |
| ps.setObject(1,mgrs[i]); |
| ResultSet rs = ps.executeQuery(); |
| assertResultSet("i="+i+" ?="+mgrs[i], m[i], rs); |
| // Re-execute ps with the same parameters |
| rs = ps.executeQuery(); |
| assertResultSet("Ri="+i+" ?="+mgrs[i], m[i], rs); |
| del.setString(1,mgrs[i]); |
| del.execute(); |
| } |
| } |
| |
| /** |
| * Test LastIndexKeyResultSet |
| */ |
| public void testLastIndexKeyResultSet() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // LastIndexKeyResultSet, ProjectRestrictResultSet, |
| // ScalarAggregateResultSet, ScrollInsensitiveResultSet, |
| PreparedStatement tst = prepareStatement |
| ("select ? || max(name) from emp"); |
| |
| // DeleteResultSet,ProjectRestrictResultSet, TableScanResultSet |
| PreparedStatement del = prepareStatement |
| ("delete from emp where name = ?"); |
| |
| testLastIndexKeyResultSet(tst, del); |
| |
| Statement s = createStatement(); |
| s.executeUpdate("drop table emp"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // re-execute on the new table |
| testLastIndexKeyResultSet(tst, del); |
| |
| // restore data |
| s.executeUpdate("delete from emp"); |
| s.executeUpdate(insertFrom("emp", "emp_data")); |
| commit(); |
| |
| // make sure another transaction has exclusive locks |
| Statement s2 = c2.createStatement(); |
| s2.executeUpdate("update emp set c0 = c0"); |
| |
| // re-execute with different isolation level (will get lock timeout |
| // with other isolation levels) |
| getConnection(). |
| setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); |
| tst.setString(1, "0_"); |
| JDBC.assertFullResultSet(tst.executeQuery(), |
| new String[][] {{"0_" + truong}}, |
| false); |
| |
| tst.close(); |
| del.close(); |
| s.close(); |
| s2.close(); |
| } |
| |
| private void testLastIndexKeyResultSet(PreparedStatement tst, |
| PreparedStatement del) |
| throws SQLException |
| { |
| Object[][][] expected = new Object[][][] { |
| {{"0_"+truong}}, {{"1_"+sam2}}, {{"2_"+sam1}}, {{"3_"+roger}}, |
| {{"4_"+robin}}, {{"5_"+monica}}, {{"6_"+lily2}}, {{"7_"+lily1}}, |
| {{"8_"+larry2}}, {{"9_"+larry1}}, {{"10_"+john}}, {{"11_"+joe2}}, |
| {{"12_"+joe1}}, {{"13_"+jim}}, {{"14_"+hamid}}, {{"15_"+guy}}, |
| {{"16_"+don}}, {{"17_"+dan}}, {{"18_"+bobbie}}, {{"19_"+ashok}}, |
| {{ null }} |
| }; |
| |
| for (int i = 0; i < expected.length; ++i) { |
| tst.setString(1, Integer.toString(i) +"_"); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("?="+i+"_", expected[i], rs); |
| |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("R ?="+i+"_", expected[i], rs); |
| |
| String victim = (String)expected[i][0][0]; |
| |
| if (victim == null) { continue; } |
| del.setString(1, victim.substring(victim.indexOf('_')+1)); |
| del.execute(); |
| } |
| } |
| |
| /** |
| * Test DistinctScanResultSet |
| */ |
| public void testDistinctScanResultSet() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| PreparedStatement del = |
| prepareStatement("delete from emp where mgrname = ?"); |
| |
| // DistinctScanResultSet, ScrollInsensitiveResultSet |
| PreparedStatement tst = prepareStatement |
| ("select ? || T.dm from "+ |
| "(select distinct mgrname dm from emp) as T"); |
| |
| testDistinctScanResultSet(tst, del); |
| |
| Statement s = createStatement(); |
| s.executeUpdate("drop table emp"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // re-execute on the new table |
| testDistinctScanResultSet(tst, del); |
| |
| // restore data |
| s.executeUpdate("delete from emp"); |
| s.executeUpdate(insertFrom("emp", "emp_data")); |
| commit(); |
| |
| // make sure another transaction has exclusive locks |
| Statement s2 = c2.createStatement(); |
| s2.executeUpdate("update emp set c0 = c0"); |
| |
| // re-execute with different isolation level (will get lock timeout |
| // with other isolation levels) |
| getConnection(). |
| setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); |
| tst.setString(1, "0_"); |
| // don't check contents, only that the query doesn't hang |
| JDBC.assertDrainResults(tst.executeQuery(), 7); |
| |
| tst.close(); |
| del.close(); |
| s.close(); |
| s2.close(); |
| } |
| |
| private void testDistinctScanResultSet(PreparedStatement tst, |
| PreparedStatement del) |
| throws SQLException |
| { |
| Object[][][] expected = new Object[][][] { |
| {{ "0_"+roger }, { "0_"+john }, { "0_"+robin }, |
| { "0_"+guy },{ "0_"+hamid },{ "0_"+ashok },{ null }}, |
| {{ "1_"+roger },{ "1_"+john },{ "1_"+robin }, |
| { "1_"+guy },{ "1_"+hamid },{ null }}, |
| {{ "2_"+roger },{ "2_"+robin },{ "2_"+guy }, |
| { "2_"+hamid },{ null }}, |
| {{ "3_"+roger },{ "3_"+robin },{ "3_"+guy },{ null }}, |
| {{ "4_"+roger },{ "4_"+guy },{ null }}, |
| {{ "5_"+guy },{ null }}, |
| {{ null }} |
| }; |
| for (int i = 0; i < expected.length; ++i) { |
| tst.setString(1,Integer.toString(i) +"_"); |
| ResultSet rs = tst.executeQuery(); |
| JDBC.assertUnorderedResultSet(rs, expected[i], false); |
| |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| JDBC.assertUnorderedResultSet(rs, expected[i], false); |
| |
| if (i < mgrs.length) { |
| del.setObject(1, mgrs[i]); |
| del.execute(); |
| } |
| } |
| } |
| |
| /** |
| * Test DistinctScalarAggregateResultSet |
| */ |
| public void testDistinctScalarAggregateResultSet() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| PreparedStatement del = |
| prepareStatement("delete from emp where mgrname = ?"); |
| |
| // DistinctScalarAggregateResultSet, |
| // BulkTableScanResultSet, ProjectRestrictResultSet, |
| // ScrollInsensitiveResultSet |
| PreparedStatement tst = prepareStatement |
| ("select count(distinct mgrname)+? from emp"); |
| |
| testDistinctScalarAggregateResultSet(tst, del); |
| |
| Statement s = createStatement(); |
| s.executeUpdate("drop table emp"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // re-execute on the new table |
| testDistinctScalarAggregateResultSet(tst, del); |
| |
| // restore data |
| s.executeUpdate("delete from emp"); |
| s.executeUpdate(insertFrom("emp", "emp_data")); |
| commit(); |
| |
| // make sure another transaction has exclusive locks |
| Statement s2 = c2.createStatement(); |
| s2.executeUpdate("update emp set c0 = c0"); |
| |
| // re-execute with different isolation level (will get lock timeout |
| // with other isolation levels) |
| getConnection(). |
| setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); |
| tst.setInt(1, 0); |
| JDBC.assertFullResultSet(tst.executeQuery(), |
| new Integer[][] {{i6}}, |
| false); |
| |
| tst.close(); |
| del.close(); |
| s.close(); |
| s2.close(); |
| } |
| |
| private void testDistinctScalarAggregateResultSet(PreparedStatement tst, |
| PreparedStatement del) |
| throws SQLException |
| { |
| Object[][][] expected = new Object[][][] { |
| {{i6}}, {{i6}}, {{i6}}, {{i6}}, {{i6}}, {{i6}}, {{i6}} |
| }; |
| for (int i = 0; i < expected.length; ++i) { |
| tst.setInt(1,i); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("?="+i,expected[i],rs); |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("R?="+i,expected[i],rs); |
| if (i < mgrs.length) { |
| del.setString(1,mgrs[i]); |
| del.execute(); |
| } |
| } |
| } |
| |
| /** |
| * Test DistinctGroupedAggregateResultSet |
| */ |
| public void testDistinctGroupedAggregateResultSet() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| PreparedStatement del = |
| prepareStatement("delete from emp where mgrname = ?"); |
| |
| // DistinctGroupedAggregateResultSet, |
| // ProjectRestrictResultSet,ScrollInsensitiveResultSet, |
| // TableScanResultSet |
| PreparedStatement tst = prepareStatement |
| ("select count(distinct mgrname) nummgrs, dno "+ |
| "from emp group by dno having dno <> ?"); |
| |
| testDistinctGroupedAggregateResultSet(tst, del); |
| |
| Statement s = createStatement(); |
| s.executeUpdate("drop table emp"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // re-execute on the new table |
| testDistinctGroupedAggregateResultSet(tst, del); |
| |
| // restore data |
| s.executeUpdate("delete from emp"); |
| s.executeUpdate(insertFrom("emp", "emp_data")); |
| commit(); |
| |
| // make sure another transaction has exclusive locks |
| Statement s2 = c2.createStatement(); |
| s2.executeUpdate("update emp set c0 = c0"); |
| |
| // re-execute with different isolation level (will get lock timeout |
| // with other isolation levels) |
| getConnection(). |
| setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); |
| tst.setObject(1, dept[0][1]); |
| JDBC.assertFullResultSet(tst.executeQuery(), |
| new Object[][] {{i1, k51}, {i2, k52}}, |
| false); |
| |
| tst.close(); |
| del.close(); |
| s.close(); |
| s2.close(); |
| } |
| |
| private void testDistinctGroupedAggregateResultSet(PreparedStatement tst, |
| PreparedStatement del) |
| throws SQLException |
| { |
| final Integer i0 = 0; |
| Object[][][][] expected = new Object[][][][] { |
| { |
| {{ i1, k51 },{ i2, k52 }}, |
| {{ i1, k51 },{ i3, k55 }}, |
| {{ i2, k52 },{ i3, k55 }} |
| }, |
| { // - ashok |
| {{ i0, k51 },{ i2, k52 }}, |
| {{ i0, k51 },{ i3, k55 }}, |
| {{ i2, k52 },{ i3, k55 }} |
| }, |
| { // - john |
| {{ i0, k51 },{ i2, k52 }}, |
| {{ i0, k51 },{ i2, k55 }}, |
| {{ i2, k52 },{ i2, k55 }} |
| }, |
| { // - hamid |
| {{ i0, k51 },{ i2, k52 }}, |
| {{ i0, k51 },{ i1, k55 }}, |
| {{ i2, k52 },{ i1, k55 }} |
| }, |
| { // - robin |
| {{ i0, k51 },{ i1, k52 }}, |
| {{ i0, k51 },{ i1, k55 }}, |
| {{ i1, k52 },{ i1, k55 }} |
| }, |
| { // - roger |
| {{ i0, k51 }}, |
| {{ i0, k51 },{ i1, k55 }}, |
| {{ i1, k55 }} |
| }, |
| { // - guy |
| {{ i0, k51 }}, |
| {{ i0, k51 }}, |
| {} |
| } |
| }; |
| |
| for (int i = 0; i < expected.length; ++i) { |
| for (int d = 0; d < dept.length; ++d) { |
| tst.setObject(1,dept[d][1]); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("i="+i+" d="+d+"("+dept[d][1]+")", |
| expected[i][d], rs); |
| |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("Ri="+i+" d="+d+"("+dept[d][1]+")", |
| expected[i][d], rs); |
| } |
| if (i < mgrs.length) { |
| del.setString(1,mgrs[i]); |
| del.execute(); |
| } |
| } |
| } |
| |
| /** |
| * Test GroupedAggregateResultSet |
| */ |
| public void testGroupedAggregateResultSet() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| PreparedStatement del = |
| prepareStatement("delete from emp where name = ?"); |
| |
| // TableScanResultSet, ProjectRestrictResultSet, |
| // GroupedAggregateResultSet, ScrollInsensitiveResultSet |
| PreparedStatement tst = prepareStatement |
| ("select max(name) maxemp, mgrname from emp "+ |
| "group by mgrname having mgrname <> ?"); |
| |
| testGroupedAggregateResultSet(tst, del); |
| |
| Statement s = createStatement(); |
| s.executeUpdate("drop table emp"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // re-execute on the new table |
| testGroupedAggregateResultSet(tst, del); |
| |
| // restore data |
| s.executeUpdate("delete from emp"); |
| s.executeUpdate(insertFrom("emp", "emp_data")); |
| commit(); |
| |
| // make sure another transaction has exclusive locks |
| Statement s2 = c2.createStatement(); |
| s2.executeUpdate("update emp set c0 = c0"); |
| |
| // re-execute with different isolation level (will get lock timeout |
| // with other isolation levels) |
| getConnection(). |
| setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); |
| tst.setString(1, mgrs[0]); |
| JDBC.assertDrainResults(tst.executeQuery(), 5); |
| |
| tst.close(); |
| del.close(); |
| s.close(); |
| s2.close(); |
| } |
| |
| private void testGroupedAggregateResultSet(PreparedStatement tst, |
| PreparedStatement del) |
| throws SQLException |
| { |
| Object[][][] expected = new Object[][][] { |
| { |
| { monica, guy }, |
| { truong, hamid }, |
| { hamid, john }, |
| { roger, robin }, |
| { sam2, roger } |
| }, |
| { // -ashok |
| { robin, ashok }, |
| { monica, guy }, |
| { truong, hamid }, |
| { roger, robin }, |
| { sam2, roger } |
| }, |
| { // -ashok,john |
| { robin, ashok }, |
| { monica, guy }, |
| { hamid, john }, |
| { roger, robin }, |
| { sam2, roger } |
| }, |
| { // -ashok,john,hamid |
| { robin, ashok }, |
| { monica, guy }, |
| { truong, hamid }, |
| { guy, john }, |
| { sam2, roger } |
| }, |
| { // -ashok,john,hamid,robin |
| { joe2, ashok }, |
| { monica, guy }, |
| { truong, hamid }, |
| { guy, john }, |
| { roger, robin }, |
| }, |
| { // -ashok,john,hamid,robin,roger |
| { joe2, ashok }, |
| { truong, hamid }, |
| { guy, john }, |
| { sam2, roger } |
| }, |
| }; |
| |
| for (int i = 0; i < mgrs.length; ++i) { |
| tst.setString(1,mgrs[i]); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("?="+mgrs[i], expected[i], rs); |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("R?="+mgrs[i], expected[i], rs); |
| |
| if (i < mgrs.length) { |
| del.setString(1,mgrs[i]); |
| del.execute(); |
| } |
| } |
| } |
| |
| |
| |
| // Fixtures for join ResultSets |
| /** |
| * Test NestedLoopResultSet |
| */ |
| public void testNestedLoopResultSet() throws Exception { |
| createTestTable("dept", DS, "dept_data"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| PreparedStatement del = |
| prepareStatement("delete from emp where mgrname = ?"); |
| |
| PreparedStatement tst = prepareStatement |
| ("select T.name, T.mgrname, T.dno, dept.dname from dept, "+ |
| "(select * from emp where mgrname = ?) as T "+ |
| "where dept.dno = T.dno"); |
| |
| testNestedLoopResultSet(tst, del); |
| |
| Statement s = createStatement(); |
| s.executeUpdate("drop table emp"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // re-execute on the new table |
| testNestedLoopResultSet(tst, del); |
| |
| // restore data |
| s.executeUpdate("delete from emp"); |
| s.executeUpdate(insertFrom("emp", "emp_data")); |
| commit(); |
| |
| // make sure another transaction has exclusive locks |
| Statement s2 = c2.createStatement(); |
| s2.executeUpdate("update emp set c0 = c0"); |
| |
| // re-execute with different isolation level (will get lock timeout |
| // with other isolation levels) |
| getConnection(). |
| setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); |
| tst.setString(1, mgrs[0]); |
| JDBC.assertDrainResults(tst.executeQuery(), 4); |
| |
| tst.close(); |
| del.close(); |
| s.close(); |
| s2.close(); |
| } |
| |
| private void testNestedLoopResultSet(PreparedStatement tst, |
| PreparedStatement del) |
| throws SQLException |
| { |
| for (int i = 0; i < non_mgrs.length; ++i) { |
| tst.setString(1,non_mgrs[i]); |
| ResultSet rs = tst.executeQuery(); |
| assertFalse(rs.next()); |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertFalse(rs.next()); |
| rs.close(); |
| } |
| Object[][][] results = new Object[][][] { |
| {{ john, ashok, k51, "CS " }, |
| { robin, ashok, k51, "CS " }, |
| { joe1, ashok, k51, "CS " }, |
| { joe2, ashok, k51, "CS " }}, |
| |
| {{ hamid, john, k55, "DB " }, |
| { guy, john, k55, "DB " }}, |
| |
| {{ truong, hamid, k55, "DB " }, |
| { larry1, hamid, k55, "DB " }, |
| { larry2, hamid, k55, "DB " }, |
| { bobbie, hamid, k55, "DB " }}, |
| |
| {{ roger, robin, k52, "OFC " }}, |
| |
| {{ jim, roger, k52, "OFC " }, |
| { dan, roger, k52, "OFC " }, |
| { sam1, roger, k52, "OFC " }, |
| { sam2, roger, k52, "OFC " }}, |
| |
| {{ don, guy, k55, "DB " }, |
| { monica, guy, k55, "DB " }, |
| { lily1, guy, k55, "DB " }, |
| { lily2, guy, k55, "DB " }} |
| }; |
| for (int i = 0; i < mgrs.length; ++i) { |
| tst.setString(1,mgrs[i]); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("i="+i+" ?="+mgrs[i],results[i],rs); |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("Ri="+i+" ?="+mgrs[i],results[i],rs); |
| del.setString(1,mgrs[i]); |
| del.execute(); |
| } |
| } |
| |
| /** |
| * Test HashTableResultSet |
| */ |
| public void testHashTableResultSet() throws Exception { |
| createTestTable("dept", DS, "dept_data"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| PreparedStatement del = |
| prepareStatement("delete from emp where mgrname = ?"); |
| |
| Statement s = createStatement(); |
| s.execute("create view vemp as select * from emp"); |
| s.execute("create view vdept as select * from dept"); |
| // HashJoinResultSet, HashTableResultSet, |
| // ProjectRestrictResultSet,ScrollInsensitiveResultSet, |
| // TableScanResultSet |
| PreparedStatement tst = prepareStatement |
| ("select vemp.name, vemp.mgrname, vemp.dno, vdept.dname "+ |
| "from vemp inner join vdept on vemp.dno = vdept.dno "+ |
| "where mgrname = ?"); |
| |
| testHashTableResultSet(tst, del); |
| |
| s.executeUpdate("drop view vemp"); |
| s.executeUpdate("drop view vdept"); |
| s.executeUpdate("drop table dept"); |
| createTestTable("dept", DS, "dept_data"); |
| s.executeUpdate("drop table emp"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| s.executeUpdate("create view vemp as select * from emp"); |
| s.executeUpdate("create view vdept as select * from dept"); |
| |
| // re-execute on the new tables |
| testHashTableResultSet(tst, del); |
| |
| // restore data |
| s.executeUpdate("delete from emp"); |
| s.executeUpdate(insertFrom("emp", "emp_data")); |
| commit(); |
| |
| // make sure another transaction has exclusive locks |
| Statement s2 = c2.createStatement(); |
| s2.executeUpdate("update emp set c0 = c0"); |
| |
| // re-execute with different isolation level (will get lock timeout |
| // with other isolation levels) |
| getConnection(). |
| setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); |
| tst.setString(1, mgrs[0]); |
| JDBC.assertDrainResults(tst.executeQuery(), 4); |
| |
| tst.close(); |
| del.close(); |
| s.close(); |
| s2.close(); |
| } |
| |
| private void testHashTableResultSet(PreparedStatement tst, |
| PreparedStatement del) |
| throws SQLException |
| { |
| for (int i = 0; i < non_mgrs.length; ++i) { |
| tst.setObject(1,non_mgrs[i]); |
| ResultSet rs = tst.executeQuery(); |
| assertFalse(rs.next()); |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertFalse(rs.next()); |
| rs.close(); |
| } |
| Object[][][] results = new Object[][][] { |
| {{ john, ashok, k51, "CS " }, |
| { robin, ashok, k51, "CS " }, |
| { joe1, ashok, k51, "CS " }, |
| { joe2, ashok, k51, "CS " }}, |
| |
| {{ hamid, john, k55, "DB " }, |
| { guy, john, k55, "DB " }}, |
| |
| {{ truong, hamid, k55, "DB " }, |
| { larry1, hamid, k55, "DB " }, |
| { larry2, hamid, k55, "DB " }, |
| { bobbie, hamid, k55, "DB " }}, |
| |
| {{ roger, robin, k52, "OFC " }}, |
| |
| {{ jim, roger, k52, "OFC " }, |
| { dan, roger, k52, "OFC " }, |
| { sam1, roger, k52, "OFC " }, |
| { sam2, roger, k52, "OFC " }}, |
| |
| {{ don, guy, k55, "DB " }, |
| { monica, guy, k55, "DB " }, |
| { lily1, guy, k55, "DB " }, |
| { lily2, guy, k55, "DB " }} |
| }; |
| for (int i = 0; i < mgrs.length; ++i) { |
| tst.setObject(1,mgrs[i]); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("i="+i+" ?="+mgrs[i],results[i],rs); |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("Ri="+i+" ?="+mgrs[i],results[i],rs); |
| del.setString(1,mgrs[i]); |
| del.execute(); |
| } |
| } |
| |
| /** |
| * Test NestedLoopLeftOuterJoinResultSet |
| */ |
| public void testNestedLoopLeftOuterJoinResultSet() throws Exception { |
| createTestTable("dept", DS, "dept_data"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| PreparedStatement del = |
| prepareStatement("delete from emp where mgrname = ?"); |
| // BulkTableScanResultSet,IndexRowToBaseRowResultSet, |
| // NestedLoopLeftOuterJoinResultSet, |
| // ProjectRestrictResultSet, ScrollInsensitiveResultSet, |
| // TableScanResultSet |
| PreparedStatement tst = prepareStatement |
| ("select emp.name, emp.mgrname, emp.dno, dept.dname "+ |
| "from emp left outer join dept on emp.dno = dept.dno "+ |
| "where mgrname = ?"); |
| |
| testNestedLoopLeftOuterJoinResultSet(tst, del); |
| |
| Statement s = createStatement(); |
| s.executeUpdate("drop table dept"); |
| createTestTable("dept", DS, "dept_data"); |
| s.executeUpdate("drop table emp"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // re-execute on the new table |
| testNestedLoopLeftOuterJoinResultSet(tst, del); |
| |
| // restore data |
| s.executeUpdate("delete from emp"); |
| s.executeUpdate(insertFrom("emp", "emp_data")); |
| commit(); |
| |
| // make sure another transaction has exclusive locks |
| Statement s2 = c2.createStatement(); |
| s2.executeUpdate("update emp set c0 = c0"); |
| |
| // re-execute with different isolation level (will get lock timeout |
| // with other isolation levels) |
| getConnection(). |
| setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); |
| tst.setString(1, mgrs[0]); |
| JDBC.assertDrainResults(tst.executeQuery(), 4); |
| |
| tst.close(); |
| del.close(); |
| s.close(); |
| s2.close(); |
| } |
| |
| private void testNestedLoopLeftOuterJoinResultSet(PreparedStatement tst, |
| PreparedStatement del) |
| throws SQLException |
| { |
| for (int i = 0; i < non_mgrs.length; ++i) { |
| tst.setObject(1,non_mgrs[i]); |
| ResultSet rs = tst.executeQuery(); |
| assertFalse(rs.next()); |
| rs = tst.executeQuery(); |
| assertFalse(rs.next()); |
| rs.close(); |
| } |
| Object[][][] results = new Object[][][] { |
| {{ john, ashok, k51, "CS " }, |
| { robin, ashok, k51, "CS " }, |
| { joe1, ashok, k51, "CS " }, |
| { joe2, ashok, k51, "CS " }}, |
| |
| {{ hamid, john, k55, "DB " }, |
| { guy, john, k55, "DB " }}, |
| |
| {{ truong, hamid, k55, "DB " }, |
| { larry1, hamid, k55, "DB " }, |
| { larry2, hamid, k55, "DB " }, |
| { bobbie, hamid, k55, "DB " }}, |
| |
| {{ roger, robin, k52, "OFC " }}, |
| |
| {{ jim, roger, k52, "OFC " }, |
| { dan, roger, k52, "OFC " }, |
| { sam1, roger, k52, "OFC " }, |
| { sam2, roger, k52, "OFC " }}, |
| |
| {{ don, guy, k55, "DB " }, |
| { monica, guy, k55, "DB " }, |
| { lily1, guy, k55, "DB " }, |
| { lily2, guy, k55, "DB " }} |
| }; |
| for (int i = 0; i < mgrs.length; ++i) { |
| tst.setObject(1,mgrs[i]); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("i="+i+" ?="+mgrs[i],results[i],rs); |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("Ri="+i+" ?="+mgrs[i],results[i],rs); |
| del.setString(1,mgrs[i]); |
| del.execute(); |
| } |
| } |
| |
| /** |
| * Test HashLeftOuterJoinResultSet |
| */ |
| public void testHashLeftOuterJoinResultSet() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| createTestTable("emp2", ES+","+DNO+")", "emp_data"); |
| PreparedStatement del = |
| prepareStatement("delete from emp where mgrname = ?"); |
| |
| // BulkTableScanResultSet, HashLeftOuterJoinResultSet, |
| // HashScanResultSet, ProjectRestrictResultSet, |
| // ScrollInsensitiveResultSet, SortResultSet |
| PreparedStatement tst = prepareStatement |
| ("select distinct emp.* "+ |
| "from emp left outer join emp2 on emp.dno = emp2.dno "+ |
| "where emp.mgrname = ? order by emp.c0"); |
| |
| testHashLeftOuterJoinResultSet(tst, del); |
| |
| Statement s = createStatement(); |
| s.executeUpdate("drop table emp"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| s.executeUpdate("drop table emp2"); |
| createTestTable("emp2", ES+","+DNO+")", "emp_data"); |
| |
| // re-execute on the new table |
| testHashLeftOuterJoinResultSet(tst, del); |
| |
| // restore data |
| s.executeUpdate("delete from emp"); |
| s.executeUpdate(insertFrom("emp", "emp_data")); |
| commit(); |
| |
| // make sure another transaction has exclusive locks |
| Statement s2 = c2.createStatement(); |
| s2.executeUpdate("update emp set c0 = c0"); |
| |
| // re-execute with different isolation level (will get lock timeout |
| // with other isolation levels) |
| getConnection(). |
| setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); |
| tst.setString(1, mgrs[0]); |
| JDBC.assertDrainResults(tst.executeQuery(), 4); |
| |
| tst.close(); |
| del.close(); |
| s.close(); |
| s2.close(); |
| } |
| |
| private void testHashLeftOuterJoinResultSet(PreparedStatement tst, |
| PreparedStatement del) |
| throws SQLException |
| { |
| for (int i = 0; i < non_mgrs.length; ++i) { |
| tst.setObject(1,non_mgrs[i]); |
| ResultSet rs = tst.executeQuery(); |
| assertFalse(rs.next()); |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertFalse(rs.next()); |
| rs.close(); |
| } |
| Object[][][] results = new Object[][][] { |
| { john_emp, robin_emp, joe1_emp, joe2_emp }, |
| { hamid_emp, guy_emp }, |
| { truong_emp, larry1_emp, larry2_emp, bobbie_emp }, |
| { roger_emp }, |
| { jim_emp, dan_emp, sam1_emp, sam2_emp }, |
| { don_emp, monica_emp, lily1_emp, lily2_emp } |
| }; |
| for (int i = 0; i < mgrs.length; ++i) { |
| tst.setObject(1,mgrs[i]); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("i="+i+" ?="+mgrs[i],results[i],rs); |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("Ri="+i+" ?="+mgrs[i],results[i],rs); |
| del.setString(1,mgrs[i]); |
| del.execute(); |
| } |
| } |
| |
| // Fixtures for update ResultSets |
| /** |
| * Test UpdateResultSet |
| */ |
| public void testUpdateResultSet() throws Exception { |
| createTestTable("dept", DS, "dept_data"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // IndexRowToBaseRowResultSet, NormalizeResultSet, |
| // ProjectRestrictResultSet, TableScanResultSet, |
| // UpdateResultSet |
| PreparedStatement tst = prepareStatement |
| ("update dept set dname = ? where dno = ?"); |
| PreparedStatement sel = prepareStatement |
| ("select dno, dname from dept order by c0"); |
| |
| Object[][][] expected = new Object[][][] { |
| { {k55, "DataBase "}, {k52, "OFC "}, {k51, "CS "} }, |
| { {k55, "DataBase "}, {k52, "Office "}, {k51, "CS "} }, |
| { {k55, "DataBase "}, {k52, "Office "}, {k51, "Computer S"} } |
| }; |
| |
| for (int i = 0; i < expected.length; ++i) { |
| tst.setObject(1, expected[i][i][1]); |
| tst.setObject(2, expected[i][i][0]); |
| tst.executeUpdate(); |
| ResultSet rs = sel.executeQuery(); |
| assertResultSet("i="+i+" ?="+expected[i][i][1]+" ?="+ |
| expected[i][i][0],expected[i],rs); |
| // Re-execute with the same parameters |
| tst.executeUpdate(); |
| rs = sel.executeQuery(); |
| assertResultSet("Ri="+i+" ?="+expected[i][i][1]+" ?="+ |
| expected[i][i][0],expected[i],rs); |
| } |
| tst.close(); |
| sel.close(); |
| } |
| |
| /** |
| * Test that an UpdateResultSet is able to detect changes in isolation |
| * level between executions. |
| */ |
| public void testUpdateResultSetWithIsolation() throws SQLException { |
| createTestTable("dept", DS, "dept_data"); |
| commit(); |
| PreparedStatement ps = prepareStatement("update dept set c0 = c0"); |
| getConnection().setTransactionIsolation( |
| Connection.TRANSACTION_SERIALIZABLE); |
| assertEquals(3, ps.executeUpdate()); |
| // when serializable, UpdateResultSet uses table-level locking |
| assertTrue(hasTableXLock("DEPT")); |
| commit(); |
| // all locks released on commit |
| assertFalse(hasTableXLock("DEPT")); |
| getConnection().setTransactionIsolation( |
| Connection.TRANSACTION_READ_COMMITTED); |
| assertEquals(3, ps.executeUpdate()); |
| // when read committed, UpdateResultSet uses row-level locking |
| assertFalse(hasTableXLock("DEPT")); |
| ps.close(); |
| } |
| |
| /** |
| * Test CurrentOfResultSet |
| */ |
| public void testCurrentOfResultSet() throws Exception { |
| createTestTable("dept", DS, "dept_data"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| PreparedStatement selForUpd = prepareStatement |
| ("select * from dept for update of dname"); |
| selForUpd.setCursorName("C1"); |
| ResultSet rs = selForUpd.executeQuery(); |
| // CurrentOfResultSet, NormalizeResultSet, |
| // ProjectRestrictResultSet, UpdateResultSet |
| PreparedStatement tst = prepareStatement |
| ("update dept set dname = ? where current of C1"); |
| |
| PreparedStatement sel = prepareStatement("select dname from dept"); |
| |
| Object[][][] expected = new Object[][][] { |
| {{"foobar___0"},{"OFC "},{"CS "}}, |
| {{"foobar___0"},{"foobar___1"},{"CS "}}, |
| {{"foobar___0"},{"foobar___1"},{"foobar___2"}} |
| }; |
| |
| for (int i = 0; i < expected.length; ++i) { |
| assertTrue(rs.next()); |
| tst.setObject(1, expected[i][i][0]); |
| tst.executeUpdate(); |
| ResultSet sel_rs = sel.executeQuery(); |
| assertResultSet("i="+i+" ?="+expected[i][i][0], |
| expected[i], sel_rs); |
| // Re-execute tst with the same parameters |
| tst.executeUpdate(); |
| sel_rs = sel.executeQuery(); |
| assertResultSet("Ri="+i+" ?="+expected[i][i][0], |
| expected[i], sel_rs); |
| } |
| assertFalse(rs.next()); |
| rs.close(); |
| tst.close(); |
| sel.close(); |
| selForUpd.close(); |
| } |
| |
| |
| // Fixtures for delete ResultSets |
| /** |
| * Test DeleteResultSet |
| */ |
| public void testDeleteResultSet() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // DeleteResultSet, ProjectRestrictResultSet, TableScanResultSet |
| PreparedStatement tst = prepareStatement |
| ("delete from emp where mgrname = ?"); |
| PreparedStatement sel = prepareStatement |
| ("select * from emp"); |
| |
| for (int i = 0; i < non_mgrs.length; ++i) { |
| tst.setObject(1,non_mgrs[i]); |
| tst.execute(); |
| ResultSet rs = sel.executeQuery(); |
| assertResultSet("i="+i+" ?="+non_mgrs[i], emp, rs); |
| // Re-execute tst with the same parameters |
| tst.execute(); |
| rs = sel.executeQuery(); |
| assertResultSet("Ri="+i+" ?="+non_mgrs[i], emp, rs); |
| } |
| |
| Object [][][] expected = new Object [][][] { |
| { ashok_emp, hamid_emp, truong_emp, larry1_emp, |
| larry2_emp, bobbie_emp, roger_emp, jim_emp, |
| dan_emp, sam1_emp, sam2_emp, guy_emp, don_emp, |
| monica_emp, lily1_emp, lily2_emp }, |
| |
| { ashok_emp, truong_emp, larry1_emp, larry2_emp, |
| bobbie_emp, roger_emp, jim_emp, dan_emp, sam1_emp, |
| sam2_emp, don_emp, monica_emp, lily1_emp, lily2_emp }, |
| |
| { ashok_emp, roger_emp, jim_emp, dan_emp, sam1_emp, |
| sam2_emp, don_emp, monica_emp, lily1_emp, lily2_emp }, |
| |
| { ashok_emp, jim_emp, dan_emp, sam1_emp, sam2_emp, |
| don_emp, monica_emp, lily1_emp, lily2_emp }, |
| |
| { ashok_emp, don_emp, monica_emp, lily1_emp, lily2_emp }, |
| { ashok_emp } |
| }; |
| |
| for (int i = 0; i < mgrs.length; ++i) { |
| tst.setObject(1,mgrs[i]); |
| tst.execute(); |
| ResultSet rs = sel.executeQuery(); |
| assertResultSet("i="+i+" ?="+non_mgrs[i], expected[i], rs); |
| //dumpAsObjectArray(rs,System.err); |
| // Re-execute tst with the same parameters |
| tst.execute(); |
| rs = sel.executeQuery(); |
| assertResultSet("Ri="+i+" ?="+non_mgrs[i], expected[i], rs); |
| } |
| tst.close(); |
| sel.close(); |
| } |
| /** |
| * Test DeleteCascadeUpdateResultSet |
| */ |
| public void testDeleteCascadeUpdateResultSet() throws Exception { |
| createTestTable("dept", DS, "dept_data"); |
| createTestTable("emp", |
| ES+ref("emp")+SETN+","+DNO+ref("dept")+SETN+")", |
| "emp_data"); |
| |
| PreparedStatement delMgr = prepareStatement |
| ("delete from emp where mgrname = ?"); |
| |
| // DeleteCascadeResultSet, DeleteCascadeUpdateResultSet, |
| // NormalizeResultSet,ProjectRestrictResultSet, |
| // RaDependentTableScanResultSet, TableScanResultSet |
| // TODO: Parameters? Possible? |
| PreparedStatement tst = prepareStatement("delete from emp"); |
| PreparedStatement ins = prepareStatement(insertFrom("emp", "emp_data")); |
| PreparedStatement sel = prepareStatement("select * from emp"); |
| for (int i = 0; i < mgrs.length; ++i) { |
| // Delete some rows so that del will get a different workload |
| delMgr.setString(1,mgrs[i]); |
| delMgr.execute(); |
| |
| // Delete all remaining rows (this is what we test here) |
| tst.execute(); |
| ResultSet rs = sel.executeQuery(); |
| assertFalse(rs.next()); |
| rs.close(); |
| // Fill table for next loop iteration |
| ins.execute(); |
| } |
| delMgr.close(); |
| tst.close(); |
| ins.close(); |
| sel.close(); |
| } |
| |
| |
| // Fixtures for set operation ResultSets |
| /** |
| * Test SetOpResultSet intersect |
| */ |
| public void testSetOpResultSet_intersect() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // SetOpResultSet |
| PreparedStatement tst = prepareStatement |
| ("select * from emp where dno = ? intersect "+ |
| "select * from emp where mgrname = ?"); |
| |
| Object[][][][] expected = new Object [][][][] { |
| { // K55 |
| {}, // ashok |
| { hamid_emp, guy_emp }, // john |
| { truong_emp, larry1_emp, larry2_emp, bobbie_emp }, // hamid |
| {}, // robin |
| {}, // roger |
| { don_emp, monica_emp, lily1_emp, lily2_emp } // guy |
| }, |
| { // K52 |
| {}, // ashok |
| {}, // john |
| {}, // hamid |
| { roger_emp }, // robin |
| { jim_emp, dan_emp, sam1_emp, sam2_emp }, // roger |
| {}, // guy |
| }, |
| { // K51 |
| { john_emp, robin_emp, joe1_emp, joe2_emp }, // ashok |
| {}, // john |
| {}, // hamid |
| {}, // robin |
| {}, // roger |
| {} // guy |
| } |
| }; |
| |
| for (int d = 0; d < dept.length; ++d) { |
| tst.setObject(1,dept[d][1]); |
| for (int m = 0; m < mgrs.length; ++m) { |
| tst.setString(2,mgrs[m]); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("?="+dept[d][1]+" ?="+mgrs[m], |
| expected[d][m], rs); |
| |
| // Re-execution of tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("R?="+dept[d][1]+" ?="+mgrs[m], |
| expected[d][m], rs); |
| } |
| } |
| tst.close(); |
| } |
| |
| /** |
| * Test SetOpResultSet except |
| */ |
| public void testSetOpResultSet_except() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // SetOpResultSet |
| PreparedStatement tst = prepareStatement |
| ("select * from emp where dno = ? except "+ |
| "select * from emp where mgrname = ?"); |
| |
| Object[][][][] expected = new Object [][][][] { |
| { // K55 |
| { hamid_emp, truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| guy_emp, don_emp, monica_emp, lily1_emp, |
| lily2_emp }, // ashok |
| |
| { truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| don_emp, monica_emp, lily1_emp, lily2_emp }, // john |
| |
| { hamid_emp, guy_emp, don_emp, monica_emp, lily1_emp, |
| lily2_emp }, // hamid |
| |
| { hamid_emp, truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| guy_emp, don_emp, monica_emp, lily1_emp, |
| lily2_emp}, // robin |
| |
| { hamid_emp, truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| guy_emp, don_emp, monica_emp, lily1_emp, |
| lily2_emp}, // roger |
| |
| { hamid_emp, truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| guy_emp } // guy |
| }, |
| { // K52 |
| { roger_emp, jim_emp, dan_emp, sam1_emp, sam2_emp }, // ashok |
| { roger_emp, jim_emp, dan_emp, sam1_emp, sam2_emp }, // john |
| { roger_emp, jim_emp, dan_emp, sam1_emp, sam2_emp }, // hamid |
| { jim_emp, dan_emp, sam1_emp, sam2_emp }, // robin |
| { roger_emp }, // roger |
| { roger_emp, jim_emp, dan_emp, sam1_emp, sam2_emp }, // guy |
| }, |
| { // K51 |
| { ashok_emp }, // ashok |
| { ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp }, // john |
| { ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp }, // hamid |
| { ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp }, // robin |
| { ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp }, // roger |
| { ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp } // guy |
| } |
| }; |
| |
| for (int d = 0; d < dept.length; ++d) { |
| tst.setObject(1,dept[d][1]); |
| for (int m = 0; m < mgrs.length; ++m) { |
| tst.setString(2,mgrs[m]); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("?="+dept[d][1]+" ?="+mgrs[m], |
| expected[d][m], rs); |
| |
| // Re-execution of tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("R?="+dept[d][1]+" ?="+mgrs[m], |
| expected[d][m], rs); |
| } |
| } |
| tst.close(); |
| } |
| |
| /** |
| * Test UnionResultSet |
| */ |
| public void testUnionResultSet() throws Exception { |
| createTestTable("dept", DS, "dept_data"); |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // ScrollInsensitiveResultSet, SortResultSet, |
| // TableScanResultSet, UnionResultSet |
| PreparedStatement tst = prepareStatement |
| ("(select * from emp where dno = ?) union "+ |
| "(select * from emp where mgrname = ?)"); |
| |
| Object[][][][] expected = new Object [][][][] { |
| { // K55 |
| { john_emp, robin_emp, joe1_emp, joe2_emp, hamid_emp, |
| truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| guy_emp, don_emp, monica_emp, lily1_emp, |
| lily2_emp }, // ashok |
| |
| { hamid_emp, truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| guy_emp, don_emp, monica_emp, lily1_emp, lily2_emp }, // john |
| |
| { hamid_emp, truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| guy_emp, don_emp, monica_emp, lily1_emp, |
| lily2_emp }, // hamid |
| |
| { hamid_emp, truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| roger_emp, guy_emp, don_emp, monica_emp, lily1_emp, |
| lily2_emp }, // robin |
| |
| { hamid_emp, truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| jim_emp, dan_emp, sam1_emp, sam2_emp, guy_emp, don_emp, |
| monica_emp, lily1_emp, lily2_emp }, // roger |
| |
| { hamid_emp, truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| guy_emp, don_emp, monica_emp, lily1_emp, |
| lily2_emp } // guy |
| }, |
| { // K52 |
| { john_emp, robin_emp, joe1_emp, joe2_emp,roger_emp, |
| jim_emp, dan_emp, sam1_emp, sam2_emp, }, // ashok |
| { hamid_emp, roger_emp, jim_emp, dan_emp, sam1_emp, sam2_emp, |
| guy_emp }, // john |
| { truong_emp, larry1_emp, larry2_emp, bobbie_emp, |
| roger_emp, jim_emp, dan_emp, sam1_emp, sam2_emp }, // hamid |
| { roger_emp, jim_emp, dan_emp, sam1_emp, sam2_emp }, // robin |
| { roger_emp, jim_emp, dan_emp, sam1_emp, sam2_emp }, // roger |
| { roger_emp, jim_emp, dan_emp, sam1_emp, sam2_emp, |
| don_emp, monica_emp, lily1_emp, lily2_emp }, // guy |
| }, |
| { // K51 |
| { ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp }, // ashok |
| { ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp, |
| hamid_emp, guy_emp }, // john |
| { ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp, |
| truong_emp, larry1_emp, larry2_emp, bobbie_emp }, // hamid |
| { ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp, |
| roger_emp }, // robin |
| { ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp, |
| jim_emp, dan_emp, sam1_emp, sam2_emp }, // roger |
| { ashok_emp, john_emp, robin_emp, joe1_emp, joe2_emp, |
| don_emp, monica_emp, lily1_emp, lily2_emp } // guy |
| } |
| }; |
| |
| for (int d = 0; d < dept.length; ++d) { |
| tst.setObject(1,dept[d][1]); |
| for (int m = 0; m < mgrs.length; ++m) { |
| tst.setString(2,mgrs[m]); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("?="+dept[d][1]+" ?="+mgrs[m], |
| expected[d][m], rs); |
| |
| // Re-execution of tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("R?="+dept[d][1]+" ?="+mgrs[m], |
| expected[d][m], rs); |
| } |
| } |
| tst.close(); |
| } |
| |
| |
| // Fixtures for binder ResultSets |
| /** |
| * Test OnceResultSet |
| */ |
| public void testOnceResultSet() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| // ScrollInsensitiveResultSet, RowResultSet, UnionResultSet, |
| // SortResultSet, OnceResultSet, BulkTableScanResultSet, |
| // ScrollInsensitiveResultSet |
| PreparedStatement tst1 = prepareStatement |
| ("select * from emp where c0 = (values (1+?) union values (1+?))"); |
| |
| for (int i = 0; i < emp.length; ++i) { |
| tst1.setInt(1,i); |
| tst1.setInt(2,i); |
| ResultSet rs = tst1.executeQuery(); |
| assertResultSet("i="+i, new Object[][] { |
| emp[i] |
| }, rs); |
| // Re-execute tst with the same parameters |
| rs = tst1.executeQuery(); |
| assertResultSet("Ri="+i, new Object[][] { |
| emp[i] |
| }, rs); |
| } |
| tst1.close(); |
| |
| // TableScanResultSet, ProjectRestrictResultSet, SortResultSet, |
| // SetOpResultSet, OnceResultSet, IndexRowToBaseRowResultSet, |
| // ScrollInsensitiveResultSet |
| PreparedStatement tst2 = prepareStatement |
| ("select * from emp where name = "+ |
| "(select name from emp where c0 <= ? intersect "+ |
| "select name from emp where c0 >= ?)"); |
| for (int i = 0; i < emp.length; ++i) { |
| tst2.setInt(1,i+1); |
| tst2.setInt(2,i+1); |
| ResultSet rs = tst2.executeQuery(); |
| assertResultSet("i="+i, new Object[][] { |
| emp[i] |
| }, rs); |
| // Re-execute tst with the same parameters |
| rs = tst2.executeQuery(); |
| assertResultSet("Ri="+i, new Object[][] { |
| emp[i] |
| }, rs); |
| } |
| tst2.close(); |
| } |
| |
| /** |
| * Test AnyResultSet |
| */ |
| public void testAnyResultSet() throws Exception { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| |
| PreparedStatement tst = prepareStatement |
| ("select * from ( values 'EXISTED' ) as T(result) where exists "+ |
| "((select name from emp where c0 <= ?) intersect "+ |
| "(select name from emp where c0 >= ?))"); |
| |
| Object [][] existed = {{ "EXISTED" }}; |
| Object [][] empty = {}; |
| for (int i = 0; i < emp.length; ++i) { |
| tst.setInt(1,i+1); |
| tst.setInt(2,i+1); |
| ResultSet rs = tst.executeQuery(); |
| assertResultSet("?="+(i+1)+" ?="+(i+1), existed, rs); |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("R?="+(i+1)+" ?="+(i+1), existed, rs); |
| |
| // Make the sets are disjunct (DERBY-2370) |
| tst.setInt(1,i); |
| rs = tst.executeQuery(); |
| assertResultSet("?="+i+" ?="+(i+1), empty, rs); |
| |
| // Re-execute tst with the same parameters |
| rs = tst.executeQuery(); |
| assertResultSet("R?="+i+" ?="+(i+1), empty, rs); |
| } |
| tst.close(); |
| } |
| |
| |
| // Regression tests for DERBY-3343 (regression from the fix for DERBY-827) |
| /** |
| * Private helper method. Runs the same test for different |
| * generated identity columns. |
| * @param dataType SMALLINT, INT, or BIGINT |
| * @param generatedType BY DEFAULT or ALWAYS |
| * @throws Exception all errors passed on to JUnit |
| */ |
| private void testGeneratedIdentity(String dataType, String generatedType) |
| throws Exception { |
| Statement s = createStatement(); |
| s.execute("CREATE TABLE T(GI "+dataType+" PRIMARY KEY GENERATED "+ |
| generatedType+ |
| " AS IDENTITY (START WITH 5, INCREMENT BY 10), "+ |
| "L VARCHAR(8))"); |
| PreparedStatement implicit = |
| prepareStatement("INSERT INTO T(L) VALUES('implicit')"); |
| implicit.executeUpdate(); |
| implicit.executeUpdate(); |
| implicit.executeUpdate(); |
| |
| PreparedStatement explicit = |
| prepareStatement("INSERT INTO T(GI, L) "+ |
| "VALUES(DEFAULT, 'explicit')"); |
| explicit.executeUpdate(); |
| explicit.executeUpdate(); |
| explicit.executeUpdate(); |
| } |
| public void testIntGeneratedByDefaultAsIdentity() throws Exception { |
| testGeneratedIdentity("INT","BY DEFAULT"); |
| } |
| public void testSmallintGeneratedByDefaultAsIdentity() throws Exception { |
| testGeneratedIdentity("SMALLINT","BY DEFAULT"); |
| } |
| public void testBigintGeneratedByDefaultAsIdentity() throws Exception { |
| testGeneratedIdentity("BIGINT","BY DEFAULT"); |
| } |
| |
| public void testIntGeneratedAlwaysAsIdentity() throws Exception { |
| testGeneratedIdentity("INT","ALWAYS"); |
| } |
| public void testSmallintGeneratedAlwaysAsIdentity() throws Exception { |
| testGeneratedIdentity("SMALLINT","ALWAYS"); |
| } |
| public void testBigintGeneratedAlwaysAsIdentity() throws Exception { |
| testGeneratedIdentity("BIGINT","ALWAYS"); |
| } |
| |
| /** |
| * Tests that the {@code maxRows} setting takes effect, data is obtained |
| * from a table select. |
| */ |
| public void testSetMaxRowsTable() |
| throws SQLException { |
| createTestTable("emp", ES+","+DNO+")", "emp_data"); |
| PreparedStatement ps = prepareStatement("select * from emp_data", |
| ResultSet.TYPE_SCROLL_INSENSITIVE, |
| ResultSet.CONCUR_READ_ONLY); |
| // Just make sure we have enough rows in the result set first. |
| // Execute without explicitly specifying maxRows. |
| assertTrue(JDBC.assertDrainResults(ps.executeQuery()) >= 20); |
| |
| // Specify maxRows |
| ps.setMaxRows(5); |
| JDBC.assertDrainResults(ps.executeQuery(), 5); |
| ps.setMaxRows(20); |
| JDBC.assertDrainResults(ps.executeQuery(), 20); |
| } |
| |
| /** |
| * Tests that the {@code maxRows} setting takes effect, data is obtained |
| * from a value clause. |
| */ |
| public void testSetMaxRowsValues() |
| throws SQLException { |
| PreparedStatement ps = prepareStatement("values 0,1,2,3,4,5,6,7,8,9", |
| ResultSet.TYPE_SCROLL_INSENSITIVE, |
| ResultSet.CONCUR_READ_ONLY); |
| ps.setMaxRows(10); |
| JDBC.assertDrainResults(ps.executeQuery(), 10); |
| ps.setMaxRows(2); |
| JDBC.assertDrainResults(ps.executeQuery(), 2); |
| } |
| |
| // Regression tests for DERBY-4204 (regression from DERBY-827) |
| /** |
| * Private helper method that prepares and executes an SQL statement |
| * multiple times and checks that the runtime statistics for the correct |
| * statement is collected. |
| * |
| * @param sql the SQL text to prepare and execute |
| */ |
| private void testRuntimeStatistics(String sql, String schema) |
| throws SQLException |
| { |
| Statement s = createStatement(); |
| s.execute("call syscs_util.syscs_set_runtimestatistics(1)"); |
| if (schema != null) |
| s.execute("call syscs_util.syscs_set_xplain_schema('"+ |
| schema.toUpperCase()+"')"); |
| PreparedStatement ps = prepareStatement(sql); |
| for (int i = 0; i < 5; i++) { |
| ps.execute(); |
| while (true) { |
| if (ps.getMoreResults()) { |
| JDBC.assertDrainResults(ps.getResultSet()); |
| } else if (ps.getUpdateCount() == -1) { |
| // No result set and no update count means no more results |
| break; |
| } |
| } |
| RuntimeStatisticsParser rtsp = |
| SQLUtilities.getRuntimeStatisticsParser(s); |
| // Before DERBY-4204 the assert below would fail for some kinds |
| // of statements because the statistics for the previous call to |
| // SYSCS_GET_RUNTIMESTATISTICS() would be returned instead of the |
| // statistics for the previously executed statement. |
| assertTrue("Wrong statement", rtsp.findString(sql, 1)); |
| } |
| if (schema != null) |
| { |
| // Before DERBY-4204, we would only get a single row for some |
| // kinds of statements, because the statistics weren't re-captured. |
| // So verify that we get 5 distinct rows in SYSXPLAIN_STATEMENTS |
| // |
| s.execute("call syscs_util.syscs_set_xplain_schema('')"); |
| PreparedStatement psStatsQ = prepareStatement( |
| "select count(*) from "+schema+".sysxplain_statements" + |
| " where stmt_text = ?"); |
| psStatsQ.setString(1, sql); |
| JDBC.assertSingleValueResultSet(psStatsQ.executeQuery(), "5"); |
| } |
| } |
| |
| /** |
| * Test that runtime statistics are collected on re-execution of a |
| * SELECT statement. |
| */ |
| public void testRuntimeStatisticsForSelect() throws SQLException { |
| createTestTable("dept", DS, "dept_data"); |
| testRuntimeStatistics("select * from dept", "select_stats"); |
| } |
| |
| /** |
| * Test that runtime statistics are collected on re-execution of an |
| * UPDATE statement. |
| */ |
| public void testRuntimeStatisticsForUpdate() throws SQLException { |
| createTestTable("dept", DS, "dept_data"); |
| testRuntimeStatistics("update dept set dname = upper(dname)", |
| "update_stats"); |
| } |
| |
| /** |
| * Test that runtime statistics are collected on re-execution of an |
| * INSERT statement. |
| */ |
| public void testRuntimeStatisticsForInsert() throws SQLException { |
| createTestTable("dept", DS, "dept_data"); |
| testRuntimeStatistics("insert into dept select * from dept where 1<>1", |
| "insert_stats"); |
| } |
| |
| /** |
| * Test that runtime statistics are collected on re-execution of a |
| * DELETE statement. |
| */ |
| public void testRuntimeStatisticsForDelete() throws SQLException { |
| createTestTable("dept", DS, "dept_data"); |
| testRuntimeStatistics("delete from dept", "delete_stats"); |
| } |
| |
| /** |
| * Test that runtime statistics are collected on re-execution of a |
| * VALUES statement. |
| */ |
| public void testRuntimeStatisticsForValues() throws SQLException { |
| testRuntimeStatistics("values (1, 2, 3, 'this is a test')", |
| "values_stats"); |
| } |
| |
| /** |
| * Test that runtime statistics are collected on re-execution of a |
| * CALL statement. |
| */ |
| public void testRuntimeStatisticsForCall() throws SQLException { |
| createTestTable("dept", DS, "dept_data"); |
| testRuntimeStatistics( |
| "call syscs_util.syscs_compress_table(" + |
| "current schema, 'DEPT', 1)", |
| null); // XPLAIN doesn't work for CALL statements currently. |
| } |
| |
| |
| public void testDerby4330_JoinResultSet() throws SQLException { |
| setTimeout(1); |
| setSchema("APP"); |
| createDerby4330_join_tables(); |
| |
| PreparedStatement ps = prepareStatement( |
| "SELECT CS.REVISION, A.NAME, CS.TIME, CS.MESSAGE, F.PATH " + |
| "FROM " + |
| "CHANGESETS CS, FILECHANGES FC, " + |
| " REPOSITORIES R, FILES F, AUTHORS A " + |
| "WHERE " + |
| "F.REPOSITORY = R.ID AND A.REPOSITORY = R.ID AND " + |
| "CS.REPOSITORY = R.ID AND CS.ID = FC.CHANGESET AND " + |
| "F.ID = FC.FILE AND A.ID = CS.AUTHOR AND " + |
| "EXISTS ( " + |
| "SELECT 1 " + |
| "FROM FILES F2 " + |
| "WHERE " + |
| "F2.ID = FC.FILE AND F2.REPOSITORY = R.ID) " + |
| "ORDER BY CS.ID DESC"); |
| |
| c3 = openDefaultConnection(); |
| c3.setAutoCommit(false); |
| Statement stm2 = c3.createStatement(); |
| stm2.execute("LOCK TABLE FILECHANGES IN EXCLUSIVE MODE"); |
| stm2.close(); |
| |
| try { |
| ps.executeQuery(); |
| fail(); |
| } catch (SQLException e) { |
| assertSQLState("Expected timeout", "40XL1", e); |
| } |
| |
| c3.rollback(); |
| c3.close(); |
| |
| ResultSet rs = ps.executeQuery(); |
| assertTrue(rs.next()); |
| assertEquals(rs.getString(2), "xyz"); // name |
| assertFalse(rs.next()); |
| ps.close(); |
| |
| } |
| |
| |
| public void testDerby4330_UnionResultSet() throws SQLException { |
| setTimeout(1); |
| setSchema("APP"); |
| createDerby4330_union_tables(); |
| |
| PreparedStatement ps = prepareStatement( |
| "SELECT * FROM (" + |
| "SELECT * FROM FILECHANGES_2 UNION " + |
| "SELECT * FROM FILECHANGES) X"); // locked file last |
| |
| PreparedStatement ps_inverse = prepareStatement( |
| "SELECT * FROM (" + |
| "SELECT * FROM FILECHANGES UNION " + // locked file first |
| "SELECT * FROM FILECHANGES_2) X"); |
| |
| c3 = openDefaultConnection(); |
| c3.setAutoCommit(false); |
| Statement stm2 = c3.createStatement(); |
| stm2.execute("LOCK TABLE FILECHANGES IN EXCLUSIVE MODE"); |
| stm2.close(); |
| |
| try { |
| ps.executeQuery(); |
| fail(); |
| } catch (SQLException e) { |
| assertSQLState("Expected timeout", "40XL1", e); |
| } |
| |
| try { |
| ps_inverse.executeQuery(); |
| fail(); |
| } catch (SQLException e) { |
| assertSQLState("Expected timeout", "40XL1", e); |
| } |
| |
| c3.rollback(); |
| c3.close(); |
| |
| ResultSet rs = ps.executeQuery(); |
| JDBC.assertFullResultSet(rs, new String[][]{{"1", "1", "1"}}); |
| |
| rs = ps_inverse.executeQuery(); |
| JDBC.assertFullResultSet(rs, new String[][]{{"1", "1", "1"}}); |
| |
| ps.close(); |
| ps_inverse.close(); |
| |
| } |
| |
| |
| public void testDerby4330_SetOpResultSet() throws SQLException { |
| setTimeout(1); |
| setSchema("APP"); |
| createDerby4330_union_tables(); |
| |
| String[] ops = {"EXCEPT", "INTERSECT"}; |
| String[][][] opExpectedRs = {null, {{"1", "1", "1"}}}; |
| |
| for (int i=0; i < 2; i++) { |
| PreparedStatement ps = prepareStatement( |
| "SELECT * FROM (" + |
| "SELECT * FROM FILECHANGES_2 " + ops[i] + " " + |
| // locked file last |
| "SELECT * FROM FILECHANGES) X ORDER BY ID"); |
| |
| PreparedStatement ps_inverse = prepareStatement( |
| "SELECT * FROM (" + |
| // locked file first: |
| "SELECT * FROM FILECHANGES " + ops[i] + " " + |
| "SELECT * FROM FILECHANGES_2) X ORDER BY ID"); |
| |
| c3 = openDefaultConnection(); |
| c3.setAutoCommit(false); |
| Statement stm2 = c3.createStatement(); |
| stm2.execute("LOCK TABLE FILECHANGES IN EXCLUSIVE MODE"); |
| stm2.close(); |
| |
| try { |
| ps.executeQuery(); |
| fail(); |
| } catch (SQLException e) { |
| assertSQLState("Expected timeout", "40XL1", e); |
| } |
| |
| try { |
| ps_inverse.executeQuery(); |
| fail(); |
| } catch (SQLException e) { |
| assertSQLState("Expected timeout", "40XL1", e); |
| } |
| |
| c3.rollback(); |
| c3.close(); |
| |
| ResultSet rs = ps.executeQuery(); |
| |
| if (opExpectedRs[i] != null) { |
| JDBC.assertFullResultSet(rs, opExpectedRs[i]); |
| } else { |
| JDBC.assertEmpty(rs); |
| } |
| |
| rs = ps_inverse.executeQuery(); |
| |
| if (opExpectedRs[i] != null) { |
| JDBC.assertFullResultSet(rs, opExpectedRs[i]); |
| } else { |
| JDBC.assertEmpty(rs); |
| } |
| |
| ps.close(); |
| ps_inverse.close(); |
| |
| } |
| |
| } |
| |
| |
| public void testDerby4330_GroupedAggregateResultSet() throws SQLException { |
| setTimeout(1); |
| setSchema("APP"); |
| createDerby4330_union_tables(); |
| |
| PreparedStatement ps = prepareStatement( |
| "SELECT SUM(CHANGESET) from FILECHANGES GROUP BY FILE"); |
| |
| c3 = openDefaultConnection(); |
| c3.setAutoCommit(false); |
| Statement stm2 = c3.createStatement(); |
| // Next statement gives an exclusive write lock on a row in FILECHANGES: |
| stm2.execute("INSERT INTO FILECHANGES(FILE,CHANGESET) VALUES (2,2)"); |
| stm2.close(); |
| |
| try { |
| ps.executeQuery(); |
| fail(); |
| } catch (SQLException e) { |
| assertSQLState("Expected timeout", "40XL1", e); |
| } |
| |
| c3.rollback(); |
| c3.close(); |
| |
| ResultSet rs = ps.executeQuery(); |
| JDBC.assertFullResultSet(rs, new String[][]{{"1"}}); |
| |
| ps.close(); |
| } |
| |
| |
| public void testDerby4330_DistinctGroupedAggregateResultSet() |
| throws SQLException |
| { |
| setTimeout(1); |
| setSchema("APP"); |
| createDerby4330_union_tables(); |
| |
| PreparedStatement ps = prepareStatement( |
| "SELECT SUM(DISTINCT CHANGESET) from FILECHANGES GROUP BY FILE"); |
| |
| c3 = openDefaultConnection(); |
| c3.setAutoCommit(false); |
| Statement stm2 = c3.createStatement(); |
| // Next statement gives an exclusive write lock on a row in FILECHANGES: |
| stm2.execute("INSERT INTO FILECHANGES(FILE,CHANGESET) VALUES (2,2)"); |
| stm2.close(); |
| |
| try { |
| ps.executeQuery(); |
| fail(); |
| } catch (SQLException e) { |
| assertSQLState("Expected timeout", "40XL1", e); |
| } |
| |
| c3.rollback(); |
| c3.close(); |
| |
| ResultSet rs = ps.executeQuery(); |
| JDBC.assertFullResultSet(rs, new String[][]{{"1"}}); |
| |
| ps.close(); |
| } |
| |
| |
| public void testDerby4330_DistinctScalarAggregateResultSet() |
| throws SQLException |
| { |
| setTimeout(1); |
| setSchema("APP"); |
| createDerby4330_union_tables(); |
| |
| PreparedStatement ps = prepareStatement( |
| "SELECT SUM(DISTINCT CHANGESET) from FILECHANGES"); |
| |
| c3 = openDefaultConnection(); |
| c3.setAutoCommit(false); |
| Statement stm2 = c3.createStatement(); |
| // Next statement gives an exclusive write lock on a row in FILECHANGES: |
| stm2.execute("INSERT INTO FILECHANGES(FILE,CHANGESET) VALUES (2,2)"); |
| stm2.close(); |
| |
| try { |
| ps.executeQuery(); |
| fail(); |
| } catch (SQLException e) { |
| assertSQLState("Expected timeout", "40XL1", e); |
| } |
| |
| c3.rollback(); |
| c3.close(); |
| |
| ResultSet rs = ps.executeQuery(); |
| JDBC.assertFullResultSet(rs, new String[][]{{"1"}}); |
| |
| ps.close(); |
| } |
| |
| |
| private void setTimeout(long t) throws SQLException { |
| Statement stm = createStatement(); |
| stm.execute("call syscs_util.syscs_set_database_property(" + |
| "'derby.locks.waitTimeout', '" + t + "')"); |
| stm.close(); |
| } |
| |
| |
| private void createDerby4330_join_tables() throws SQLException { |
| Statement stm = createStatement(); |
| stm.execute( |
| "CREATE TABLE REPOSITORIES (" + |
| "ID INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY," + |
| "PATH VARCHAR(32672) UNIQUE NOT NULL)"); |
| |
| stm.execute( |
| "INSERT INTO REPOSITORIES(PATH) VALUES ('r')"); |
| |
| stm.execute( |
| "CREATE TABLE FILES (" + |
| "ID INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY," + |
| "PATH VARCHAR(32672) NOT NULL," + |
| "REPOSITORY INT NOT NULL REFERENCES REPOSITORIES" + |
| " ON DELETE CASCADE," + |
| "UNIQUE (REPOSITORY, PATH))"); |
| |
| stm.execute( |
| "INSERT INTO FILES(PATH, REPOSITORY) VALUES ('/adsf',1)"); |
| |
| stm.execute( |
| "CREATE TABLE AUTHORS (" + |
| "ID INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY," + |
| "REPOSITORY INT NOT NULL REFERENCES REPOSITORIES " + |
| " ON DELETE CASCADE," + |
| "NAME VARCHAR(32672) NOT NULL," + |
| "UNIQUE (REPOSITORY, NAME))"); |
| |
| stm.execute( |
| "INSERT INTO AUTHORS(REPOSITORY, NAME) VALUES (1, 'xyz')"); |
| |
| stm.execute( |
| "CREATE TABLE CHANGESETS (" + |
| "ID INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY," + |
| "REPOSITORY INT NOT NULL REFERENCES REPOSITORIES " + |
| " ON DELETE CASCADE," + |
| "REVISION VARCHAR(1024) NOT NULL," + |
| "AUTHOR INT NOT NULL REFERENCES AUTHORS ON DELETE CASCADE," + |
| "TIME TIMESTAMP NOT NULL," + |
| "MESSAGE VARCHAR(32672) NOT NULL," + |
| "UNIQUE (REPOSITORY, REVISION))"); |
| |
| stm.execute( |
| "INSERT INTO CHANGESETS(REPOSITORY, REVISION, " + |
| " AUTHOR, TIME, MESSAGE)" + |
| " VALUES (1,'',1,CURRENT_TIMESTAMP,'')"); |
| |
| stm.execute( |
| "CREATE TABLE FILECHANGES (" + |
| "ID INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY," + |
| "FILE INT NOT NULL REFERENCES FILES ON DELETE CASCADE," + |
| "CHANGESET INT NOT NULL REFERENCES CHANGESETS ON DELETE CASCADE," + |
| "UNIQUE (FILE, CHANGESET))"); |
| |
| stm.execute("INSERT INTO FILECHANGES(FILE,CHANGESET) VALUES (1,1)"); |
| stm.close(); |
| commit(); |
| } |
| |
| |
| private void createDerby4330_union_tables() throws SQLException { |
| Statement stm = createStatement(); |
| stm.execute("CREATE TABLE FILECHANGES (" + |
| "ID INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY," + |
| "FILE INT NOT NULL," + |
| "CHANGESET INT NOT NULL," + |
| "UNIQUE (FILE, CHANGESET))"); |
| |
| stm.execute("CREATE TABLE FILECHANGES_2 (" + |
| "ID INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY," + |
| "FILE INT NOT NULL," + |
| "CHANGESET INT NOT NULL," + |
| "UNIQUE (FILE, CHANGESET))"); |
| |
| stm.execute("INSERT INTO FILECHANGES(FILE,CHANGESET) VALUES (1,1)"); |
| stm.execute("INSERT INTO FILECHANGES_2(FILE,CHANGESET) VALUES (1,1)"); |
| stm.close(); |
| commit(); |
| } |
| |
| |
| private void setSchema(String schema) throws SQLException { |
| Statement stm = createStatement(); |
| stm.execute("SET SCHEMA " + schema); |
| stm.close(); |
| } |
| |
| /** |
| * Test case for DERBY-4488, where the third execution of a statement |
| * that attempted to insert a NULL into a non-nullable column failed with |
| * a NullPointerException. |
| */ |
| public void testInsertNullIntoNonNullableColumn() throws SQLException { |
| setAutoCommit(false); |
| |
| Statement s = createStatement(); |
| s.execute("create table d4488_t1 (pk int primary key)"); |
| s.execute("insert into d4488_t1 values 1"); |
| s.execute("create table d4488_t2 (c1 int, c2 int not null)"); |
| commit(); |
| |
| PreparedStatement ps = prepareStatement( |
| "insert into d4488_t2(c1) select 1 from d4488_t1"); |
| for (int i = 0; i < 5; i++) { |
| // Expect this to fail, but not with NullPointerException. |
| assertStatementError(SQLSTATE_NULL_INTO_NON_NULL, ps); |
| // Need a rollback here in order to close the index scan on |
| // D4488_T1, otherwise the NPE won't reproduce. Alternatively, |
| // run with auto-commit enabled. |
| rollback(); |
| } |
| } |
| } |