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 my...@apache.org on 2007/04/06 10:03:51 UTC
svn commit: r526087 [2/3] - in
/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests:
tests/jdbcapi/DataSourceTest.java util/SecurityCheck.java
Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DataSourceTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DataSourceTest.java?view=auto&rev=526087
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DataSourceTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DataSourceTest.java Fri Apr 6 01:03:51 2007
@@ -0,0 +1,3246 @@
+/*
+
+ Derby - Class org.apache.derbyTesting.functionTests.tests.jdbcapi.DataSourceTest
+
+ 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.io.File;
+import java.io.Serializable;
+import java.security.AccessController;
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ParameterMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.sql.ConnectionEvent;
+import javax.sql.ConnectionEventListener;
+import javax.sql.ConnectionPoolDataSource;
+import javax.sql.DataSource;
+import javax.sql.PooledConnection;
+import javax.sql.XAConnection;
+import javax.sql.XADataSource;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.derby.jdbc.ClientConnectionPoolDataSource;
+import org.apache.derby.jdbc.ClientDataSource;
+import org.apache.derby.jdbc.ClientXADataSource;
+import org.apache.derby.jdbc.EmbeddedConnectionPoolDataSource;
+import org.apache.derby.jdbc.EmbeddedDataSource;
+import org.apache.derby.jdbc.EmbeddedSimpleDataSource;
+import org.apache.derby.jdbc.EmbeddedXADataSource;
+import org.apache.derbyTesting.functionTests.util.SecurityCheck;
+import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.J2EEDataSource;
+import org.apache.derbyTesting.junit.JDBC;
+import org.apache.derbyTesting.junit.JDBCDataSource;
+import org.apache.derbyTesting.junit.TestConfiguration;
+//import org.apache.oro.text.perl.Perl5Util;
+
+/**
+ * Test the various embedded DataSource implementations of Derby.
+ *
+ * Performs SecurityCheck analysis on the JDBC objects returned.
+ * This is because this test returns to the client a number of
+ * different implementations of Connection, Statement etc.
+ *
+ * @see org.apache.derbyTesting.functionTests.util.SecurityCheck
+ *
+ */
+public class DataSourceTest extends BaseJDBCTestCase {
+
+ protected static String dbName =
+ TestConfiguration.getCurrent().getDefaultDatabaseName();
+
+ /**
+ * A hashtable of opened connections. This is used when checking to
+ * make sure connection strings are unique; we need to make sure all
+ * the connections are closed when we are done, so they are stored
+ * in this hashtable
+ */
+ protected static Hashtable conns = new Hashtable();
+
+ /**
+ * This is a utility that knows how to do pattern matching. Used
+ * in checking the format of a connection string
+ */
+// protected static Perl5Util p5u = new Perl5Util();
+
+ /** The expected format of a connection string. In English:
+ * "<classname>@<hashcode> (XID=<xid>), (SESSION = <sessionid>),
+ * (DATABASE=<dbname>), (DRDAID = <drdaid>)"
+ */
+ private static final String CONNSTRING_FORMAT = "\\S+@[0-9]+ " +
+ "\\(XID = .*\\), \\(SESSIONID = [0-9]+\\), " +
+ "\\(DATABASE = [A-Za-z]+\\), \\(DRDAID = .+\\)";
+
+ /**
+ * Hang onto the SecurityCheck class while running the
+ * tests so that it is not garbage collected during the
+ * test and lose the information it has collected,
+ * in case it should get printed out.
+ */
+ private final Object nogc = SecurityCheck.class;
+
+ public DataSourceTest(String name) {
+ super(name);
+ }
+
+ public static Test suite() {
+ // TODO: remove tearDown?
+ if (JDBC.vmSupportsJSR169())
+ {
+ // test uses unsupported classes like DriverManager, XADataSource,
+ // ConnectionPoolDataSource, ConnectionEvenListenere, as well as
+ // unsupported methods, like Connection.setTypeMap()...
+ TestSuite suite =
+ new TestSuite("DatasourceTest cannot run with JSR169");
+ return suite;
+ }
+ else
+ {
+ return TestConfiguration.defaultSuite(DataSourceTest.class);
+ }
+ }
+
+ /**
+ * Set up the conection to the database.
+ */
+ public void setUp() throws Exception {
+ Statement s = createStatement();
+ s.executeUpdate("create table autocommitxastart(i int)");
+ s.executeUpdate("insert into autocommitxastart values 1,2,3,4,5");
+ s.executeUpdate("create schema SCHEMA_Patricio");
+ s.executeUpdate("create table " +
+ "SCHEMA_Patricio.Patricio (id VARCHAR(255), value INTEGER)");
+ s.executeUpdate("create table intTable(i int)");
+ s.executeUpdate("create table hold_30 " +
+ "(id int not null primary key, b char(30))");
+ s.executeUpdate(
+ "create procedure checkConn2(in dsname varchar(20)) " +
+ "parameter style java language java modifies SQL DATA " +
+ "external name " +
+ "'org.apache.derbyTesting.functionTests.tests.jdbcapi." +
+ this.getNestedMethodName() +
+ "'");
+
+ // theoretically, commit should be unnecessary, because
+ // autocommit should be true by default.
+ commit();
+ s.close();
+ }
+
+ public void tearDown() throws Exception {
+ getConnection().setAutoCommit(false);
+ Statement s = createStatement();
+ s.executeUpdate("drop table autocommitxastart");
+ s.executeUpdate("drop table intTable");
+ s.executeUpdate("drop table hold_30");
+ s.executeUpdate("drop table SCHEMA_Patricio.Patricio");
+ s.executeUpdate("drop schema SCHEMA_Patricio restrict");
+ s.executeUpdate("drop procedure checkConn2");
+ // should be automatic?
+ commit();
+ s.close();
+
+ // attempt to get rid of any left-over trace files
+ AccessController.doPrivileged(new java.security.PrivilegedAction() {
+ public Object run() {
+ for (int i=0 ; i < 6 ; i++)
+ {
+ String traceFileName = "trace" + (i+1) + ".out";
+ File traceFile = new File(traceFileName);
+ if (traceFile.exists())
+ {
+ // if it exists, attempt to get rid of it
+ traceFile.delete();
+ }
+ }
+ return null;
+ }
+ });
+ }
+
+ /* comment out. leaving in, just in case it's ever relevant.
+ * when uncommented, this will run when network server tests are
+ * started, and then reflect the results of the embedded checks.
+ // perform security analysis of the public api for the embedded engine
+ public void testDataSourceAPI() throws SQLException, ClassNotFoundException
+ {
+ SecurityCheck.report();
+ }
+ */
+
+ public void testAllDataSources() throws SQLException, Exception
+ {
+ Connection dmc = getConnection();
+ CallableStatement cs = dmc.prepareCall("call checkConn2(?)");
+ cs.setString(1,"Nested");
+ try {
+ cs.execute();
+ } catch (SQLException sqle) {
+ assertSQLState("40XC0", sqle);
+ }
+ cs.setString(1,"Nested2");
+ cs.execute();
+
+ String EmptyMapValue=null;
+ // Note: currently, not supported
+ String NullMapValue=null;
+ String MapMapValue=null;
+ if (usingEmbedded())
+ {
+ EmptyMapValue="OK"; NullMapValue="XJ081"; MapMapValue="0A000";
+ }
+ else if (usingDerbyNetClient())
+ {
+ EmptyMapValue="0A000"; NullMapValue="0A000"; MapMapValue="0A000";
+ }
+ Object[] expectedValues = {
+ new Integer(ResultSet.HOLD_CURSORS_OVER_COMMIT), "XJ010",
+ new Integer(2), new Boolean(true), new Boolean(false),
+ EmptyMapValue, NullMapValue, MapMapValue};
+
+ assertConnectionOK(expectedValues, "DriverManager ", dmc);
+
+ if (usingEmbedded())
+ assertTenConnectionsUnique();
+
+ DataSource dscs = JDBCDataSource.getDataSource(dbName);
+ if (usingEmbedded())
+ assertToString(dscs);
+
+ DataSource ds = dscs;
+ assertConnectionOK(expectedValues, "DataSource", ds.getConnection());
+
+ DataSource dssimple = null;
+ // simple datasource is only supported with embedded
+ if (usingEmbedded())
+ {
+ EmbeddedSimpleDataSource realdssimple =
+ new EmbeddedSimpleDataSource();
+ realdssimple.setDatabaseName(dbName);
+ ds = realdssimple;
+ dssimple = (DataSource)realdssimple;
+ assertConnectionOK(
+ expectedValues, "SimpleDataSource", ds.getConnection());
+ }
+
+ ConnectionPoolDataSource dsp =
+ J2EEDataSource.getConnectionPoolDataSource();
+ JDBCDataSource.setBeanProperty(dsp, "DatabaseName", dbName);
+
+ if (usingEmbedded())
+ assertToString(dsp);
+
+ PooledConnection pc = dsp.getPooledConnection();
+ // checks currently only implemented for embedded
+ if (usingEmbedded())
+ {
+ SecurityCheck.assertSourceSecurity(
+ pc, "javax.sql.PooledConnection");
+ }
+ pc.addConnectionEventListener(new AssertEventCatcher(1));
+
+ // TODO: log bug / check if one exists
+ // with Network Server / DerbyNetClient, the assertConnectionOK check
+ // returns a different connection object...
+ assertConnectionOK(
+ expectedValues, "ConnectionPoolDataSource", pc.getConnection());
+ assertConnectionOK(
+ expectedValues, "ConnectionPoolDataSource", pc.getConnection());
+
+ XADataSource dsx = J2EEDataSource.getXADataSource();
+ JDBCDataSource.setBeanProperty(dsx, "DatabaseName", dbName);
+ if (usingEmbedded())
+ assertToString(dsx);
+
+ // shutdown db and check all's still ok thereafter
+ TestConfiguration.getCurrent().shutdownDatabase();
+
+ dmc = getConnection();
+ cs = dmc.prepareCall("call checkConn2(?)");
+ // checks currently only implemented for embedded
+ if (usingEmbedded())
+ {
+ SecurityCheck.assertSourceSecurity(
+ cs, "java.sql.CallableStatement");
+ }
+ cs.setString(1,"Nested");
+ try {
+ cs.execute();
+ } catch (SQLException sqle) {
+ assertSQLState("40XC0", sqle);
+ }
+ cs.setString(1, "Nested2");
+ cs.execute();
+
+ XAConnection xac = dsx.getXAConnection();
+ // checks currently only implemented for embedded
+ if (usingEmbedded())
+ {
+ SecurityCheck.assertSourceSecurity(xac, "javax.sql.XAConnection");
+ }
+ xac.addConnectionEventListener(new AssertEventCatcher(3));
+ assertConnectionOK(
+ expectedValues, "XADataSource", xac.getConnection());
+
+ pc = dsp.getPooledConnection();
+ pc.addConnectionEventListener(new AssertEventCatcher(2));
+ assertConnectionOK(
+ expectedValues, "ConnectionPoolDataSource", pc.getConnection());
+
+ // test "local" XAConnections
+ xac = dsx.getXAConnection();
+ xac.addConnectionEventListener(new AssertEventCatcher(4));
+ assertConnectionOK(
+ expectedValues, "XADataSource", xac.getConnection());
+ assertConnectionOK(
+ expectedValues, "XADataSource", xac.getConnection());
+ xac.close();
+
+ // test "global" XAConnections
+ xac = dsx.getXAConnection();
+ xac.addConnectionEventListener(new AssertEventCatcher(5));
+ XAResource xar = xac.getXAResource();
+ // checks currently only implemented for embedded
+ if (usingEmbedded())
+ {
+ SecurityCheck.assertSourceSecurity(
+ xar, "javax.transaction.xa.XAResource");
+ }
+ Xid xid = new cdsXid(1, (byte) 35, (byte) 47);
+ xar.start(xid, XAResource.TMNOFLAGS);
+ Connection xacc = xac.getConnection();
+ xacc.close();
+ expectedValues[0] = new Integer(ResultSet.CLOSE_CURSORS_AT_COMMIT);
+ if (usingEmbedded())
+ expectedValues[1] = "XJ058";
+ expectedValues[3] = new Boolean(false);
+ assertConnectionOK(
+ expectedValues, "Global XADataSource", xac.getConnection());
+ assertConnectionOK(
+ expectedValues, "Global XADataSource", xac.getConnection());
+
+ xar.end(xid, XAResource.TMSUCCESS);
+
+ expectedValues[0] = new Integer(ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ expectedValues[3] = new Boolean(true);
+ assertConnectionOK(expectedValues,
+ "Switch to local XADataSource", xac.getConnection());
+ assertConnectionOK(expectedValues,
+ "Switch to local XADataSource", xac.getConnection());
+
+ Connection backtoGlobal = xac.getConnection();
+
+ xar.start(xid, XAResource.TMJOIN);
+ expectedValues[0] = new Integer(ResultSet.CLOSE_CURSORS_AT_COMMIT);
+ expectedValues[3] = new Boolean(false);
+ assertConnectionOK(expectedValues,
+ "Switch to global XADataSource", backtoGlobal);
+ assertConnectionOK(expectedValues,
+ "Switch to global XADataSource", xac.getConnection());
+ xar.end(xid, XAResource.TMSUCCESS);
+ xar.commit(xid, true);
+
+ xac.close();
+ }
+
+ public void testClosedCPDSConnection() throws SQLException, Exception {
+ // verify that outstanding updates from a closed connection, obtained
+ // from a ConnectionPoolDataSource, are not committed, but rolled back.
+ ConnectionPoolDataSource dsp =
+ J2EEDataSource.getConnectionPoolDataSource();
+ JDBCDataSource.setBeanProperty(dsp, "DatabaseName", dbName);
+ PooledConnection pc = dsp.getPooledConnection();
+ Connection c1 = pc.getConnection();
+ Statement s = c1.createStatement();
+ c1.setAutoCommit(false);
+
+ // this update should get rolled back later
+ s.executeUpdate("insert into intTable values(1)");
+ // this should automatically close the original connection
+ c1 = pc.getConnection();
+
+ ResultSet rs =
+ c1.createStatement().executeQuery("select count(*) from intTable");
+ rs.next();
+ assertEquals(0, rs.getInt(1));
+ c1.close();
+
+ // check connection objects are closed once connection is closed
+ try {
+ rs.next();
+ fail("ResultSet is open for a closed connection obtained from PooledConnection");
+ } catch (SQLException sqle) {
+ // 08003 - No current connection; XCL16 - ResultSet not open
+ if (usingEmbedded())
+ assertSQLState("08003", sqle);
+ else if (usingDerbyNetClient())
+ assertSQLState("XCL16", sqle);
+ }
+
+ try {
+ s.executeUpdate("update intTable set i = 1");
+ fail("Statement is open for a closed connection " +
+ "obtained from PooledConnection");
+ } catch (SQLException sqle) {
+ assertSQLState("08003", sqle);
+ }
+
+ pc.close();
+ pc = null;
+ PoolReset("ConnectionPoolDataSource", dsp.getPooledConnection());
+ s.close();
+ rs.close();
+ c1.close();
+ }
+
+ public void testClosedXADSConnection() throws SQLException, Exception {
+ // verify that outstanding updates from a closed connection, obtained
+ // from an XADataSource, are not committed, but rolled back.
+ XADataSource dsx = J2EEDataSource.getXADataSource();
+ JDBCDataSource.setBeanProperty(dsx, "DatabaseName", dbName);
+ XAConnection xac = dsx.getXAConnection();
+ Connection c1 = xac.getConnection();
+ Statement s = c1.createStatement();
+
+ c1.setAutoCommit(false);
+
+ // this update should be rolled back
+ s.executeUpdate("insert into intTable values(2)");
+
+ c1 = xac.getConnection();
+
+ ResultSet rs = c1.createStatement().executeQuery(
+ "select count(*) from intTable");
+ rs.next();
+
+ assertEquals(0, rs.getInt(1));
+
+ rs.close();
+ c1.close();
+ xac.close();
+ xac = null;
+
+ PoolReset("XADataSource", dsx.getXAConnection());
+ }
+
+ public void testGlobalLocalInterleaf() throws SQLException, XAException {
+ // now some explicit tests for how connection state behaves
+ // when switching between global transactions and local
+ // and setting connection state.
+ // some of this may be tested elsewhere too.
+ // TODO: there is a difference in ReadOnly state between
+ // DerbyNetClient and embedded...Is this a bug?
+
+ XADataSource dsx = J2EEDataSource.getXADataSource();
+ JDBCDataSource.setBeanProperty(dsx, "DatabaseName", dbName);
+ XAConnection xac = dsx.getXAConnection();
+ xac.addConnectionEventListener(new AssertEventCatcher(6));
+ XAResource xar = xac.getXAResource();
+ Xid xid = new cdsXid(1, (byte) 93, (byte) 103);
+
+ // series 1 - Single connection object
+ Connection cs1 = xac.getConnection();
+ // initial local
+ assertConnectionState(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_READ_COMMITTED,
+ true, false, cs1);
+ xar.start(xid, XAResource.TMNOFLAGS);
+ // initial X1
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_COMMITTED,
+ false, false, cs1);
+ cs1.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
+ cs1.setReadOnly(true);
+ setHoldability(cs1, false); // close cursors
+ // modified X1
+ boolean ReadOnly = false;
+ if (usingEmbedded())
+ ReadOnly = true;
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ false, ReadOnly, cs1);
+ xar.end(xid, XAResource.TMSUCCESS);
+ // the underlying local transaction/connection must pick up the
+ // state of the Connection handle cs1
+ // modified local:
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ true, ReadOnly, cs1);
+
+ cs1.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
+ cs1.setReadOnly(false);
+ setHoldability(cs1, false); // close cursors
+
+ // reset local
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_COMMITTED,
+ true, false, cs1);
+
+ // now re-join the transaction, should pick up the read-only
+ // and isolation level from the transaction,
+ // holdability remains that of this handle.
+ xar.start(xid, XAResource.TMJOIN);
+ // re-join X1
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ false, ReadOnly, cs1);
+ xar.end(xid, XAResource.TMSUCCESS);
+
+ // back to local - should be the same as the reset local
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_COMMITTED,
+ true, false, cs1);
+
+ // test suspend/resume
+ // now re-join the transaction (X1) for the second time, should pick
+ // up the read-only and isolation level from the transaction,
+ // holdability remains that of this handle.
+ xar.start(xid, XAResource.TMJOIN);
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ false, ReadOnly, cs1);
+
+ xar.end(xid, XAResource.TMSUSPEND);
+ // local after suspend
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_COMMITTED,
+ true, false, cs1);
+
+ xar.start(xid, XAResource.TMRESUME);
+ // resume X1
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ false, ReadOnly, cs1);
+
+ xar.end(xid, XAResource.TMSUCCESS);
+ // back to local (second time)
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_COMMITTED,
+ true, false, cs1);
+
+ cs1.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
+ cs1.setReadOnly(true);
+ setHoldability(cs1, true); // hold
+ cs1.close();
+
+ cs1 = xac.getConnection();
+ // new handle - local
+ assertConnectionState(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_READ_COMMITTED,
+ true, false, cs1);
+ cs1.close();
+
+ xar.start(xid, XAResource.TMJOIN);
+ cs1 = xac.getConnection();
+ // re-join with new handle X1
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ false, ReadOnly, cs1);
+ cs1.close();
+ xar.end(xid, XAResource.TMSUCCESS);
+
+ // now get a connection (attached to a local)
+ // attach to the global and commit it.
+ // state should be that of the local after the commit.
+ cs1 = xac.getConnection();
+ cs1.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
+ // pre-X1 commit - local
+ assertConnectionState(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_REPEATABLE_READ,
+ true, false, cs1);
+ xar.start(xid, XAResource.TMJOIN);
+ // pre-X1 commit - X1
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ false, ReadOnly, cs1);
+ xar.end(xid, XAResource.TMSUCCESS);
+ // post-X1 end - local
+ assertConnectionState(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_REPEATABLE_READ,
+ true, false, cs1);
+ xar.commit(xid, true);
+ // post-X1 commit - local
+ assertConnectionState(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_REPEATABLE_READ,
+ true, false, cs1);
+ cs1.close();
+ }
+
+ // really part of testGlobalLocalInterLeaf:
+ /**
+ * @throws SQLException
+ * @throws XAException
+ */
+ public void testSetIsolationWithStatement()
+ throws SQLException, XAException {
+ // DERBY-421 Setting isolation level with SQL was not getting
+ // handled correctly
+ // Some more isolation testing using SQL and JDBC api
+ XADataSource dsx = J2EEDataSource.getXADataSource();
+ JDBCDataSource.setBeanProperty(dsx, "DatabaseName", dbName);
+ XAConnection xac = dsx.getXAConnection();
+ xac.addConnectionEventListener(new AssertEventCatcher(6));
+ XAResource xar = xac.getXAResource();
+ Connection conn = xac.getConnection();
+ Statement s = conn.createStatement();
+ // initial local
+ assertConnectionState(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_READ_COMMITTED,
+ true, false, conn);
+
+ // Issue setTransactionIsolation in local transaction
+ conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
+ // setTransactionIsolation in local
+ assertConnectionState(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ true, false, conn);
+
+ Xid xid;
+ //Issue SQL to change isolation in local transaction
+ s.executeUpdate("set current isolation = RR");
+ assertConnectionState(ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_SERIALIZABLE,
+ true, false, conn);
+
+ xid = new cdsXid(1, (byte) 35, (byte) 47);
+ xar.start(xid, XAResource.TMNOFLAGS);
+ // 1st global (new)
+ assertConnectionState(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_SERIALIZABLE,
+ false, false, conn);
+ xar.end(xid, XAResource.TMSUCCESS);
+
+ // local
+ assertConnectionState(ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_SERIALIZABLE,
+ true, false, conn);
+ //Issue SQL to change isolation in local transaction
+ s.executeUpdate("set current isolation = RS");
+ assertConnectionState(ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_REPEATABLE_READ,
+ true, false, conn);
+
+ // DERBY-1325 - Isolation level of local connection does not get reset after ending
+ // a global transaction that was joined/resumed if the isolation level was changed
+ // using SQL
+ xar.start(xid, XAResource.TMJOIN);
+ // 1st global(existing)
+ assertConnectionState(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_SERIALIZABLE,
+ false, false, conn);
+ xar.end(xid, XAResource.TMSUCCESS);
+ // local
+ assertConnectionState(ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_REPEATABLE_READ,
+ true, false, conn);
+ // DERBY-1325 end test
+
+ Xid xid2 = new cdsXid(1, (byte) 93, (byte) 103);
+ xar.start(xid2, XAResource.TMNOFLAGS);
+ // 2nd global (new)
+ assertConnectionState(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_REPEATABLE_READ,
+ false, false, conn);
+ xar.end(xid2, XAResource.TMSUCCESS);
+
+ xar.start(xid, XAResource.TMJOIN);
+ // 1st global (existing)
+ assertConnectionState(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_SERIALIZABLE,
+ false, false, conn);
+ xar.end(xid, XAResource.TMSUCCESS);
+
+ //local
+ assertConnectionState(ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_REPEATABLE_READ,
+ true, false, conn);
+
+ xar.start(xid, XAResource.TMJOIN);
+
+ // 1st global (existing)
+ assertConnectionState(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_SERIALIZABLE,
+ false, false, conn);
+ // Issue SQL to change isolation in 1st global transaction
+ s.executeUpdate("set current isolation = UR");
+ assertConnectionState(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ false, false, conn);
+ xar.end(xid, XAResource.TMSUCCESS);
+
+ // local
+ assertConnectionState(ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ true, false, conn);
+
+ xar.start(xid2, XAResource.TMJOIN);
+ // 2nd global (existing)
+ assertConnectionState(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_REPEATABLE_READ,
+ false, false, conn);
+ xar.end(xid2, XAResource.TMSUCCESS);
+ xar.rollback(xid2);
+ // (After 2nd global rollback ) local
+ assertConnectionState(ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ true, false, conn);
+
+ xar.rollback(xid);
+ // (After 1st global rollback) local
+ assertConnectionState(ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ Connection.TRANSACTION_READ_UNCOMMITTED,
+ true, false, conn);
+ }
+
+ // This test includes some short-hand descriptions of the test cases
+ // left in for reference to the original non-junit test
+ public void testReuseAcrossGlobalLocal() throws SQLException, XAException {
+
+ // TODO: analyze & log a bug if needed:
+ // network server cannot run this test - it hits a protocol error
+ // on tearDown.
+ if (usingDerbyNetClient())
+ return;
+
+ int[] onetwothree = {1,2,3};
+ int[] three = {3};
+ int[] pspc = {1, 4}; // expected parameter count for prepared statements
+ int[] cspc = {2, 12, 12}; // for callable statements
+
+ // statics for testReuseAcrossGlobalLocal
+ int[] StatementExpectedValues = {
+ ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY,
+ ResultSet.FETCH_REVERSE, 444, 713, 19,
+ ResultSet.HOLD_CURSORS_OVER_COMMIT};
+ //ResultSet.CLOSE_CURSORS_AT_COMMIT};
+ int[] PreparedStatementExpectedValues = {
+ ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY,
+ ResultSet.FETCH_REVERSE, 888, 317, 91,
+ ResultSet.HOLD_CURSORS_OVER_COMMIT};
+ int[] CallableStatementExpectedValues = {
+ ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY,
+ ResultSet.FETCH_REVERSE, 999, 137, 85,
+ ResultSet.HOLD_CURSORS_OVER_COMMIT};
+
+ XADataSource dsx = J2EEDataSource.getXADataSource();
+ JDBCDataSource.setBeanProperty(dsx, "DatabaseName", dbName);
+ XAConnection xac = dsx.getXAConnection();
+ xac.addConnectionEventListener(new AssertEventCatcher(6));
+ XAResource xar = xac.getXAResource();
+ Xid xid = new cdsXid(1, (byte) 103, (byte) 119);
+
+ // now check re-use of *Statement objects across local/global
+ // connections.
+ Connection cs1 = xac.getConnection();
+
+ // ensure read locks stay around until end-of transaction
+ cs1.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
+ cs1.setAutoCommit(false);
+ assertLocks(null, cs1);
+
+ Statement sru1 = cs1.createStatement();
+ sru1.setCursorName("SN1");
+ sru1.executeUpdate("insert into intTable values 1,2,3");
+ Statement sruBatch = cs1.createStatement();
+ sruBatch.setCursorName("sruBatch");
+ Statement sruState = createFloatStatementForStateChecking(
+ StatementExpectedValues, cs1);
+ PreparedStatement psruState = createFloatStatementForStateChecking(
+ new int[] {1, 4}, PreparedStatementExpectedValues, cs1,
+ "select i from intTable where i = ?");
+ CallableStatement csruState = createFloatCallForStateChecking(
+ new int[] {2, 12, 12}, CallableStatementExpectedValues, cs1,
+ "CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY(?,?)");
+ PreparedStatement psParams =
+ cs1.prepareStatement("select * from intTable where i > ?");
+ psParams.setCursorName("params");
+ psParams.setInt(1, 2);
+ // Params-local-1
+ resultSetQuery("params", three, psParams.executeQuery());
+
+ sruBatch.addBatch("insert into intTable values 4");
+ // sru1-local-1
+ queryOnStatement("SN1", onetwothree, cs1, sru1);
+ cs1.commit(); // need to commit to switch to an global connection;
+
+ // simple case - underlying connection is re-used for global.
+ xar.start(xid, XAResource.TMNOFLAGS);
+ // Expecting downgrade because global transaction sru1-global-2 is
+ // using a statement with holdability true
+ // sru1-global-2
+ queryOnStatement("SN1", onetwothree, cs1, sru1);
+ sruBatch.addBatch("insert into intTable values 5");
+ Statement sru2 = cs1.createStatement();
+ sru2.setCursorName("OAK2");
+ //sru2-global-3
+ queryOnStatement("OAK2", onetwothree, cs1, sru2);
+ // Expecting downgrade because global transaction sru1-global-4 is
+ // using a statement with holdability true
+ // sru1-global-4
+ queryOnStatement("SN1", onetwothree, cs1, sru1);
+ // Global statement
+ StatementExpectedValues[6] = ResultSet.CLOSE_CURSORS_AT_COMMIT;
+ PreparedStatementExpectedValues[6] = ResultSet.CLOSE_CURSORS_AT_COMMIT;
+ CallableStatementExpectedValues[6] = ResultSet.CLOSE_CURSORS_AT_COMMIT;
+ assertStatementState(null, StatementExpectedValues ,sruState);
+ // Global PreparedStatement
+ assertStatementState(pspc, PreparedStatementExpectedValues, psruState);
+ // Global CallableStatement
+ assertStatementState(cspc, CallableStatementExpectedValues, csruState);
+ // Params-global-1
+ resultSetQuery("params", three, psParams.executeQuery());
+
+ xar.end(xid, XAResource.TMSUCCESS);
+ // now a new underlying connection is created
+ // sru1-local-5
+ queryOnStatement("SN1", onetwothree, cs1, sru1);
+ // sru2-local-6
+ queryOnStatement("OAK2", onetwothree, cs1, sru2);
+ sruBatch.addBatch("insert into intTable values 6,7");
+ Statement sru3 = cs1.createStatement();
+ sru3.setCursorName("SF3");
+ // sru3-local-7
+ queryOnStatement("SF3", onetwothree, cs1, sru3);
+ // Two transactions should hold locks (global and the current XA);
+ // LOCAL
+ StatementExpectedValues[6] = ResultSet.HOLD_CURSORS_OVER_COMMIT;
+ PreparedStatementExpectedValues[6] = ResultSet.HOLD_CURSORS_OVER_COMMIT;
+ CallableStatementExpectedValues[6] = ResultSet.HOLD_CURSORS_OVER_COMMIT;
+ assertStatementState(null, StatementExpectedValues, sruState);
+ assertStatementState(pspc, PreparedStatementExpectedValues, psruState);
+ assertStatementState(cspc, CallableStatementExpectedValues, csruState);
+ // Params-local-2
+ resultSetQuery("params", three, psParams.executeQuery());
+ assertLocks(new int[] {14,14}, cs1);
+ cs1.commit();
+
+ // attach the XA transaction to another connection and see what happens
+ XAConnection xac2 = dsx.getXAConnection();
+ xac2.addConnectionEventListener(new AssertEventCatcher(5));
+ XAResource xar2 = xac2.getXAResource();
+
+ xar2.start(xid, XAResource.TMJOIN);
+ Connection cs2 = xac2.getConnection();
+
+ // these statements were generated by cs1 and thus are still
+ // in a local connection.
+ // sru1-local-8
+ queryOnStatement("SN1", onetwothree, cs1, sru1);
+ // sru2-local-9
+ queryOnStatement("OAK2", onetwothree, cs1, sru2);
+ // sru3-local-10
+ queryOnStatement("SF3", onetwothree, cs1, sru3);
+ sruBatch.addBatch("insert into intTable values 8");
+ // LOCAL 2
+ assertStatementState(null, StatementExpectedValues, sruState);
+ assertStatementState(pspc, PreparedStatementExpectedValues, psruState);
+ assertStatementState(cspc, CallableStatementExpectedValues, csruState);
+
+ assertLocks(new int[] {14, 12}, cs1);
+
+ int[] updateCounts = sruBatch.executeBatch();
+ int[] expectedUpdateCounts = {1, 1, 2, 1};
+ // sruBatch update counts:
+ for (int i = 0; i < updateCounts.length; i++) {
+ assertEquals(expectedUpdateCounts[i], updateCounts[i]);
+ }
+ // sruBatch
+ queryOnStatement(
+ "sruBatch", new int[] {1,2,3,4,5,6,7,8}, cs1, sruBatch);
+
+ xar2.end(xid, XAResource.TMSUCCESS);
+ xac2.close();
+
+ // allow close on already closed XAConnection
+ xac2.close();
+ xac2.addConnectionEventListener(null);
+ xac2.removeConnectionEventListener(null);
+
+ // test methods against a closed XAConnection and its resource
+ try {
+ xac2.getXAResource();
+ // TODO: is this a bug?:
+ // Network Server does not think this is worth an exception.
+ if (usingEmbedded())
+ fail("expected SQLException on " +
+ "closed XAConnection.getXAResource");
+ } catch (SQLException sqle) {
+ assertSQLState("08003", sqle);
+ }
+ try {
+ xac2.getConnection();
+ fail ("expected SQLException on XAConnection.getConnection");
+ } catch (SQLException sqle) {
+ assertSQLState("08003", sqle);
+ }
+ try {
+ xar2.start(xid, XAResource.TMJOIN);
+ fail ("expected XAException on XAResource.TMJOIN");
+ } catch (XAException xae) {
+ assertXAException("XAResource.start", xae);
+ }
+ try {
+ xar2.end(xid, XAResource.TMJOIN);
+ fail ("expected XAException on XAResource.TMJOIN");
+ } catch (XAException xae) {
+ assertXAException("XAResource.end", xae);
+ }
+ try {
+ xar2.commit(xid, true);
+ fail ("expected XAException on XAResource.commit");
+ } catch (XAException xae) {
+ assertXAException("XAResource.commit", xae);
+ }
+ try {
+ xar2.prepare(xid);
+ fail ("expected XAException on XAResource.prepare");
+ } catch (XAException xae) {
+ assertXAException("XAResource.prepare", xae);
+ }
+ try {
+ xar2.recover(0);
+ fail ("expected XAException on XAResource.recover");
+ } catch (XAException xae) {
+ assertXAException("XAResource.recover", xae);
+ }
+ try {
+ xar2.prepare(xid);
+ fail ("expected XAException on XAResource.prepare");
+ } catch (XAException xae) {
+ assertXAException("XAResource.prepare", xae);
+ }
+ try {
+ xar2.isSameRM(xar2);
+ fail ("expected XAException on XAResource.isSameRM");
+ } catch (XAException xae) {
+ assertXAException("XAResource.isSameRM", xae);
+ }
+
+ // close everything
+ cs1.rollback();
+ sruState.close();
+ psruState.close();
+ csruState.close();
+ psParams.close();
+ sruBatch.close();
+ sru1.close();
+ sru2.close();
+ sru3.close();
+ cs1.close();
+ cs2.close();
+ xac.removeConnectionEventListener(null);
+ xac.close();
+ xac2.close();
+
+ // but, still not enough.
+ // what with all the switching between global and local transactions
+ // we still have a lock open on intTable, which will interfere with
+ // our tearDown efforts. Bounce the database.
+ TestConfiguration.getCurrent().shutdownDatabase();
+ }
+
+ public void testSetSchemaInXAConnection() throws SQLException {
+ // tests that set schema works correctly in an XA connection.
+
+ XADataSource dsx = J2EEDataSource.getXADataSource();
+ XAConnection xac3 = dsx.getXAConnection();
+ Connection conn3 = xac3.getConnection();
+ Statement st3 = conn3.createStatement();
+ st3.execute("SET SCHEMA SCHEMA_Patricio");
+ st3.close();
+
+ PreparedStatement ps3 =
+ conn3.prepareStatement("INSERT INTO Patricio VALUES (?, ?)");
+ ps3.setString(1, "Patricio");
+ ps3.setInt(2, 3);
+ ps3.executeUpdate();
+
+ assertEquals(1, ps3.getUpdateCount());
+ ps3.close();
+ conn3.close();
+ xac3.close();
+ }
+
+
+ // test that an xastart in auto commit mode commits the existing work.
+ // test fix of a bug ('beetle 5178') wherein XAresource.start() when
+ // auto-commit is true did not implictly commit any transaction
+ // Also tests DERBY-1025, same description, but for client.
+ public void testAutoCommitOnXAResourceStart() throws SQLException, XAException {
+
+ XADataSource dsx = J2EEDataSource.getXADataSource();
+ XAConnection xac4 = dsx.getXAConnection();
+ Xid xid4a= null;
+
+ // We get an XAID_DUP error from networkserver when attempting
+ // the XAResource.start below if we use the same xid.
+ // Possibly because we're in the same jvm.
+ // When the test is run with clientserverSuite, rather than default,
+ // this wasn't needed, so just create a different id for client
+ if (usingEmbedded())
+ xid4a = new cdsXid(4, (byte) 23, (byte) 76);
+ else if (usingDerbyNetClient())
+ xid4a = new cdsXid(5, (byte) 23, (byte) 76);
+
+ Connection conn4 = xac4.getConnection();
+ assertTrue(conn4.getAutoCommit());
+
+ Statement s4 = conn4.createStatement();
+ ResultSet rs4 = s4.executeQuery("select i from autocommitxastart");
+ rs4.next();
+ assertEquals(1, rs4.getInt(1));
+ rs4.next();
+ assertEquals(2, rs4.getInt(1));
+
+ // XAResource().start should commit the transaction
+ try {
+ xac4.getXAResource().start(xid4a, XAResource.TMNOFLAGS);
+ xac4.getXAResource().end(xid4a, XAResource.TMSUCCESS);
+ } catch (XAException xae) {
+ fail("unexpected XAException on xac4.getXAResource.start or end");
+ } catch (Exception e) {
+ fail("unexpected Exception on xac4.getXAResource.start or end");
+ }
+
+ // DERBY-1025.
+ // With Embedded, this will give error: 08003 - No current connection
+ // But with NetworkServer / DerbyNetClient, the transaction does not
+ // appear to be closed, and we actually get a value.
+ try {
+ rs4.next();
+ rs4.getInt(1);
+ if (usingEmbedded())
+ fail ("expected an exception indicating resultset is closed.");
+ } catch (SQLException sqle) {
+ // expect 08003 - No current connection (or similar).
+ assertSQLState("08003",sqle);
+ }
+
+ conn4.setAutoCommit(false);
+ assertFalse(conn4.getAutoCommit());
+
+ rs4 = s4.executeQuery("select i from autocommitxastart");
+ rs4.next();
+ assertEquals(1, rs4.getInt(1));
+ rs4.next();
+ assertEquals(2, rs4.getInt(1));
+
+ // Get a new xid to begin another transaction.
+ if (usingEmbedded())
+ xid4a = new cdsXid(4, (byte) 93, (byte) 103);
+ else if (usingDerbyNetClient())
+ xid4a = new cdsXid(5, (byte) 93, (byte) 103);
+
+ try {
+ xac4.getXAResource().start(xid4a, XAResource.TMNOFLAGS);
+ } catch (XAException xae) {
+ if (usingEmbedded())
+ assertNull(xae.getMessage());
+ else if (usingDerbyNetClient())
+ {
+ // This should give XAER_OUTSIDE exception because
+ // the resource manager is busy in the local transaction
+ assertTrue(xae.getMessage().indexOf("XAER_OUTSIDE") >=0 );
+ }
+ assertEquals(-9, xae.errorCode);
+ }
+
+ try {
+ rs4.next();
+ assertEquals(3, rs4.getInt(1));
+ } catch (Exception e) {
+ fail (" unexpected exception");
+ }
+ rs4.close();
+
+ conn4.rollback();
+ conn4.close();
+ xac4.close();
+ }
+
+ public void testReadOnlyToWritableTran() throws SQLException, Exception
+ {
+ // TESTING READ_ONLY TRANSACTION FOLLOWED BY WRITABLE TRANSACTION
+ // Test following sequence of steps
+ // 1)start a read-only global transaction
+ // 2)finish that read-only transaction
+ // 3)start another global transaction
+
+ XADataSource dsx = J2EEDataSource.getXADataSource();
+ JDBCDataSource.setBeanProperty(dsx, "DatabaseName", dbName);
+ XAConnection xac5 = dsx.getXAConnection();
+ Xid xid5a = new cdsXid(5, (byte) 119, (byte) 129);
+ Connection conn5 = xac5.getConnection();
+ Statement sru5a = conn5.createStatement();
+ XAResource xar = xac5.getXAResource();
+ xar.start(xid5a, XAResource.TMNOFLAGS);
+ conn5.setReadOnly(true);
+
+ // Read-Only XA transaction;
+ // holdability: (hold, or close cursors over commit) ,
+ // transaction isolation: read-committed,
+ // auto-commit false, read-only true (with embedded)
+ if (usingEmbedded())
+ {
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_COMMITTED,
+ false, true, conn5);
+ }
+ // Note: the original test had no comments about this difference
+ // between Embedded and DerbyNetClient, this has apparently
+ // been accepted behavior.
+ else if (usingDerbyNetClient())
+ {
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_COMMITTED,
+ false, false, conn5);
+ }
+
+ ResultSet rs5 = sru5a.executeQuery(
+ "select count(*) from autocommitxastart");
+ rs5.next();
+ assertEquals(5, rs5.getInt(1));
+ rs5.close();
+ xar.end(xid5a, XAResource.TMSUCCESS);
+ xar.commit(xid5a, true);
+ conn5.close();
+
+ //now start a new transaction
+ conn5 = xac5.getConnection();
+ sru5a = conn5.createStatement();
+ xar.start(xid5a, XAResource.TMNOFLAGS);
+
+ // Writeable XA transaction
+ // holdability: (hold, or close cursors over commit) ,
+ // transaction isolation: read-committed,
+ // auto-commit false, read-only false
+ assertConnectionState(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ Connection.TRANSACTION_READ_COMMITTED,
+ false, false, conn5);
+ sru5a.executeUpdate("insert into autocommitxastart values 6,7");
+ rs5 = sru5a.executeQuery("select count(*) from autocommitxastart");
+ rs5.next();
+ assertEquals(7, rs5.getInt(1));
+ xar.end(xid5a, XAResource.TMSUCCESS);
+ xar.commit(xid5a, true);
+ conn5.close();
+ xac5.close();
+ sru5a.close();
+ }
+
+ // test jira-derby 95 - a NullPointerException was returned when passing
+ // an incorrect database name, should now give error:
+ // XCY00 - invalid valid for property ...
+ // with DataSource
+ public void testJira95ds() throws SQLException {
+ if (usingEmbedded())
+ {
+ try {
+ DataSource ds = JDBCDataSource.getDataSource();
+ // non-existent database
+ JDBCDataSource.setBeanProperty(ds, "databaseName", "jdbc:derby:wombat");
+ ds.getConnection();
+ fail ("expected an SQLException!");
+ } catch (SQLException sqle) {
+ // DERBY-2498: with client, getting a NullPointerException.
+ // Note also: the NPE does not occur with XADataSource - see
+ // testJira95xads().
+ if (usingEmbedded())
+ assertSQLState("XCY00", sqle);
+ } catch (Exception e) {
+ e.printStackTrace();
+ // DERBY-2498, when fixed, remove 'if'
+ if (usingEmbedded())
+ fail ("unexpected exception: " + e.toString());
+ }
+ }
+ }
+
+ // test jira-derby 95 - a NullPointerException was returned when passing
+ // an incorrect database name, should now give error XCY00
+ // with ConnectionPoolDataSource
+ public void testJira95pds() throws SQLException {
+ try {
+ ConnectionPoolDataSource pds = J2EEDataSource.getConnectionPoolDataSource();
+ JDBCDataSource.setBeanProperty(pds, "databaseName", "jdbc:derby:boo");
+ pds.getPooledConnection();
+ fail ("expected an SQLException!");
+ } catch (SQLException sqle) {
+ // DERBY-2498 - when fixed, remove if
+ if (usingEmbedded())
+ assertSQLState("XCY00", sqle);
+ } catch (Exception e) {
+ // DERBY-2498 - when fixed, remove if
+ if (usingEmbedded())
+ fail ("unexpected exception: " + e.toString());
+ }
+ }
+
+ // test jira-derby 95 - a NullPointerException was returned when passing
+ // an incorrect database name, should now give error XCY00
+ // with XADataSource
+ public void testJira95xads() throws SQLException {
+ try {
+ XADataSource dxs = J2EEDataSource.getXADataSource();
+ JDBCDataSource.setBeanProperty(dxs, "databaseName", "jdbc:derby:boo");
+ dxs.getXAConnection().getConnection();
+ fail ("expected an SQLException!");
+ } catch (SQLException sqle) {
+ assertSQLState("XCY00", sqle);
+ } catch (Exception e) {
+ fail ("unexpected exception: " + e.toString());
+ }
+ }
+
+ public void testBadConnectionAttributeSyntax() throws SQLException {
+
+ // DataSource - bad connattr syntax
+ DataSource ds = JDBCDataSource.getDataSource();
+ JDBCDataSource.setBeanProperty(ds, "databaseName", dbName);
+ JDBCDataSource.setBeanProperty(ds, "ConnectionAttributes", "bad");
+ try {
+ ds.getConnection();
+ fail ("should have seen an error");
+ } catch (SQLException e) {
+ if (usingEmbedded())
+ assertSQLState("XJ028", e);
+ else if (usingDerbyNetClient())
+ assertSQLState("XJ212", e);
+ }
+ JDBCDataSource.clearStringBeanProperty(ds, "ConnectionAttributes");
+
+ // ConnectionPoolDataSource - bad connatr syntax
+ ConnectionPoolDataSource cpds = J2EEDataSource.getConnectionPoolDataSource();
+ JDBCDataSource.setBeanProperty(cpds, "databaseName", dbName);
+ JDBCDataSource.setBeanProperty(cpds, "ConnectionAttributes", "bad");
+ try {
+ cpds.getPooledConnection();
+ fail ("should have seen an error");
+ } catch (SQLException e) {
+ assertSQLState("XJ028", e);
+ }
+ JDBCDataSource.clearStringBeanProperty(cpds, "ConnectionAttributes");
+
+ // XADataSource - bad connattr syntax");
+ XADataSource xads = J2EEDataSource.getXADataSource();
+ JDBCDataSource.setBeanProperty(xads, "databaseName", dbName);
+ JDBCDataSource.setBeanProperty(xads, "ConnectionAttributes", "bad");
+ try {
+ xads.getXAConnection();
+ fail ("should have seen an error");
+ } catch (SQLException e) {
+ assertSQLState("XJ028", e);
+ }
+ JDBCDataSource.clearStringBeanProperty(xads, "ConnectionAttributes");
+ } // End testBadConnectionAttributeSyntax
+
+ /**
+ * Check that database name set using setConnectionAttributes is not used
+ * by ClientDataSource. This method tests DERBY-1130.
+ *
+ * @throws SQLException
+ */
+ public void testClientDSConnectionAttributes() throws SQLException {
+ if (usingEmbedded())
+ return;
+
+ ClientDataSource ds = new ClientDataSource();
+
+ // DataSource - EMPTY; expect error 08001 in all cases
+ // 08001: Required Derby DataSource property databaseName not set.
+ dsConnectionRequests(new String[]
+ {"08001","08001","08001","08001",
+ "08001","08001","08001","08001","08001"}, ds);
+
+ // DataSource - connectionAttributes=databaseName=<valid name>
+ ds.setConnectionAttributes("databaseName=" + dbName);
+ dsConnectionRequests(new String[]
+ {"08001","08001","08001","08001",
+ "08001","08001","08001","08001","08001"}, ds);
+ ds.setConnectionAttributes(null);
+
+ // Test that (invalid) database name specified in connection
+ // attributes is not used
+ // DataSource - databaseName=<valid db> and
+ // connectionAttributes=databaseName=kangaroo
+ ds.setConnectionAttributes("databaseName=kangaroo");
+ ds.setDatabaseName(dbName);
+ dsConnectionRequests(new String[]
+ {"OK","08001","OK","OK",
+ "08001","08001","OK","OK","OK"}, ds);
+ ds.setConnectionAttributes(null);
+ ds.setDatabaseName(null);
+
+ // now with ConnectionPoolDataSource
+ ClientConnectionPoolDataSource cpds =
+ new ClientConnectionPoolDataSource();
+ // ConnectionPoolDataSource - EMPTY
+ dsConnectionRequests(new String[]
+ {"08001","08001","08001","08001",
+ "08001","08001","08001","08001","08001"},
+ (ConnectionPoolDataSource)cpds);
+
+ // ConnectionPoolDataSource
+ // - connectionAttributes=databaseName=<valid dbname>
+ cpds.setConnectionAttributes("databaseName=" + dbName);
+ dsConnectionRequests(new String[]
+ {"08001","08001","08001","08001",
+ "08001","08001","08001","08001","08001"},
+ (ConnectionPoolDataSource)cpds);
+ cpds.setConnectionAttributes(null);
+
+ // Test that database name specified in connection attributes is
+ // not used
+ // ConnectionPoolDataSource - databaseName=wombat and
+ // connectionAttributes=databaseName=kangaroo
+ cpds.setConnectionAttributes("databaseName=kangaroo");
+ cpds.setDatabaseName(dbName);
+ dsConnectionRequests(new String[]
+ {"OK","08001","OK","OK","08001","08001","OK","OK","OK"},
+ (ConnectionPoolDataSource)cpds);
+ cpds.setConnectionAttributes(null);
+ cpds.setDatabaseName(null);
+
+ // now with XADataSource
+ ClientXADataSource xads = new ClientXADataSource();
+ // XADataSource - EMPTY
+ dsConnectionRequests(new String[]
+ {"08001","08001","08001","08001",
+ "08001","08001","08001","08001","08001"},
+ (XADataSource) xads);
+
+ // XADataSource - connectionAttributes=databaseName=<valid dbname>
+ xads.setConnectionAttributes("databaseName=wombat");
+ dsConnectionRequests(new String[]
+ {"08001","08001","08001","08001",
+ "08001","08001","08001","08001","08001"},
+ (XADataSource) xads);
+ xads.setConnectionAttributes(null);
+
+ // Test that database name specified in connection attributes is not used
+ // XADataSource - databaseName=wombat and
+ // connectionAttributes=databaseName=kangaroo
+ xads.setConnectionAttributes("databaseName=kangaroo");
+ xads.setDatabaseName("wombat");
+ dsConnectionRequests(new String[]
+ {"OK","08001","OK","OK","08001","08001","OK","OK","OK"},
+ (XADataSource) xads);
+ xads.setConnectionAttributes(null);
+ xads.setDatabaseName(null);
+ } // End testClientDSConnectionAttributes
+
+ // Following test is similar to testClientDSRequestAuthentication, but
+ // for embedded datasources.
+ // This subtest does not run for network server, the database shutdown
+ // is done using setDatabaseShutdown.
+ public static void testDSRequestAuthentication() throws SQLException {
+
+ if (usingDerbyNetClient())
+ return;
+
+ EmbeddedDataSource ds = new EmbeddedDataSource();
+
+ // DataSource - EMPTY
+ dsConnectionRequests(new String[] {
+ "XJ004","XJ004","XJ004","XJ004",
+ "XJ004","XJ004","XJ004","XJ004","XJ004"}, ds);
+
+ // DataSource - connectionAttributes=databaseName=wombat");
+ ds.setConnectionAttributes("databaseName=" + dbName);
+ dsConnectionRequests(new String[] {
+ "XJ004","XJ004","XJ004","XJ004",
+ "XJ004","XJ004","XJ004","XJ004","XJ004"}, ds);
+ ds.setConnectionAttributes(null);
+
+ // DataSource - attributesAsPassword=true");
+ ds.setAttributesAsPassword(true);
+ dsConnectionRequests(new String[] {
+ "XJ004","XJ004","XJ004","XJ028",
+ "XJ028","XJ004","XJ004","XJ004","XJ004"}, ds);
+ ds.setAttributesAsPassword(false);
+
+ // DataSource - attributesAsPassword=true,
+ // connectionAttributes=databaseName=kangaroo");
+ ds.setAttributesAsPassword(true);
+ ds.setConnectionAttributes("databaseName=kangaroo");
+ dsConnectionRequests(new String[] {
+ "XJ004","XJ004","XJ004","XJ028",
+ "XJ028","XJ004","XJ004","XJ004","XJ004"}, ds);
+ ds.setAttributesAsPassword(false);
+ ds.setConnectionAttributes(null);
+
+ // Enable Authentication;
+
+ setDatabaseProperty("derby.user.fred", "wilma");
+ setDatabaseProperty("derby.user.APP", "APP");
+ setDatabaseProperty("derby.authentication.provider", "BUILTIN");
+ setDatabaseProperty("derby.connection.requireAuthentication", "true");
+
+ ds.setShutdownDatabase("shutdown");
+ try {
+ ds.getConnection();
+ } catch (SQLException sqle) {
+ assertSQLState("XJ015", sqle);
+ }
+
+ ds.setDatabaseName(null);
+ ds.setShutdownDatabase(null);
+
+ // "AUTHENTICATION NOW ENABLED");
+
+ // DataSource - attributesAsPassword=true
+ ds.setAttributesAsPassword(true);
+ dsConnectionRequests(new String[] {
+ "XJ004","XJ004","XJ004","XJ028",
+ "XJ028","XJ004","XJ004","XJ004","XJ004"}, ds);
+ ds.setAttributesAsPassword(false);
+
+ // ensure the DS property password is not treated as a set of
+ // attributes.
+ // DataSource - attributesAsPassword=true, user=fred,
+ // password=databaseName=wombat;password=wilma
+ ds.setAttributesAsPassword(true);
+ ds.setUser("fred");
+ ds.setPassword("databaseName=" + dbName + ";password=wilma");
+ dsConnectionRequests(new String[] {
+ "XJ004","XJ004","XJ004","XJ028",
+ "XJ028","XJ004","XJ004","XJ004","XJ004"}, ds);
+ ds.setAttributesAsPassword(false);
+ ds.setUser(null);
+ ds.setPassword(null);
+ ds = null;
+
+ // now with ConnectionPoolDataSource
+ EmbeddedConnectionPoolDataSource cpds = new EmbeddedConnectionPoolDataSource();
+ // ConnectionPoolDataSource - EMPTY
+ dsConnectionRequests(new String[] {
+ "XJ004","XJ004","XJ004","XJ004",
+ "XJ004","XJ004","XJ004","XJ004","XJ004"},
+ (ConnectionPoolDataSource)cpds);
+
+ // ConnectionPoolDataSource -
+ // connectionAttributes=databaseName=wombat
+ cpds.setConnectionAttributes("databaseName=" + dbName);
+ dsConnectionRequests(new String[] {
+ "XJ004","XJ004","XJ004","XJ004",
+ "XJ004","XJ004","XJ004","XJ004","XJ004"},
+ (ConnectionPoolDataSource)cpds);
+ cpds.setConnectionAttributes(null);
+
+ // ConnectionPoolDataSource - attributesAsPassword=true
+ cpds.setAttributesAsPassword(true);
+ dsConnectionRequests(new String[] {
+ "XJ004","XJ004","XJ004","XJ028",
+ "XJ028","XJ004","XJ004","XJ004","XJ004"},
+ (ConnectionPoolDataSource)cpds);
+ cpds.setAttributesAsPassword(false);
+
+ // ensure the DS property password is not treated as a set of
+ // attributes.
+ // ConnectionPoolDataSource - attributesAsPassword=true,
+ // user=fred, password=databaseName=wombat;password=wilma");
+ cpds.setAttributesAsPassword(true);
+ cpds.setUser("fred");
+ cpds.setPassword("databaseName=" + dbName + ";password=wilma");
+ dsConnectionRequests(new String[] {
+ "XJ004","XJ004","XJ004","XJ028",
+ "XJ028","XJ004","XJ004","XJ004","XJ004"},
+ (ConnectionPoolDataSource)cpds);
+ cpds.setAttributesAsPassword(false);
+ cpds.setUser(null);
+ cpds.setPassword(null);
+ cpds = null;
+
+ // now with XADataSource
+ EmbeddedXADataSource xads = new EmbeddedXADataSource();
+ // XADataSource - EMPTY
+ dsConnectionRequests(new String[] {
+ "08006","08006","08006","08006",
+ "08006","08006","08006","08006","08006"},
+ (XADataSource) xads);
+
+ // XADataSource - databaseName=wombat
+ xads.setDatabaseName(dbName);
+ dsConnectionRequests(new String[] {
+ "08004","08004","08004","OK",
+ "08004","08004","08004","08004","08004"},
+ (XADataSource) xads);
+ xads.setDatabaseName(null);
+
+ // XADataSource - connectionAttributes=databaseName=wombat");
+ xads.setConnectionAttributes("databaseName=" + dbName);
+ dsConnectionRequests(new String[] {
+ "08006","08006","08006","08006",
+ "08006","08006","08006","08006","08006"},
+ (XADataSource) xads);
+ xads.setConnectionAttributes(null);
+
+ // XADataSource - attributesAsPassword=true
+ xads.setAttributesAsPassword(true);
+ dsConnectionRequests(new String[] {
+ "08006","08006","08006","08006",
+ "08006","08006","08006","08006","08006"},
+ (XADataSource) xads);
+ xads.setAttributesAsPassword(false);
+
+ // XADataSource - databaseName=wombat, attributesAsPassword=true
+ xads.setDatabaseName(dbName);
+ xads.setAttributesAsPassword(true);
+ dsConnectionRequests(new String[] {
+ "08004","08004","08004","XJ028",
+ "XJ028","08004","08004","OK","08004"},
+ (XADataSource) xads);
+ xads.setAttributesAsPassword(false);
+ xads.setDatabaseName(null);
+
+ setDatabaseProperty("derby.connection.requireAuthentication", "false");
+ TestConfiguration.getCurrent().shutdownDatabase();
+ }
+
+ /**
+ * Check that traceFile connection attribute functions correctly.
+ * tracefile was tested in checkDriver, but not for DataSources.
+ * tracefile= was used in datasourcepermissions_net, but that's
+ * incorrect syntax. Note that we're not checking the contents of
+ * the tracefile.
+ *
+ * Note also that this test cannot run against a remote server.
+ *
+ * @throws SQLException
+ */
+ public void testClientTraceFileDSConnectionAttribute() throws SQLException
+ {
+ if (usingEmbedded())
+ return;
+
+ String traceFile;
+
+ // DataSource
+ ClientDataSource ds = new ClientDataSource();
+ ds.setDatabaseName(dbName);
+
+ // DataSource - setTransationAttributes
+ traceFile = "trace1.out";
+ ds.setConnectionAttributes("traceFile="+traceFile);
+ // In this scenario, we *only* get a tracefile, if we first get a
+ // successful connection, followed by an unsuccessful connection.
+ // So, we cannot just use ds.getConnection()
+ dsGetBadConnection(ds);
+ ds.setConnectionAttributes(null);
+ // DataSource - setTraceFile
+ traceFile = "trace2.out";
+ ds.setTraceFile(traceFile);
+ ds.getConnection();
+ ds.setTraceFile(null);
+ ds.setDatabaseName(null);
+
+ // now with ConnectionPoolDataSource
+ ClientConnectionPoolDataSource cpds = new ClientConnectionPoolDataSource();
+ cpds.setDatabaseName(dbName);
+
+ traceFile = "trace3.out";
+ cpds.setConnectionAttributes("traceFile="+traceFile);
+ // DERBY-2468 - trace3.out does not get created
+ cpds.getConnection();
+ cpds.setConnectionAttributes(null);
+
+ traceFile = "trace4.out";
+ cpds.setTraceFile(traceFile);
+ cpds.getConnection();
+ cpds.setTraceFile(null);
+ cpds.setDatabaseName(null);
+
+ // now with XADataSource
+ ClientXADataSource xads = new ClientXADataSource();
+ xads.setDatabaseName(dbName);
+
+ traceFile = "trace5.out";
+ xads.setConnectionAttributes("traceFile="+traceFile);
+ xads.getConnection();
+ // DERBY-2468 - trace5.out does not get created
+ xads.setConnectionAttributes(null);
+
+ traceFile = "trace6.out";
+ xads.setTraceFile(traceFile);
+ xads.getConnection();
+ xads.setTraceFile(null);
+ xads.setDatabaseName(null);
+
+ assertTraceFilesExist();
+ }
+
+ /* -- Helper Methods for testClientTraceFileDSConnectionAttribute -- */
+
+ private static void dsGetBadConnection(DataSource ds) {
+ // first get a good connection, or we don't get a
+ // traceFile when using connectionattributes.
+ // also, we do not get a tracefile that way unless
+ // we see an error.
+ // with setTraceFile, we *always* get a file, even
+ // with just a successful connection.
+ try {
+ ds.getConnection();
+ ds.getConnection(null, null);
+ fail("expected an sqlException");
+ } catch (SQLException sqle) {
+ assertSQLState("08001", sqle);
+ }
+ }
+
+ /**
+ * Check that trace file exists in <framework> directory
+ *
+ * @param filename Name of trace file
+ */
+ private static void assertTraceFilesExist()
+ {
+ AccessController.doPrivileged(new java.security.PrivilegedAction() {
+ public Object run() {
+ for (int i=0 ; i < 6 ; i++)
+ {
+ String traceFileName = "trace" + (i+1) + ".out";
+ File traceFile = new File(traceFileName);
+ if (i == 2 || i == 4)
+ continue;
+ else
+ {
+ assertTrue(traceFile.exists());
+ }
+ }
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Check that messageText connection attribute functions correctly.
+ * retrievemessagetext was tested in checkdriver, and derbynet/testij,
+ * but not tested for datasources, and in datasourcepermissions_net,
+ * but as it has nothing to do with permissions/authentication,
+ * this test seems a better place for it.
+ *
+ * @throws SQLException
+ */
+ public void testClientMessageTextConnectionAttribute() throws SQLException
+ {
+ if (usingEmbedded())
+ return;
+
+ String retrieveMessageTextProperty = "retrieveMessageText";
+ Connection conn;
+
+ // DataSource
+ // DataSource - retrieveMessageTextProperty
+ ClientDataSource ds = new ClientDataSource();
+ ds.setDatabaseName(dbName);
+ ds.setConnectionAttributes(retrieveMessageTextProperty + "=false");
+ conn = ds.getConnection();
+ assertMessageText(conn,"false");
+ conn.close();
+ // now try with retrieveMessageText = true
+ ds.setConnectionAttributes(retrieveMessageTextProperty + "=true");
+ conn = ds.getConnection();
+ assertMessageText(conn,"true");
+ ds.setConnectionAttributes(null);
+ conn.close();
+
+ // now with ConnectionPoolDataSource
+ // ConnectionPoolDataSource - retrieveMessageTextProperty
+ ClientConnectionPoolDataSource cpds = new ClientConnectionPoolDataSource();
+ cpds.setDatabaseName(dbName);
+ cpds.setConnectionAttributes(
+ retrieveMessageTextProperty + "=false");
+ conn = cpds.getConnection();
+ assertMessageText(conn,"false");
+ conn.close();
+ cpds.setConnectionAttributes(
+ retrieveMessageTextProperty + "=true");
+ conn = cpds.getConnection();
+ assertMessageText(conn,"true");
+ cpds.setConnectionAttributes(null);
+ conn.close();
+
+ // now with XADataSource
+ ClientXADataSource xads = new ClientXADataSource();
+ //XADataSource - retrieveMessageTextProperty
+ xads.setDatabaseName(dbName);
+ xads.setConnectionAttributes(
+ retrieveMessageTextProperty + "=false");
+ conn = xads.getConnection();
+ assertMessageText(conn,"false");
+ conn.close();
+ xads.setConnectionAttributes(
+ retrieveMessageTextProperty + "=true");
+ conn = xads.getConnection();
+ assertMessageText(conn,"true");
+ conn.close();
+ xads.setConnectionAttributes(null);
+ }
+
+ /* -- Helper Method for testClientMessageTextDSConnectionAttribute -- */
+
+ private static void assertMessageText(
+ Connection conn, String retrieveMessageTextValue)
+ throws SQLException
+ {
+ try {
+ conn.createStatement().executeQuery("SELECT * FROM APP.NOTTHERE");
+ }
+ catch (SQLException e)
+ {
+ assertSQLState("42X05", e);
+ if (retrieveMessageTextValue.equals("true") )
+ {
+ assertTrue(e.getMessage().indexOf("does not exist") >= 0);
+ }
+ else
+ {
+ // retrieveMessageTextValue is false
+ assertTrue(e.getMessage().indexOf("does not exist") == -1);
+ }
+ }
+ }
+
+ /**
+ * Check that messageText connection attribute functions correctly.
+ * retrievemessagetext was tested in checkdriver, and derbynet/testij
+ * (but not tested for datasources), and in datasourcepermissions_net,
+ * but as it has nothing to do with permissions/authentication,
+ * this test seems a better place for it.
+ *
+ * @throws SQLException
+ */
+ public void testClientDescriptionConnectionAttribute()
+ throws SQLException, Exception {
+
+ if (usingEmbedded())
+ return;
+
+ // DataSource
+ String setDescription =
+ "Everything you ever wanted to know about this datasource";
+ String getDescription;
+
+ // DataSource - setDescription
+ ClientDataSource ds = new ClientDataSource();
+ ds.setDatabaseName(dbName);
+ ds.setDescription(setDescription);
+ ds.getConnection();
+ getDescription = ds.getDescription();
+ assertEquals(setDescription, getDescription);
+ ds.setDescription(null);
+
+ // ConnectionPoolDataSource - setDescription
+ ClientConnectionPoolDataSource cpds =
+ new ClientConnectionPoolDataSource();
+ cpds.setDatabaseName(dbName);
+ cpds.setDescription(setDescription);
+ cpds.getConnection();
+ getDescription = cpds.getDescription();
+ assertEquals(setDescription, getDescription);
+ cpds.setDescription(null);
+
+ // XADataSource - setDescription
+ ClientXADataSource xads = new ClientXADataSource();
+ xads.setDatabaseName(dbName);
+ xads.setDescription(setDescription);
+ xads.getConnection();
+ getDescription = xads.getDescription();
+ assertEquals(setDescription, getDescription);
+ xads.setDescription(null);
+ }
+
+ /* ------------------ JDBC30 (and up) Fixtures ------------------ */
+
+ public void testXAHoldability() throws SQLException, XAException {
+ // TODO: figure this out
+ // This test, when run with Network server / DerbyNetClient
+ // leaves the database is a bad state which results in a
+ // network protocol error
+ if (usingDerbyNetClient())
+ return;
+ // START XA HOLDABILITY TEST
+ XADataSource dscsx = J2EEDataSource.getXADataSource();
+ JDBCDataSource.setBeanProperty(dscsx, "databaseName", dbName);
+
+ XAConnection xac = dscsx.getXAConnection();
+ XAResource xr = xac.getXAResource();
+ Xid xid = new cdsXid(25, (byte) 21, (byte) 01);
+ Connection conn1 = xac.getConnection();
+ // check that autocommit is true; default for a connection
+ assertTrue(conn1.getAutoCommit());
+ // check that holdability is HOLD_CURSORS_OVER_COMMIT in a default
+ // CONNECTION(not in xa transaction yet)
+ assertEquals(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT, conn1.getHoldability());
+ // start a global transaction and default holdability and
+ // autocommit will be switched to match Derby XA restrictions
+ xr.start(xid, XAResource.TMNOFLAGS);
+ // So, now autocommit should be false for connection because it is
+ // part of the global transaction
+ assertFalse(conn1.getAutoCommit());
+ // Connection's holdability is now CLOSE_CURSORS_AT_COMMIT because
+ // it is part of the global transaction
+ assertEquals(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT, conn1.getHoldability());
+
+ xr.end(xid, XAResource.TMSUCCESS);
+ conn1.commit();
+ conn1.close();
+
+ xid = new cdsXid(27, (byte) 21, (byte) 01);
+ xr.start(xid, XAResource.TMNOFLAGS);
+ conn1 = xac.getConnection();
+ // CONNECTION(in xa transaction) HOLDABILITY:
+ assertEquals(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT, conn1.getHoldability());
+ // Autocommit on Connection inside global transaction should be false
+ assertFalse(conn1.getAutoCommit());
+ xr.end(xid, XAResource.TMSUCCESS);
+ conn1.rollback();
+
+ Connection conn = xac.getConnection();
+ conn.setAutoCommit(false);
+ conn.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
+ // CONNECTION(non-xa transaction) HOLDABILITY:
+ assertEquals(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT, conn.getHoldability());
+
+ Statement s = conn.createStatement();
+ // STATEMENT HOLDABILITY:
+ assertEquals(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT, s.getResultSetHoldability());
+
+ s.executeUpdate("insert into hold_30 values " +
+ "(1,'init2'), (2, 'init3'), (3,'init3')");
+ s.executeUpdate("insert into hold_30 values " +
+ "(4,'init4'), (5, 'init5'), (6,'init6')");
+ s.executeUpdate("insert into hold_30 values " +
+ "(7,'init7'), (8, 'init8'), (9,'init9')");
+
+ // STATEMENT HOLDABILITY :
+ assertEquals(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT, s.getResultSetHoldability());
+
+ Statement sh = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+ ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ PreparedStatement psh = conn.prepareStatement(
+ "select id from hold_30 for update", ResultSet.TYPE_FORWARD_ONLY,
+ ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ CallableStatement csh = conn.prepareCall(
+ "select id from hold_30 for update", ResultSet.TYPE_FORWARD_ONLY,
+ ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+
+ // STATEMENT HOLDABILITY :
+ assertEquals(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT, sh.getResultSetHoldability());
+ // PREPARED STATEMENT HOLDABILITY :
+ assertEquals(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT, psh.getResultSetHoldability());
+ // CALLABLE STATEMENT HOLDABILITY :
+ assertEquals(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT, csh.getResultSetHoldability());
+
+ ResultSet rsh = sh.executeQuery("select id from hold_30 for update");
+ rsh.next();
+ assertEquals(1, rsh.getInt(1)); // H@1 id
+ rsh.next();
+ assertEquals(2, rsh.getInt(1)); // H@2 id
+ conn.commit();
+ rsh.next();
+ assertEquals(3, rsh.getInt(1)); // H@3 id
+ conn.commit();
+
+ xid = new cdsXid(23, (byte) 21, (byte) 01);
+ xr.start(xid, XAResource.TMNOFLAGS);
+ Statement stmtInsideGlobalTransaction = conn.createStatement();
+ PreparedStatement prepstmtInsideGlobalTransaction =
+ conn.prepareStatement("select id from hold_30");
+ CallableStatement callablestmtInsideGlobalTransaction =
+ conn.prepareCall("select id from hold_30");
+
+ // CONNECTION(xa) HOLDABILITY:
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, conn.getHoldability());
+ // STATEMENT(this one was created with holdability false, outside the
+ // global transaction. Check its holdability inside global transaction
+ assertEquals(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT, s.getResultSetHoldability());
+ // STATEMENT(this one was created with holdability true,
+ // outside the global transaction. Check its holdability inside
+ // global transaction:
+ // TODO: network server / DerbyNetClient has a different value than
+ // embedded. Log a bug or is there one?:
+ if (usingEmbedded())
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ sh.getResultSetHoldability());
+ else if (usingDerbyNetClient())
+ assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ sh.getResultSetHoldability());
+ // STATEMENT(this one was created with default holdability inside this
+ // global transaction. Check its holdability:
+ assertEquals(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ stmtInsideGlobalTransaction.getResultSetHoldability());
+ // PREPAREDSTATEMENT(this one was created with default holdability
+ // inside this global transaction. Check its holdability:
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ prepstmtInsideGlobalTransaction.getResultSetHoldability());
+ // CALLABLESTATEMENT(this one was created with default holdability
+ // inside this global transaction. Check its holdability:
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ callablestmtInsideGlobalTransaction.getResultSetHoldability());
+
+ ResultSet rsx = s.executeQuery("select id from hold_30 for update");
+
+ rsx.next();
+ assertEquals(1, rsx.getInt(1)); // X@1 id
+ rsx.next();
+ assertEquals(2, rsx.getInt(1)); // X@2 id
+ xr.end(xid, XAResource.TMSUCCESS);
+
+ // result set should not be useable, since it is part of a detached
+ // XAConnection
+ try {
+ rsx.next();
+ rsx.getInt(1);
+ fail("rsx's connection not active id ");
+ } catch (SQLException sqle) {
+ assertSQLState("08003", sqle);
+ }
+
+ // result set should not be useable, it should have been closed by
+ // the xa start.
+ try {
+ rsh.next();
+ rsh.getInt(1);
+ fail("rsh's connection not active id ");
+ } catch (SQLException sqle) {
+ if (usingEmbedded())
+ assertSQLState("08003", sqle);
+ else if (usingDerbyNetClient())
+ assertSQLState("XCL16", sqle);
+ }
+
+ // resume XA transaction and keep using rs");
+ xr.start(xid, XAResource.TMJOIN);
+ Statement stmtAfterGlobalTransactionResume = conn.createStatement();
+ PreparedStatement prepstmtAfterGlobalTransactionResume =
+ conn.prepareStatement("select id from hold_30");
+ CallableStatement callablestmtAfterGlobalTransactionResume =
+ conn.prepareCall("select id from hold_30");
+
+ // Check holdability of various jdbc objects after resuming XA
+ // transaction
+ // CONNECTION(xa) HOLDABILITY:
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,conn.getHoldability());
+ // STATEMENT(this one was created with holdability false, outside the
+ // global transaction. Check its holdability inside global transaction
+ assertEquals(
+ ResultSet.CLOSE_CURSORS_AT_COMMIT, s.getResultSetHoldability());
+ // STATEMENT(this one was created with holdability true, outside the
+ // global transaction. Check its holdability inside global transaction
+ if (usingEmbedded())
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ sh.getResultSetHoldability());
+ else if (usingDerbyNetClient())
+ assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ sh.getResultSetHoldability());
+ // STATEMENT(this one was created with default holdability inside the
+ // global transaction when it was first started. Check its holdability
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ stmtInsideGlobalTransaction.getResultSetHoldability());
+ // PREPAREDSTATEMENT(this one was created with default holdability
+ // inside the global transaction when it was first started. Check its
+ // holdability)
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ prepstmtInsideGlobalTransaction.getResultSetHoldability());
+ // CALLABLESTATEMENT(this one was created with default holdability
+ // inside the global transaction when it was first started. Check its
+ // holdability) HOLDABILITY
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ callablestmtInsideGlobalTransaction.getResultSetHoldability());
+ // STATEMENT(this one was created with default holdability after the
+ // global transaction was resumed. Check its holdability
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ stmtAfterGlobalTransactionResume.getResultSetHoldability());
+ // PREPAREDSTATEMENT(this one was created with default holdability
+ // after the global transaction was resumed. Check its holdability
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ prepstmtAfterGlobalTransactionResume.getResultSetHoldability());
+ // CALLABLESTATEMENT(this one was created with default holdability
+ // after the global transaction was resumed. Check its holdability
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ callablestmtAfterGlobalTransactionResume.getResultSetHoldability());
+ // DERBY-1370
+ if (usingEmbedded())
+ {
+ // Network XA BUG gives result set closed
+ rsx.next();
+ assertEquals(3, rsx.getInt(1)); // X@3 id
+ }
+ xr.end(xid, XAResource.TMSUCCESS);
+
+ if (xr.prepare(xid) != XAResource.XA_RDONLY)
+ xr.commit(xid, false);
+
+ // try again once the xa transaction has been committed.
+ try {
+ rsx.next();
+ rsx.getInt(1);
+ fail("rsx's connection not active id (B)");
+ } catch (SQLException sqle) {
+ assertSQLState("XCL16", sqle);
+ }
+ try {
+ rsh.next();
+ rsh.getInt(1);
+ fail ("rsh's should be closed (B)");
+ } catch (SQLException sqle) {
+ assertSQLState("XCL16", sqle);
+ }
+
+ // Set connection to hold
+ conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ // CONNECTION(held) HOLDABILITY:
+ assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT,
+ conn.getHoldability());
+
+ xid = new cdsXid(24, (byte) 21, (byte) 01);
+ xr.start(xid, XAResource.TMNOFLAGS);
+ // CONNECTION(xa) HOLDABILITY:
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, conn.getHoldability());
+ try {
+ conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ fail("allowed to set hold mode in xa transaction");
+ } catch (SQLException sqle) {
+ assertSQLState("XJ05C", sqle);
+ }
+
+ // JDBC 4.0 (proposed final draft) section 16.1.3.1 allows Statements
+ // to be created with a different holdability if the driver cannot
+ // support it. In this case the driver does not support holdability in
+ // a global transaction, so a valid statement is returned with close
+ // cursors on commit.
+ Statement shxa = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+ ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ // HOLDABLE Statement in global xact "
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ s.getResultSetHoldability());
+ assertEquals(10000, conn.getWarnings().getErrorCode());
+ shxa.close();
+
+ shxa = conn.prepareStatement("select id from hold_30",
+ ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
+ ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ // HOLDABLE PreparedStatement in global xact
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ s.getResultSetHoldability());
+ assertEquals(10000, conn.getWarnings().getErrorCode());
+ shxa.close();
+
+ shxa = conn.prepareCall("CALL SYSCS_UTIL.SYSCS_CHECKPOINT_DATABASE()",
+ ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
+ ResultSet.HOLD_CURSORS_OVER_COMMIT);
+ // HOLDABLE CallableStatement in global xact:
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ s.getResultSetHoldability());
+ assertEquals(10000, conn.getWarnings().getErrorCode());
+ shxa.close();
+
+ // check we can use a holdable statement set up in local mode.
+ // holdability is downgraded, tested in XATest.java
+ // DERBY-1370
+ if(usingEmbedded()) {
+ // STATEMENT HOLDABILITY:
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ sh.getResultSetHoldability());
+ sh.executeQuery("select id from hold_30").close();
+ sh.execute("select id from hold_30");
+ sh.getResultSet().close();
+
+ // PREPARED STATEMENT HOLDABILITY:
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ psh.getResultSetHoldability());
+ psh.executeQuery().close();
+ psh.execute();
+ psh.getResultSet().close();
+
+ // CALLABLE STATEMENT HOLDABILITY:
+ assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT,
+ csh.getResultSetHoldability());
+ csh.executeQuery().close();
+ csh.execute();
+ csh.getResultSet().close();
+ }
+
+ // but an update works
+ sh.executeUpdate("insert into hold_30 values(10, 'init10')");
+
+ xr.end(xid, XAResource.TMSUCCESS);
+
+ // CONNECTION(held) HOLDABILITY:
+ assertEquals(
+ ResultSet.HOLD_CURSORS_OVER_COMMIT, conn.getHoldability());
+
+ s.close();
+ sh.close();
+ csh.close();
+ psh.close();
+ rsx.close();
+ stmtInsideGlobalTransaction.close();
+ prepstmtInsideGlobalTransaction.close();
+ callablestmtInsideGlobalTransaction.close();
+ stmtAfterGlobalTransactionResume.close();
+ prepstmtAfterGlobalTransactionResume.close();
+ callablestmtAfterGlobalTransactionResume.close();
+ conn.close();
+ xac.close();
+ TestConfiguration.getCurrent().shutdownDatabase();
+ // END XA HOLDABILITY TEST");
+ }
+
+ /**
+ * Tests for DERBY-1144
+ *
+ * This test tests that holdability, autocomit, and transactionIsolation
+ * are reset on getConnection for PooledConnections obtaind from
+ * connectionPoolDataSources
+ *
[... 1088 lines stripped ...]