blob: 3f049da2234f5cc459aa9f3684ebcbf856f3307a [file] [log] [blame]
/**
* Derby - Class org.apache.derbyTesting.functionTests.tests.jdbapi.XATest
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.derbyTesting.functionTests.tests.jdbcapi;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import javax.sql.XAConnection;
import javax.sql.XADataSource;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import static junit.framework.Assert.fail;
import junit.framework.Test;
import org.apache.derby.shared.common.reference.SQLState;
import org.apache.derbyTesting.functionTests.util.DeadlockWatchdog;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
import static org.apache.derbyTesting.junit.BaseJDBCTestCase.assertSQLState;
import org.apache.derbyTesting.junit.BaseTestSuite;
import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
import org.apache.derbyTesting.junit.DatabasePropertyTestSetup;
import org.apache.derbyTesting.junit.J2EEDataSource;
import org.apache.derbyTesting.junit.JDBC;
import org.apache.derbyTesting.junit.SecurityManagerSetup;
import org.apache.derbyTesting.junit.TestConfiguration;
import org.apache.derbyTesting.junit.Utilities;
import org.apache.derbyTesting.junit.XATestUtil;
public class XATest extends BaseJDBCTestCase {
//create own policy file
private static final String POLICY_FILE_NAME =
"org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.policy";
public static final String LOCKTIMEOUT="40XL1";
public XATest(String name) {
super(name);
}
/**
* A single connection and 1 phase commit.
*
*
* Original "SQL" from xaSimplePositive.sql <code>
xa_connect ;
xa_start xa_noflags 0;
xa_getconnection;
drop table foo;
create table foo (a int);
insert into foo values (0);
select * from foo;
run resource '/org/apache/derbyTesting/functionTests/tests/store/global_xactTable.view';
select * from global_xactTable where gxid is not null order by gxid;
xa_end xa_success 0;
xa_commit xa_1phase 0;
xa_datasource 'wombat' shutdown;
</code>
*
* @throws SQLException
* @throws XAException
* @throws XAException
*/
public void testSingleConnectionOnePhaseCommit() throws SQLException,
XAException {
XADataSource xads = J2EEDataSource.getXADataSource();
J2EEDataSource.setBeanProperty(xads, "databaseName", "wombat");
XAConnection xac = xads.getXAConnection();
XAResource xar = xac.getXAResource();
Xid xid = XATestUtil.getXid(0, 32, 46);
xar.start(xid, XAResource.TMNOFLAGS);
Connection conn = xac.getConnection();
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, conn.getHoldability());
Statement s = conn.createStatement();
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, s
.getResultSetHoldability());
s.execute("create table foo (a int)");
s.executeUpdate("insert into foo values (0)");
ResultSet rs = s.executeQuery("select * from foo");
JDBC.assertDrainResults(rs, 1);
String[][] expectedRows = { { "(0", "ACTIVE", "false", "APP",
"UserTransaction" } };
XATestUtil.checkXATransactionView(conn, expectedRows);
s.close();
xar.end(xid, XAResource.TMSUCCESS);
// 1 phase commit
xar.commit(xid, true);
conn.close();
xac.close();
}
/*
* Two interleaving transaction and prepare/commit prepare/rollback.
*
* (original test said two connections but only one connection was opened)
*
* <code> xa_datasource 'wombat'; xa_connect user 'sku' password 'testxa' ;
*
* xa_start xa_noflags 1; xa_getconnection; insert into APP.foo values (1);
* xa_end xa_suspend 1;
*
* xa_start xa_noflags 2; insert into APP.foo values (2); xa_end xa_suspend
* 2;
*
* xa_start xa_resume 1; insert into APP.foo values (3); xa_end xa_suspend
* 1;
*
* xa_start xa_resume 2; insert into APP.foo values (4); select * from
* APP.global_xactTable where gxid is not null order by gxid; -- this
* prepare won't work since transaction 1 has been suspended - XA_PROTO
* xa_prepare 1;
*
* select * from APP.global_xactTable where gxid is not null order by gxid;
* xa_end xa_success 2; -- this assumes a resume xa_end xa_success 1;
* xa_prepare 1; xa_prepare 2; -- both transactions should be prepared
* select * from APP.global_xactTable where gxid is not null order by gxid; --
* NOTE: The following call to "xa_recover xa_startrscan" is apt to --
* return the result set rows in reverse order when changes to -- the Derby
* engine affect the number of transactions that it takes -- to create a
* database. The transactions are stored in a hash table -- based on a
* global and local id, and when the number of transactions -- changes, the
* (internal) local id can change, which may lead to a -- change in the
* result set order. This order is determined by the -- JVM's hashing
* algorithm. Examples of changes to the engine that -- can affect this
* include ones that cause more commits or that -- change the amount of data
* being stored, such as changes to the -- metadata statements (which is
* what prompted this explanation in -- the first place). Ultimately, the
* problem is that there is no -- way to order the return values from
* "xa_recover" since it is an -- ij internal statement, not SQL...
* xa_recover xa_startrscan; xa_recover xa_noflags;
*
* xa_commit xa_2Phase 1; xa_rollback 2; -- check results xa_start
* xa_noflags 3; select * from APP.global_xactTable where gxid is not null
* order by gxid; select * from APP.foo; xa_end xa_success 3;
*
* xa_prepare 3; -- should fail with XA_NOTA because we prepared a read only
* transaction xa_commit xa_1Phase 3; disconnect; </code>
*/
public void testInterleavingTransactions() throws SQLException, XAException {
Statement preStatement = getConnection().createStatement();
preStatement.execute("create table fooInterleaving (a int)");
preStatement.execute("insert into fooInterleaving values (0)");
preStatement.close();
XADataSource xads = J2EEDataSource.getXADataSource();
XAConnection xac = xads.getXAConnection("sku", "testxa");
XAResource xar = xac.getXAResource();
Xid xid1 = XATestUtil.getXid(1, 93, 18);
Xid xid2 = XATestUtil.getXid(2, 45, 77);
xar.start(xid1, XAResource.TMNOFLAGS);
Connection conn = xac.getConnection();
Statement s = conn.createStatement();
s.executeUpdate("insert into APP.fooInterleaving values (1)");
xar.end(xid1, XAResource.TMSUSPEND);
xar.start(xid2, XAResource.TMNOFLAGS);
s.executeUpdate("insert into APP.fooInterleaving values (2)");
xar.end(xid2, XAResource.TMSUSPEND);
xar.start(xid1, XAResource.TMRESUME);
s.executeUpdate("insert into APP.fooInterleaving values (3)");
xar.end(xid1, XAResource.TMSUSPEND);
xar.start(xid2, XAResource.TMRESUME);
s.executeUpdate("insert into APP.fooInterleaving values (4)");
String[][] expectedRows = {
{ "(1", "ACTIVE", "false", "SKU", "UserTransaction" },
{ "(2", "ACTIVE", "false", "SKU", "UserTransaction" } };
XATestUtil.checkXATransactionView(conn, expectedRows);
// this prepare won't work since
// transaction 1 has been suspended - XA_PROTO
try {
xar.prepare(xid1);
fail("FAIL - prepare on suspended transaction");
} catch (XAException e) {
if (e.errorCode != XAException.XAER_PROTO)
XATestUtil.dumpXAException(
"FAIL - prepare on suspended transaction", e);
}
// check it was not prepared
XATestUtil.checkXATransactionView(conn, expectedRows);
xar.end(xid2, XAResource.TMSUCCESS);
xar.end(xid1, XAResource.TMSUCCESS);
xar.prepare(xid1);
xar.prepare(xid2);
// both should be prepared.
expectedRows = new String[][] {
{ "(1", "PREPARED", "false", "SKU", "UserTransaction" },
{ "(2", "PREPARED", "false", "SKU", "UserTransaction" } };
XATestUtil.checkXATransactionView(conn, expectedRows);
Xid[] recoveredStart = xar.recover(XAResource.TMSTARTRSCAN);
assertEquals(2, recoveredStart.length);
Xid[] recovered = xar.recover(XAResource.TMNOFLAGS);
assertEquals(0, recovered.length);
Xid[] recoveredEnd = xar.recover(XAResource.TMENDRSCAN);
assertEquals(0, recoveredEnd.length);
for (int i = 0; i < recoveredStart.length; i++) {
Xid xid = recoveredStart[i];
if (xid.getFormatId() == 1) {
// commit 1 with 2pc
xar.commit(xid, false);
} else if (xid.getFormatId() == 2) {
xar.rollback(xid);
} else {
fail("FAIL: unknown xact");
}
}
// check the results
Xid xid3 = XATestUtil.getXid(3, 2, 101);
xar.start(xid3, XAResource.TMNOFLAGS);
expectedRows = new String[][] { { "(3", "IDLE", "NULL", "SKU",
"UserTransaction" } };
XATestUtil.checkXATransactionView(conn, expectedRows);
ResultSet rs = s.executeQuery("select * from APP.fooInterleaving");
expectedRows = new String[][] { { "0" }, { "1" }, { "3" } };
JDBC.assertFullResultSet(rs, expectedRows);
rs.close();
xar.end(xid3, XAResource.TMSUCCESS);
int pr = xar.prepare(xid3);
if (pr != XAResource.XA_RDONLY)
fail("FAIL - prepare on read only xact returned " + pr);
try {
xar.commit(xid3, true);
fail("FAIL - 2pc commit on read-only xact");
} catch (XAException e) {
if (e.errorCode != XAException.XAER_NOTA)
throw e;
}
s.close();
conn.close();
xac.close();
}
/**
* Tests on INIT STATE (no tr Original SQL from xaStateTran.sql. <code>
-- the following should error XAER_NOTA
xa_start xa_join 11;
-- the following should error XAER_NOTA
xa_start xa_resume 11;
-- the following should error XAER_NOTA
xa_end xa_success 11;
-- the following should error XAER_NOTA
xa_end xa_fail 11;
-- the following should error XAER_NOTA
xa_end xa_suspend 11;
-- the following should error XAER_NOTA
xa_prepare 11;
-- the following should error XAER_NOTA
xa_commit xa_1phase 11;
-- the following should error XAER_NOTA
xa_commit xa_2phase 11;
-- the following should error XAER_NOTA
xa_rollback 11;
-- the following should error XAER_NOTA
xa_forget 11;
</code>
*/
public void testNoTransaction() throws SQLException, XAException {
XADataSource xads = J2EEDataSource.getXADataSource();
XAConnection xac = xads.getXAConnection();
XAResource xar = xac.getXAResource();
Xid xid11 = XATestUtil.getXid(11, 3, 128);
try {
xar.start(xid11, XAResource.TMJOIN);
} catch (XAException e) {
if (e.errorCode != XAException.XAER_NOTA)
throw e;
}
try {
xar.start(xid11, XAResource.TMRESUME);
} catch (XAException e) {
if (e.errorCode != XAException.XAER_NOTA)
throw e;
}
try {
xar.end(xid11, XAResource.TMSUCCESS);
} catch (XAException e) {
if (e.errorCode != XAException.XAER_NOTA)
throw e;
}
try {
xar.end(xid11, XAResource.TMFAIL);
} catch (XAException e) {
if (e.errorCode != XAException.XAER_NOTA)
throw e;
}
try {
xar.end(xid11, XAResource.TMSUSPEND);
} catch (XAException e) {
if (e.errorCode != XAException.XAER_NOTA)
throw e;
}
try {
xar.prepare(xid11);
} catch (XAException e) {
if (e.errorCode != XAException.XAER_NOTA)
throw e;
}
try {
xar.commit(xid11, false);
} catch (XAException e) {
if (e.errorCode != XAException.XAER_NOTA)
throw e;
}
try {
xar.commit(xid11, true);
} catch (XAException e) {
if (e.errorCode != XAException.XAER_NOTA)
throw e;
}
try {
xar.rollback(xid11);
} catch (XAException e) {
if (e.errorCode != XAException.XAER_NOTA)
throw e;
}
try {
xar.forget(xid11);
} catch (XAException e) {
if (e.errorCode != XAException.XAER_NOTA)
throw e;
}
}
/**
* Morph a connection between local anf global transactions.
*/
public void testMorph() throws SQLException, XAException {
Statement preStatement = getConnection().createStatement();
preStatement.execute("create table fooMorph (a int)");
preStatement.executeUpdate("insert into APP.fooMorph values (0)");
preStatement.executeUpdate("insert into APP.fooMorph values (1)");
preStatement.executeUpdate("insert into APP.fooMorph values (2)");
preStatement.executeUpdate("insert into APP.fooMorph values (3)");
preStatement.executeUpdate("insert into APP.fooMorph values (4)");
preStatement.close();
XADataSource xads = J2EEDataSource.getXADataSource();
XAConnection xac = xads.getXAConnection();
XAResource xar = xac.getXAResource();
Connection conn = xac.getConnection();
/*
* autocommit off; insert into foo values (1); select * from
* global_xactTable where gxid is not null order by gxid,username;
* commit;
*/
conn.setAutoCommit(false);
Statement s = conn.createStatement();
s.executeUpdate("insert into APP.fooMorph values (2001)");
// no rows expected
XATestUtil.checkXATransactionView(conn, null);
conn.commit();
/*
* autocommit on; insert into foo values (2); select * from
* global_xactTable where gxid is not null order by gxid,username;
*
*/
conn.setAutoCommit(true);
s.executeUpdate("insert into APP.fooMorph values (2002)");
XATestUtil.checkXATransactionView(conn, null);
/*
* -- morph the connection to a global transaction xa_start xa_noflags
* 1; select * from global_xactTable where gxid is not null order by
* gxid,username; insert into foo values (3);
*/
Xid xid = XATestUtil.getXid(1001, 66, 13);
xar.start(xid, XAResource.TMNOFLAGS);
String[][] expectedRows = { { "(1", "IDLE", "NULL", "APP",
"UserTransaction" } };
XATestUtil.checkXATransactionView(conn, expectedRows);
s.executeUpdate("insert into APP.fooMorph values (2003)");
/*
* -- disallowed commit; -- disallowed rollback; -- disallowed
* autocommit on; -- OK autocommit off;
*/
try {
conn.commit();
fail("FAIL: commit allowed in global xact");
} catch (SQLException e) {
}
try {
conn.rollback();
fail("FAIL: roll back allowed in global xact");
} catch (SQLException e) {
}
try {
conn.setAutoCommit(true);
fail("FAIL: setAutoCommit(true) allowed " + "in global xact");
} catch (SQLException e) {
}
try {
conn.setSavepoint();
fail("FAIL: setSavepoint() allowed in global xact");
} catch (SQLException e) {
}
try {
conn.setSavepoint("badsavepoint");
fail("FAIL: setSavepoint(String) allowed in " + "global xact");
} catch (SQLException e) {
}
conn.setAutoCommit(false);
// s was created in local mode so it has holdibilty
// set, will execute but ResultSet will have close on commit
// DERBY-1158 query with holdable statement
s.executeQuery("select * from APP.fooMorph where A >= 2000").close();
s.close();
// statement created in global xact is CLOSE_CURSORS_AT_COMMIT
s = conn.createStatement();
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, s
.getResultSetHoldability());
/*
* select * from foo; xa_end xa_success 1; xa_prepare 1;
*/
ResultSet rs = s.executeQuery("select * from APP.fooMorph where A >= 2000");
expectedRows = new String[][] { { "2001" }, { "2002" }, { "2003" } };
rs.close();
xar.end(xid, XAResource.TMSUCCESS);
xar.prepare(xid);
/*
* -- dup id xa_start xa_noflags 1;
*/
try {
xar.start(xid, XAResource.TMNOFLAGS);
fail("FAIL - start with duplicate XID");
} catch (XAException e) {
if (e.errorCode != XAException.XAER_DUPID)
throw e;
}
/*
* xa_start xa_noflags 2; -- still should disallow autommit; autocommit
* on; -- still should disallow commit and rollback commit; rollback;
* select * from global_xactTable where gxid is not null order by
* gxid,username; xa_end xa_suspend 2;
*/
Xid xid2 = XATestUtil.getXid(1002, 23, 3);
xar.start(xid2, XAResource.TMNOFLAGS);
try {
conn.commit();
fail("FAIL: commit allowed in global xact");
} catch (SQLException e) {
}
try {
conn.rollback();
fail("FAIL: roll back allowed in global xact");
} catch (SQLException e) {
}
try {
conn.setAutoCommit(true);
fail("FAIL: setAutoCommit(true) allowed in global xact");
} catch (SQLException e) {
}
conn.setAutoCommit(false);
xar.end(xid2, XAResource.TMSUSPEND);
/*
* -- get local connection again xa_getconnection;
*
* insert into foo values (5); -- autocommit should be on by default;
* commit;
*
* autocommit off; insert into foo values (6); -- commit and rollback is
* allowed on local connection rollback;
*
* insert into foo values (6); commit;
*/
conn = xac.getConnection();
s = conn.createStatement();
s.executeUpdate("insert into APP.fooMorph values (2005)");
conn.commit();
conn.setAutoCommit(false);
s.executeUpdate("insert into APP.fooMorph values (2006)");
conn.rollback();
s.executeUpdate("insert into APP.fooMorph values (2007)");
conn.commit();
expectedRows = new String[][] {
{ "(1", "PREPARED", "false", "APP", "UserTransaction" },
{ "(1", "IDLE", "NULL", "APP", "UserTransaction" } };
XATestUtil.checkXATransactionView(conn, expectedRows);
/*
* -- I am still able to commit other global transactions while I am
* attached to a -- local transaction. xa_commit xa_2phase 1; xa_end
* xa_success 2; xa_rollback 2;
*/
xar.commit(xid, false);
xar.end(xid2, XAResource.TMSUCCESS);
xar.rollback(xid2);
XATestUtil.checkXATransactionView(conn, null);
rs = s.executeQuery("select * from APP.fooMorph where A >= 2000");
expectedRows = new String[][] { { "2001" }, { "2002" }, { "2003" },
{ "2005" }, { "2007" } };
JDBC.assertFullResultSet(rs, expectedRows);
rs.close();
conn.rollback();
conn.close();
/*
* xa_getconnection; select * from global_xactTable where gxid is not
* null order by gxid,username; select * from foo; autocommit off;
* delete from foo;
*/
conn = xac.getConnection();
conn.setAutoCommit(false);
s = conn.createStatement();
s.executeUpdate("delete from app.fooMorph");
rs = s.executeQuery("select * from APP.fooMorph");
JDBC.assertEmpty(rs);
rs.close();
/*
* -- yanking a local connection away should rollback the changes
*/
conn = xac.getConnection();
conn.setAutoCommit(false);
s = conn.createStatement();
rs = s.executeQuery("select * from APP.fooMorph where A >= 2000");
expectedRows = new String[][] { { "2001" }, { "2002" }, { "2003" },
{ "2005" }, { "2007" } };
JDBC.assertFullResultSet(rs, expectedRows);
/*
* -- cannot morph it if the local transaction is not idle xa_start
* xa_noflags 3; commit; -- now morph it to a global transaction
* xa_start xa_noflags 3;
*/
Xid xid3 = XATestUtil.getXid(1003, 27, 9);
try {
xar.start(xid3, XAResource.TMNOFLAGS);
fail("FAIL XAResource.start on a global transaction with an active local transaction (autocommit false)");
} catch (XAException xae) {
if (xae.errorCode != XAException.XAER_OUTSIDE)
throw xae;
}
conn.commit();
xar.start(xid3, XAResource.TMNOFLAGS);
/*
* -- now I shouldn't be able to yank it xa_getconnection;
*/
// DERBY-341 - client skip XAConnection with active local xact
if (usingEmbedded()) {
try {
xac.getConnection();
fail("FAIL: getConnection with active global xact");
} catch (SQLException sqle) {
assertSQLState("XJ059", sqle);
}
}
/*
* select * from foo; delete from foo;
*
* xa_end xa_fail 3; xa_rollback 3; -- local connection again
* xa_getconnection; select * from global_xactTable where gxid is not
* null order by gxid,username; select * from foo;
*/
s = conn.createStatement();
s.executeUpdate("delete from APP.fooMorph");
rs = s.executeQuery("select * from APP.fooMorph where A >= 2000");
JDBC.assertEmpty(rs);
rs.close();
try {
xar.end(xid3, XAResource.TMFAIL);
} catch (XAException e) {
if (e.errorCode != XAException.XA_RBROLLBACK)
throw e;
}
xar.rollback(xid3);
conn = xac.getConnection();
s = conn.createStatement();
rs = s.executeQuery("select * from APP.fooMorph where A >= 2000");
expectedRows = new String[][] { { "2001" }, { "2002" }, { "2003" },
{ "2005" }, { "2007" } };
JDBC.assertFullResultSet(rs, expectedRows);
rs.close();
s.close();
conn.close();
}
/**
* This test checks the fix on DERBY-4310, for not repreparing PreparedStatements
* upon calling close() on them.
*/
public void testDerby4310PreparedStatement() throws SQLException, XAException {
XADataSource xads = J2EEDataSource.getXADataSource();
J2EEDataSource.setBeanProperty(xads, "databaseName", "wombat");
XAConnection xaconn = xads.getXAConnection();
XAResource xar = xaconn.getXAResource();
Xid xid = XATestUtil.getXid(1,93,18);
/* Create the table and insert some records into it. */
Connection conn = xaconn.getConnection();
Statement s = conn.createStatement();
s.executeUpdate("CREATE TABLE foo4310_PS (I INT)");
conn.createStatement().executeUpdate("insert into APP.foo4310_PS values (0)");
conn.createStatement().executeUpdate("insert into APP.foo4310_PS values (1)");
conn.createStatement().executeUpdate("insert into APP.foo4310_PS values (2)");
conn.commit();
/* Prepare and execute the statement to be tested */
PreparedStatement ps = conn.prepareStatement("SELECT * FROM APP.foo4310_PS");
ps.executeQuery().close();
/* Start and end a transaction on the XAResource object */
xar.start(xid, XAResource.TMNOFLAGS);
xar.end(xid, XAResource.TMSUCCESS);
/* Drop the table on a parallel, regular connection */
Connection conn2 = getConnection();
Statement s2 = conn2.createStatement();
s2.execute("DROP TABLE foo4310_PS");
conn2.commit();
conn2.close();
try {
/* Try to close the prepared statement. This would throw an exception
* before the fix, claiming that the table was not found. */
ps.close();
} finally {
/* Rollback the transaction and close the connections */
xar.rollback(xid);
conn.close();
xaconn.close();
}
}
/**
* This test checks the fix on DERBY-4310, for not repreparing CallableStatements
* upon calling close() on them.
*/
public void testDerby4310CallableStatement() throws SQLException, XAException {
XADataSource xads = J2EEDataSource.getXADataSource();
J2EEDataSource.setBeanProperty(xads, "databaseName", "wombat");
XAConnection xaconn = xads.getXAConnection();
XAResource xar = xaconn.getXAResource();
Xid xid = XATestUtil.getXid(1,93,18);
/* Create the procedure bazed on XATest.zeroArg() */
Connection conn = xaconn.getConnection();
Statement s = conn.createStatement();
s.executeUpdate("CREATE PROCEDURE ZA() LANGUAGE JAVA "+
"EXTERNAL NAME 'org.apache.derbyTesting.functionTests.tests.jdbcapi.XATest.zeroArg' "+
"PARAMETER STYLE JAVA");
conn.commit();
/* Prepare and execute CallableStatement based on the procedure above */
CallableStatement cs = conn.prepareCall("CALL ZA()");
cs.execute();
/* Start and end a transaction on the XAResource object */
xar.start(xid, XAResource.TMNOFLAGS);
xar.end(xid, XAResource.TMSUCCESS);
/* Drop the procedure on a parallel, regular connection */
Connection conn2 = getConnection();
Statement s2 = conn2.createStatement();
s2.execute("DROP PROCEDURE ZA");
conn2.commit();
conn2.close();
try {
/* Try to close the prepared statement. This would throw an exception
* before the fix, claiming that the table was not found. */
cs.close();
} finally {
/* Rollback the transaction and close the connections */
xar.rollback(xid);
conn.close();
xaconn.close();
}
}
/**
* Derby-966 holdability and global/location transactions. (work in
* progress)
*/
public void testDerby966() throws SQLException, XAException {
Statement preStatement = getConnection().createStatement();
preStatement.execute("create table foo966 (a int)");
preStatement.executeUpdate("insert into APP.foo966 values (0)");
preStatement.executeUpdate("insert into APP.foo966 values (1)");
preStatement.executeUpdate("insert into APP.foo966 values (2)");
preStatement.executeUpdate("insert into APP.foo966 values (3)");
preStatement.executeUpdate("insert into APP.foo966 values (4)");
preStatement.executeUpdate("insert into APP.foo966 values (2001)");
preStatement.executeUpdate("insert into APP.foo966 values (2002)");
preStatement.executeUpdate("insert into APP.foo966 values (2003)");
preStatement.executeUpdate("insert into APP.foo966 values (2005)");
preStatement.executeUpdate("insert into APP.foo966 values (2007)");
preStatement.close();
XADataSource xads = J2EEDataSource.getXADataSource();
XAConnection xac = xads.getXAConnection();
XAResource xar = xac.getXAResource();
Xid xid = XATestUtil.getXid(996, 9, 48);
Connection conn = xac.getConnection();
// Obtain Statements and PreparedStatements
// with all the holdability options.
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, conn.getHoldability());
Statement sdh = conn.createStatement();
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, sdh
.getResultSetHoldability());
checkHeldRS(conn, sdh, sdh.executeQuery("select * from app.foo966"));
PreparedStatement psdh = conn.prepareStatement("SELECT * FROM APP.foo966");
PreparedStatement psdh_d = conn
.prepareStatement("DELETE FROM APP.foo966 WHERE A < -99");
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, psdh
.getResultSetHoldability());
checkHeldRS(conn, psdh, psdh.executeQuery());
Statement shh = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, shh
.getResultSetHoldability());
checkHeldRS(conn, shh, shh.executeQuery("select * from app.foo966"));
PreparedStatement pshh = conn.prepareStatement("SELECT * FROM APP.foo966",
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
PreparedStatement pshh_d = conn.prepareStatement(
"DELETE FROM APP.foo966 WHERE A < -99",
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, shh
.getResultSetHoldability());
checkHeldRS(conn, pshh, pshh.executeQuery());
Statement sch = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, sch
.getResultSetHoldability());
checkHeldRS(conn, sch, sch.executeQuery("select * from app.foo966"));
PreparedStatement psch = conn.prepareStatement("SELECT * FROM APP.foo966",
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.CLOSE_CURSORS_AT_COMMIT);
PreparedStatement psch_d = conn.prepareStatement(
"DELETE FROM APP.foo966 WHERE A < -99",
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.CLOSE_CURSORS_AT_COMMIT);
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, psch_d
.getResultSetHoldability());
checkHeldRS(conn, psch, psch.executeQuery());
// set the connection's holdabilty to false
conn.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
Statement sdc = conn.createStatement();
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, sdc
.getResultSetHoldability());
checkHeldRS(conn, sdc, sdc.executeQuery("select * from app.foo966"));
PreparedStatement psdc = conn.prepareStatement("SELECT * FROM APP.foo966");
PreparedStatement psdc_d = conn
.prepareStatement("DELETE FROM APP.foo966 WHERE A < -99");
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, psdc
.getResultSetHoldability());
checkHeldRS(conn, psdc, psdc.executeQuery());
Statement shc = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, psdc
.getResultSetHoldability());
checkHeldRS(conn, shc, shc.executeQuery("select * from app.foo966"));
PreparedStatement pshc = conn.prepareStatement("SELECT * FROM APP.foo966",
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
PreparedStatement pshc_d = conn.prepareStatement(
"DELETE FROM APP.foo966 WHERE A < -99",
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, pshc
.getResultSetHoldability());
checkHeldRS(conn, pshc, pshc.executeQuery());
Statement scc = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, scc
.getResultSetHoldability());
checkHeldRS(conn, scc, scc.executeQuery("select * from app.foo966"));
PreparedStatement pscc = conn.prepareStatement("SELECT * FROM APP.foo966",
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.CLOSE_CURSORS_AT_COMMIT);
PreparedStatement pscc_d = conn.prepareStatement(
"DELETE FROM APP.foo966 WHERE A < -99",
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.CLOSE_CURSORS_AT_COMMIT);
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, pscc
.getResultSetHoldability());
checkHeldRS(conn, pscc, pscc.executeQuery());
// Revert back to holdable
conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
ResultSet rs = sdh.executeQuery("SELECT * FROM APP.foo966");
rs.next();
// before commit
assertEquals(0, +rs.getInt(1));
conn.commit();
// aftercommit
rs.next();
assertEquals(1, rs.getInt(1));
rs.close();
// ensure a transaction is active to test DERBY-1025
rs = sdh.executeQuery("SELECT * FROM APP.foo966");
// This switch to global is ok because conn
// is in auto-commit mode, thus the start performs
// an implicit commit to complete the local transaction.
// start a global xact and test those statements.
xar.start(xid, XAResource.TMNOFLAGS);
// Statements not returning ResultSet's should be ok
sdh.executeUpdate("DELETE FROM APP.foo966 where A < -99");
shh.executeUpdate("DELETE FROM APP.foo966 where A < -99");
sch.executeUpdate("DELETE FROM APP.foo966 where A < -99");
ArrayList<ResultSet> openRS = new ArrayList<ResultSet>();
// Statements obtained while default was hold.
// All should work, holability will be downgraded
// to close on commit for those Statements with hold set.
openRS.add(sdh.executeQuery("SELECT * FROM APP.foo966"));
openRS.add(shh.executeQuery("SELECT * FROM APP.foo966"));
openRS.add(sch.executeQuery("SELECT * FROM APP.foo966"));
// PreparedStatements obtained while default was hold.
// Holdability should be downgraded.
openRS.add(psdh.executeQuery());
openRS.add(pshh.executeQuery());
openRS.add(psch.executeQuery());
// Statements not returning ResultSet's should be ok
psdh_d.executeUpdate();
pshh_d.executeUpdate();
psch_d.executeUpdate();
// Statements not returning ResultSet's should be ok
sdc.executeUpdate("DELETE FROM APP.foo966 where A < -99");
shc.executeUpdate("DELETE FROM APP.foo966 where A < -99");
scc.executeUpdate("DELETE FROM APP.foo966 where A < -99");
// Statements obtained while default was close.
// all should return close on commit ResultSets
openRS.add(sdc.executeQuery("SELECT * FROM APP.foo966"));
openRS.add(shc.executeQuery("SELECT * FROM APP.foo966"));
openRS.add(scc.executeQuery("SELECT * FROM APP.foo966"));
// PreparedStatements obtained while default was close.
openRS.add(psdc.executeQuery());
openRS.add(pshc.executeQuery());
openRS.add(pscc.executeQuery());
// Statements not returning ResultSet's should be ok
psdc_d.executeUpdate();
pshc_d.executeUpdate();
pscc_d.executeUpdate();
// All the ResultSets should be open. Run a simple
// test, clearWarnings throws an error if the ResultSet
// is closed. Also would be nice here to use the new
// JDBC 4.0 method getHoldabilty to ensure the
// holdability is reported correctly.
int orsCount = 0;
for (ResultSet ors : openRS) {
ors.clearWarnings();
orsCount++;
}
assertEquals("Incorrect number of open result sets", 12, orsCount);
// Test we cannot switch the connection to holdable
try {
conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
fail("FAIL - set holdability in global xact.");
} catch (SQLException sqle) {
assertSQLState("XJ05C", sqle);
}
// JDBC 4.0 (proposed final draft) section allows
// drivers to change the holdability when creating
// a Statement object and attach a warning to the Connection.
Statement sglobalhold = conn.createStatement(
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, sglobalhold
.getResultSetHoldability());
sglobalhold.close();
// DERBY2481 Client does not downgrade PreparedStatement holdability
if (!usingDerbyNetClient()) {
PreparedStatement psglobalhold = conn.prepareStatement(
"SELECT * FROM APP.foo966", ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, psglobalhold
.getResultSetHoldability());
psglobalhold.close();
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, sdh
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, sch
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, psdh
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, pshh
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, psch
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, sdc
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, shc
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, scc
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, psdh_d
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, pshh_d
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, psch_d
.getResultSetHoldability());
}
xar.end(xid, XAResource.TMSUCCESS);
if (xar.prepare(xid) != XAResource.XA_RDONLY)
fail("FAIL prepare didn't indicate r/o");
// All the ResultSets should be closed. Run a simple
// test, clearWarnings throws an error if the ResultSet
// is closed.
int crsCount = 0;
for (ResultSet crs : openRS) {
try {
crs.clearWarnings();
} catch (SQLException sqle) {
}
crsCount++;
}
assertEquals("After global transaction closed ResultSets ", 12,
crsCount);
// Check the statements revert to holdable as required.
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, sdh
.getResultSetHoldability());
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, shh
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, sch
.getResultSetHoldability());
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, psdh
.getResultSetHoldability());
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, pshh
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, psch
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, sdc
.getResultSetHoldability());
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, shc
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, scc
.getResultSetHoldability());
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, psdh_d
.getResultSetHoldability());
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, pshh_d
.getResultSetHoldability());
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, psch_d
.getResultSetHoldability());
// intermittently we get a failure in this test if we do not
// rollback, see DERBY-6248.
conn.rollback();
conn.close();
}
/**
* DERBY-4731
* Test using a GLOBAL TEMPORARY TABLE table in an
* XA transaction and leaving it active during two phase commit.
* Before the fix this test would throw the following at commit
* time:
* ERROR 40XT0: An internal error was identified by RawStore module.
*
*
* @throws XAException
* @throws SQLException
*
*/
public void testXATempTableD4731_RawStore()
throws SQLException, XAException {
doXATempTableD4731Work(true, false, XATestUtil.getXid(997, 9, 49));
}
/**
* DERBY-4735 Temp tables with XA transactions
* an Assert will occur on prepare if only
* temp table work is done in the xact.
*
* @throws XAException
* @throws SQLException
*
*/
public void xtestXATempTableD4735_Assert()
throws SQLException, XAException {
doXATempTableD4731Work(false, false, XATestUtil.getXid(999, 11, 51));
doXATempTableD4731Work(false, true, XATestUtil.getXid(1000, 12, 52));
}
/**
* DERBY-4743 Temp tables with XA transactions
*
* Verifies that global temporary table can not be accessed after the
* commit of the XA transaction.
*
* @throws XAException
* @throws SQLException
*
*/
public void testXATempTableD4743()
throws SQLException, XAException {
doXATempTableD4731Work(true, true, XATestUtil.getXid(998, 10, 50));
}
/**
* DERBY-5552 Check that lock timeout does not destroy connection
* during an XA Transaction.
*
* @throws SQLException
* @throws XAException
*/
public void testXALockTimeout() throws SQLException, XAException {
XADataSource xads = J2EEDataSource.getXADataSource();
J2EEDataSource.setBeanProperty(xads, "databaseName", "wombat");
// Get the first connection and lock table in
// xa transaction
XAConnection xaconn = xads.getXAConnection();
XAResource xar = xaconn.getXAResource();
Xid xid = XATestUtil.getXid(998,10,50);
Connection conn = xaconn.getConnection();
Statement s = conn.createStatement();
xar.start(xid, XAResource.TMNOFLAGS);
s.executeUpdate("INSERT INTO TABLT VALUES(2)");
// Get a second connection and global xact
// and try to select causing lock timeout
XAConnection xaconn2 = xads.getXAConnection();
XAResource xar2 = xaconn2.getXAResource();
Xid xid2 = XATestUtil.getXid(999,11,51);
Connection conn2 = xaconn2.getConnection();
// Set to serializable so we get lock timeout
conn2.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
xar2.start(xid2, XAResource.TMNOFLAGS);
Statement s2 = conn2.createStatement();
s2.executeUpdate("INSERT INTO TABLT VALUES(3)");
assertGlobalXactCount(2);
try {
ResultSet rs = s2.executeQuery("SELECT * FROM TABLT");
fail("Should have gotten lock timeout error: " + LOCKTIMEOUT);
} catch (SQLException se) {
assertSQLState(LOCKTIMEOUT,se);
}
// After the lock timeout we just have one global transaction.
// lock timeout implicitly rolled back xid2
assertGlobalXactCount(1);
assertConnOK(conn);
// DERBY-5552 Make sure connection is ok after lock timeout
assertConnOK(conn2);
//Should be able to end and commit xid1
xar.end(xid, XAResource.TMSUCCESS);
xar.prepare(xid);
xar.commit(xid, false);
// xid2 should have already been rolled back so end should fail
try {
xar2.end(xid2, XAResource.TMSUCCESS);
fail("Should have gotten exception ending xid2");
} catch (XAException xae) {
//xae.printStackTrace();
assertEquals(XAException.XA_RBTIMEOUT, xae.errorCode);
}
// Should have no locks on TABLT
Statement drops = createStatement();
drops.executeUpdate("DROP TABLE TABLT");
// verify there are no more global transactions
assertGlobalXactCount(0);
// Need to explicitly rollback xid2 as it ended with
// an implicit rollback XA_RBTIMEOUT
xar2.rollback(xid2);
// Make sure both connections can be used to make a new global xact
xar.start(xid, XAResource.TMNOFLAGS);
s.executeUpdate("CREATE TABLE TABLT (I INT)");
s.executeUpdate("INSERT INTO TABLT VALUES(1)");
xar.end(xid, XAResource.TMSUCCESS);
xar.prepare(xid);
xar.commit(xid, false);
// now the other connection ..
xar2.start(xid2, XAResource.TMNOFLAGS);
s2.executeUpdate("INSERT INTO TABLT VALUES(2)");
xar2.end(xid2, XAResource.TMSUCCESS);
xar.prepare(xid2);
xar.commit(xid2, false);
assertGlobalXactCount(0);
conn.close();
xaconn.close();
conn2.close();
xaconn2.close();
}
/**
* DERBY-6879 Check that a XA transaction timeout while a cleanupOnError is
* being performed does not cause a Java level deadlock.
*
* The strategy is to cause a XA statement to wait for a period that is
* longer than the XA transaction timeout which will allow the timeout to
* cancel the XA transaction. That is accomplished by locking a table using
* a standard connection and then issuing a select on the same table using a
* XA connection. The select will wait for the required locks to be
* available up to the lock timeout. For the test to work correctly the XA
* transaction timeout must be less than the lock timeout.
*
* A dealock watchdog is used to detect the deadlock until the DERBY-6879
* issue is fixed.
*
* @throws SQLException
* @throws XAException
*/
public void testDerby6879() throws SQLException, XAException {
XADataSource xads = J2EEDataSource.getXADataSource();
J2EEDataSource.setBeanProperty(xads, "databaseName", "wombat");
Connection conn = J2EEDataSource.getConnectionPoolDataSource().getPooledConnection().getConnection();
conn.setAutoCommit(false);
Statement s = conn.createStatement();
s.execute("LOCK TABLE TABLT IN EXCLUSIVE MODE");
// Get a second connection and global xact
// and try to select causing lock timeout
XAConnection xaconn2 = xads.getXAConnection();
XAResource xar2 = xaconn2.getXAResource();
xar2.setTransactionTimeout(2);
Xid xid2 = XATestUtil.getXid(6879, 11, 51);
Connection conn2 = xaconn2.getConnection();
// Set to serializable so we get lock timeout
conn2.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
xar2.start(xid2, XAResource.TMNOFLAGS);
Statement s2 = conn2.createStatement();
assertGlobalXactCount(1);
DeadlockWatchdog wd = new DeadlockWatchdog(30 * 1000);
wd.start();
try {
ResultSet rs = s2.executeQuery("SELECT * FROM TABLT");
fail("Should have gotten lock timeout error: " + LOCKTIMEOUT);
} catch (SQLException se) {
assertSQLState(LOCKTIMEOUT, se);
}
wd.stop();
// xid2 should have already been rolled back so end should fail
try {
xar2.end(xid2, XAResource.TMSUCCESS);
fail("Should have gotten exception ending xid2");
} catch (XAException xae) {
assertTrue(xae.errorCode >= XAException.XAER_OUTSIDE || xae.errorCode <= XAException.XAER_ASYNC);
}
conn.commit();
conn.close();
conn2.close();
xaconn2.close();
}
/**
* The two cases for DERBY-4371 do essentially the same thing. Except doing
* logged work causes the RawStore error and doing only temp table
* operations causes the assert.
*
* @param doLoggedWorkInXact
* @throws SQLException
* @throws XAException
*/
private void doXATempTableD4731Work(
boolean doLoggedWorkInXact,
boolean access_temp_table_after_xaendandcommit,
Xid xid)
throws SQLException, XAException{
XADataSource xads = J2EEDataSource.getXADataSource();
XAConnection xaconn = xads.getXAConnection();
XAResource xar = xaconn.getXAResource();
xar.start(xid, XAResource.TMNOFLAGS);
Connection conn = xaconn.getConnection();
Statement s = conn.createStatement();
if (doLoggedWorkInXact){
// need to do some real work in our transaction
// so make a table
makeARealTable(s);
}
// make the temp table
s.executeUpdate("DECLARE GLOBAL TEMPORARY TABLE SESSION.T1 ( XWSID INT, XCTID INT, XIID CHAR(26), XVID SMALLINT, XLID CHAR(8) FOR BIT DATA) ON COMMIT DELETE ROWS NOT LOGGED ON ROLLBACK DELETE ROWS");
// insert a row
PreparedStatement ps =
conn.prepareStatement("INSERT INTO SESSION.T1 VALUES (?,?,?,?,?)");
ps.setInt(1,1);
ps.setInt(2,1);
ps.setString(3,"hello");
ps.setShort(4, (short) 1);
ps.setBytes(5, new byte[] {0x0,0x1});
ps.executeUpdate();
ResultSet rs = s.executeQuery("SELECT count(*) FROM SESSION.t1");
JDBC.assertFullResultSet(rs, new String[][] {{"1"}});
rs.close();
// You could work around the issue by dropping the TEMP table
//s.executeUpdate("DROP TABLE SESSION.T1");
xar.end(xid, XAResource.TMSUCCESS);
assertEquals(
(doLoggedWorkInXact ? XAResource.XA_OK : XAResource.XA_RDONLY),
xar.prepare(xid));
if (doLoggedWorkInXact)
{
// if you don't do logged work in the transaction, then the
// prepare with be done with XAResource.XA_RDONLY. If you
// try to commit a prepared read only transaction you will get
// an error, so only commit prepared transactions here that did
// some "real" logged work.
xar.commit(xid,false);
}
if (access_temp_table_after_xaendandcommit)
{
// temp table should not be available after commit of an XA
// transaction.
assertStatementError(
"42X05", s, "SELECT count(*) FROM SESSION.t1");
conn.commit();
}
s.close();
conn.close();
xaconn.close();
}
private void makeARealTable(Statement s) throws SQLException {
try {
s.executeUpdate("DROP TABLE REALTABLE1");
} catch (SQLException se) {
{
s.executeUpdate("CREATE TABLE REALTABLE1 (i int)");
}
}
}
/**
* Check the held state of a ResultSet by fetching one row, executing a
* commit and then fetching the next. Checks the held state matches the
* behaviour.
*/
private static void checkHeldRS(Connection conn, Statement s, ResultSet rs)
throws SQLException {
// DERBY-1008 - can't run with client
if (!usingDerbyNetClient()) {
if (s.getConnection() != conn)
fail("FAIL - mismatched statement & Connection");
}
if (rs.getStatement() != s) {
// DERBY-1009
fail("FAIL - mismatched statement & ResultSet "
+ " Statement class " + s.getClass()
+ " ResultSet' Statements class "
+ rs.getStatement().getClass());
}
boolean held = (ResultSet.HOLD_CURSORS_OVER_COMMIT == s
.getResultSetHoldability());
rs.next();
assertEquals(0, rs.getInt(1));
conn.commit();
try {
rs.next();
} catch (SQLException sqle) {
boolean ok = !held;
if (ok) {
assertSQLState("XCL16", sqle);
} else {
fail("Held cursor closed on commit");
}
}
rs.close();
conn.commit();
}
/**
* Dummy method for testDerby4310* fixtures
*/
public static void zeroArg() { }
public static Test baseSuite(String name) {
BaseTestSuite suite = new BaseTestSuite(name);
suite.addTestSuite(XATest.class);
return new CleanDatabaseTestSetup(suite) {
/**
* Creates the table used in the test cases.
*
*/
protected void decorateSQL(Statement s) throws SQLException {
XATestUtil.createXATransactionView(s);
// Table for lock timeout test
s.executeUpdate("CREATE TABLE TABLT (I INT)");
s.executeUpdate("INSERT INTO TABLT VALUES(1)");
}
};
}
/**
* Excecute a simple SQL statement to assert that the connection is valid
* @param conn Connection to check
* @throws SQLException on error
*/
private static void assertConnOK(Connection conn) throws SQLException{
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery("VALUES(1)");
JDBC.assertSingleValueResultSet(rs, "1");
}
/**
* Verify the expected number of global transactions.
* Run test with -Dderby.tests.debug to see the full transaction table on the
* console
*
* @param expectedCount expected number of global transaction
* @throws SQLException on error
*/
private void assertGlobalXactCount(int expectedCount ) throws SQLException {
Connection conn = openDefaultConnection();
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery(
"SELECT COUNT(*) FROM syscs_diag.transaction_table WHERE GLOBAL_XID IS NOT NULL");
rs.next();
int count = rs.getInt(1);
if (TestConfiguration.getCurrent().isVerbose()) {
System.out.println("assertGlobalXactCount(" + expectedCount +
"): Full Transaction Table ...");
Utilities.showResultSet(s.executeQuery(
"SELECT * FROM syscs_diag.transaction_table"));
}
assertTrue("Expected " + expectedCount + "global transactions but saw " + count, expectedCount == count);
}
/**
* Runs the test fixtures in embedded and client.
*
* @return test suite
*/
public static Test suite() {
BaseTestSuite suite = new BaseTestSuite("XATest");
// no XA for JSR169
if (JDBC.vmSupportsJSR169())
return suite;
suite.addTest(baseSuite("XATest:embedded"));
suite.addTest(TestConfiguration
.clientServerDecorator(baseSuite("XATest:client")));
Test test = DatabasePropertyTestSetup.setLockTimeouts(suite, 3, 5);
test = decorateWithPolicy(test);
return test;
}
// grant ALL FILES execute, and getPolicy permissions,
// as well as write for the trace files.
private static Test decorateWithPolicy(Test test) {
//
// Install a security manager using the initial policy file. This is
// needed foro the DeadlockWatchdog to allow it to access the ThreadMXBean
// to check for a deadlock
//
return new SecurityManagerSetup(test, POLICY_FILE_NAME);
}
}