You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by da...@apache.org on 2009/08/14 21:12:47 UTC
svn commit: r804327 - in /db/derby/code/branches/10.4/java:
engine/org/apache/derby/impl/sql/execute/
testing/org/apache/derbyTesting/functionTests/tests/lang/
Author: dag
Date: Fri Aug 14 19:12:46 2009
New Revision: 804327
URL: http://svn.apache.org/viewvc?rev=804327&view=rev
Log:
DERBY-4330 NullPointerException or assert failure when re-executing PreparedStatement after lock timeout
Backported fix from trunk as:
svn merge -c 804271 https://svn.apache.org/repos/asf/db/derby/code/trunk
Patch derby-4330c fixes this issue. The problem is that when a timeout
happens (or a deadlock), the result set tree for prepared statements
for some queries is partically in a closed, partially in an open
state. (The issue was reported for a join query, but exists for others
queries as well). This causes problems when the result set tree is
being reused, i.e. when the prpared statement is attempted re-executed
after the timeout, since the tree is expected to be fully closed at
that time, cuasing the assert or NPE.
The fix ensures that the tree is left in a fully closed state in such
cases.
Modified:
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/DistinctScalarAggregateResultSet.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/GroupedAggregateResultSet.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/JoinResultSet.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/SetOpResultSet.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/SortResultSet.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/UnionResultSet.java
db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ResultSetsFromPreparedStatementTest.java
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/DistinctScalarAggregateResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/DistinctScalarAggregateResultSet.java?rev=804327&r1=804326&r2=804327&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/DistinctScalarAggregateResultSet.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/DistinctScalarAggregateResultSet.java Fri Aug 14 19:12:46 2009
@@ -138,10 +138,20 @@
source.openCore();
- /*
- ** Load up the sorter because we have something to sort.
- */
- scanController = loadSorter();
+ try {
+ /*
+ ** Load up the sorter because we have something to sort.
+ */
+ scanController = loadSorter();
+ } catch (StandardException e) {
+ // DERBY-4330 Result set tree must be atomically open or
+ // closed for reuse to work (after DERBY-827).
+
+ isOpen = true; // to make close do its thing:
+ try { close(); } catch (StandardException ee) {}
+ throw e;
+ }
+
sorted = true;
isOpen = true;
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/GroupedAggregateResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/GroupedAggregateResultSet.java?rev=804327&r1=804326&r2=804327&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/GroupedAggregateResultSet.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/GroupedAggregateResultSet.java Fri Aug 14 19:12:46 2009
@@ -158,26 +158,35 @@
source.openCore();
- /* If this is an in-order group by then we do not need the sorter.
- * (We can do the aggregation ourselves.)
- * We save a clone of the first row so that subsequent next()s
- * do not overwrite the saved row.
- */
- if (isInSortedOrder)
- {
- currSortedRow = getNextRowFromRS();
- if (currSortedRow != null)
+ try {
+ /* If this is an in-order group by then we do not need the sorter.
+ * (We can do the aggregation ourselves.)
+ * We save a clone of the first row so that subsequent next()s
+ * do not overwrite the saved row.
+ */
+ if (isInSortedOrder)
{
- currSortedRow = (ExecIndexRow) currSortedRow.getClone();
- initializeVectorAggregation(currSortedRow);
+ currSortedRow = getNextRowFromRS();
+ if (currSortedRow != null)
+ {
+ currSortedRow = (ExecIndexRow) currSortedRow.getClone();
+ initializeVectorAggregation(currSortedRow);
+ }
}
- }
- else
- {
- /*
- ** Load up the sorter
- */
- scanController = loadSorter();
+ else
+ {
+ /*
+ ** Load up the sorter
+ */
+ scanController = loadSorter();
+ }
+ } catch (StandardException e) {
+ // DERBY-4330 Result set tree must be atomically open or
+ // closed for reuse to work (after DERBY-827).
+
+ isOpen = true; // to make close do its thing:
+ try { close(); } catch (StandardException ee) {}
+ throw e;
}
isOpen = true;
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/JoinResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/JoinResultSet.java?rev=804327&r1=804326&r2=804327&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/JoinResultSet.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/JoinResultSet.java Fri Aug 14 19:12:46 2009
@@ -143,14 +143,25 @@
if (SanityManager.DEBUG)
SanityManager.ASSERT( ! isOpen, "JoinResultSet already open");
- isOpen = true;
leftResultSet.openCore();
- leftRow = leftResultSet.getNextRowCore();
- if (leftRow != null)
- {
- openRight();
- rowsSeenLeft++;
+
+ try {
+ leftRow = leftResultSet.getNextRowCore();
+ if (leftRow != null)
+ {
+ openRight();
+ rowsSeenLeft++;
+ }
+ } catch (StandardException e) {
+ // DERBY-4330 Result set tree must be atomically open or
+ // closed for reuse to work (after DERBY-827).
+
+ isOpen = true; // to make close work:
+ try { close(); } catch (StandardException ee) {}
+ throw e;
}
+
+ isOpen = true;
numOpens++;
openTime += getElapsedMillis(beginTime);
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/SetOpResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/SetOpResultSet.java?rev=804327&r1=804326&r2=804327&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/SetOpResultSet.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/SetOpResultSet.java Fri Aug 14 19:12:46 2009
@@ -108,15 +108,25 @@
if (SanityManager.DEBUG)
SanityManager.ASSERT( ! isOpen, "SetOpResultSet already open");
- isOpen = true;
leftSource.openCore();
- rightSource.openCore();
- rightInputRow = rightSource.getNextRowCore();
+
+ try {
+ rightSource.openCore();
+ rightInputRow = rightSource.getNextRowCore();
+ } catch (StandardException e) {
+ // DERBY-4330 Result set tree must be atomically open or
+ // closed for reuse to work (after DERBY-827).
+ isOpen = true; // to make close work:
+ try { close(); } catch (StandardException ee) {}
+ throw e;
+ }
+
if (rightInputRow != null)
{
rowsSeenRight++;
}
+ isOpen = true;
numOpens++;
openTime += getElapsedMillis(beginTime);
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/SortResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/SortResultSet.java?rev=804327&r1=804326&r2=804327&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/SortResultSet.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/SortResultSet.java Fri Aug 14 19:12:46 2009
@@ -247,26 +247,35 @@
source.openCore();
- /* If this is an in-order distinct then we do not need the sorter.
- * (We filter out the duplicate rows ourselves.)
- * We save a clone of the first row so that subsequent next()s
- * do not overwrite the saved row.
- */
- if (isInSortedOrder && distinct)
- {
- currSortedRow = getNextRowFromRS();
- if (currSortedRow != null)
+ try {
+ /* If this is an in-order distinct then we do not need the sorter.
+ * (We filter out the duplicate rows ourselves.) We save a clone
+ * of the first row so that subsequent next()s do not overwrite the
+ * saved row.
+ */
+ if (isInSortedOrder && distinct)
+ {
+ currSortedRow = getNextRowFromRS();
+
+ if (currSortedRow != null)
+ {
+ currSortedRow = (ExecRow) currSortedRow.getClone();
+ }
+ }
+ else
{
- currSortedRow = (ExecRow) currSortedRow.getClone();
+ /*
+ ** Load up the sorter.
+ */
+ scanController = loadSorter();
+ sorted = true;
}
- }
- else
- {
- /*
- ** Load up the sorter.
- */
- scanController = loadSorter();
- sorted = true;
+ } catch (StandardException e) {
+ // DERBY-4330 Result set tree must be atomically open or
+ // closed for reuse to work (after DERBY-827).
+ isOpen = true; // to make close do its thing:
+ try { close(); } catch (StandardException ee) {}
+ throw e;
}
isOpen = true;
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/UnionResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/UnionResultSet.java?rev=804327&r1=804326&r2=804327&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/UnionResultSet.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/sql/execute/UnionResultSet.java Fri Aug 14 19:12:46 2009
@@ -99,8 +99,8 @@
if (SanityManager.DEBUG)
SanityManager.ASSERT( ! isOpen, "UnionResultSet already open");
- isOpen = true;
source1.openCore();
+ isOpen = true;
numOpens++;
openTime += getElapsedMillis(beginTime);
Modified: db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ResultSetsFromPreparedStatementTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ResultSetsFromPreparedStatementTest.java?rev=804327&r1=804326&r2=804327&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ResultSetsFromPreparedStatementTest.java (original)
+++ db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ResultSetsFromPreparedStatementTest.java Fri Aug 14 19:12:46 2009
@@ -167,6 +167,10 @@
/** 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;
/**
* Creates a String containing an insert statement for the
@@ -452,6 +456,31 @@
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) {
+ }
+
+ 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();
@@ -2132,4 +2161,364 @@
ps.setMaxRows(2);
JDBC.assertDrainResults(ps.executeQuery(), 2);
}
+
+ 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();
+ }
}