/*

   Derby - Class org.apache.derbyTesting.functionTests.tests.jdbcapi.J2EEDataSourceTest

   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.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.security.AccessController;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
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.sql.Savepoint;
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.ClientConnectionPoolDataSourceInterface;
import org.apache.derby.jdbc.ClientDataSourceInterface;
import org.apache.derby.jdbc.ClientXADataSourceInterface;
import org.apache.derby.jdbc.EmbeddedSimpleDataSource;
import org.apache.derbyTesting.functionTests.util.PrivilegedFileOpsForTests;
import org.apache.derbyTesting.functionTests.util.SecurityCheck;
import org.apache.derbyTesting.functionTests.util.TestRoutines;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
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.JDBCClient;
import org.apache.derbyTesting.junit.JDBCDataSource;
import org.apache.derbyTesting.junit.SupportFilesSetup;
import org.apache.derbyTesting.junit.TestConfiguration;

/**
 * Test the ConnectionPoolDataSource and XADataSource implementations of Derby.
 * DataSource functionality common to DataSources including what is
 * supported with JSR169 is tested in DataSourceTest. 
 * 
 * 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 J2EEDataSourceTest extends BaseJDBCTestCase {

    private static final 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();
    
    /** 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 J2EEDataSourceTest(String name) {
        super(name);
    }
    
    /**
     * Return a suite of tests that are run with a lower lock timeout.
     *
     * @param postfix suite name postfix
     * @return A suite of tests being run with a lower lock timeout.
     */
    private static Test getTimeoutSuite(String postfix) {
        TestSuite suite = new TestSuite("Lower lock timeout" + postfix);
        suite.addTest(new J2EEDataSourceTest("timeoutTestDerby1144PooledDS"));
        suite.addTest(new J2EEDataSourceTest("timeoutTestDerby1144XADS"));
        // Reduce the timeout threshold to make the tests run faster.
        return DatabasePropertyTestSetup.setLockTimeouts(suite, 3, 5);
    }
    
    /**
     * Return a suite of tests that are run with both client and embedded
     * 
     * @param postfix suite name postfix
     * @return A suite of tests to be run with client and/or embedded
     */
    private static Test baseSuite(String postfix) {
        TestSuite suite = new TestSuite("ClientAndEmbedded" + postfix);
        suite.addTest(new J2EEDataSourceTest("testGlobalLocalInterleaf"));
        suite.addTest(new J2EEDataSourceTest("testSetIsolationWithStatement"));
        suite.addTest(new J2EEDataSourceTest("testJira95pds"));
        suite.addTest(new J2EEDataSourceTest("testJira95xads"));
        suite.addTest(new J2EEDataSourceTest("testBadConnectionAttributeSyntax"));
        suite.addTest(new J2EEDataSourceTest("testCloseActiveConnection_DS"));
        suite.addTest(new J2EEDataSourceTest("testCloseActiveConnection_CP"));
        suite.addTest(
            new J2EEDataSourceTest("testCloseActiveConnection_XA_local"));
        suite.addTest(
            new J2EEDataSourceTest("testCloseActiveConnection_XA_global"));
        suite.addTest(new J2EEDataSourceTest("testDescriptionProperty"));
        suite.addTest(new J2EEDataSourceTest("testConnectionErrorEvent"));
        suite.addTest(new J2EEDataSourceTest("testIsolationWithFourConnections"));
        suite.addTest(new J2EEDataSourceTest(
                              "testConnectionEventListenerIsNull"));
        suite.addTest(new J2EEDataSourceTest("testReadOnlyToWritableTran"));
        suite.addTest(new J2EEDataSourceTest("testAutoCommitOnXAResourceStart"));
        suite.addTest(new J2EEDataSourceTest("testAllDataSources"));
        suite.addTest(new J2EEDataSourceTest("testClosedCPDSConnection"));
        suite.addTest(new J2EEDataSourceTest("testClosedXADSConnection"));
        suite.addTest(new J2EEDataSourceTest("testSetSchemaInXAConnection"));
        suite.addTest(new J2EEDataSourceTest("testPooledReuseOnClose"));
        suite.addTest(new J2EEDataSourceTest("testSchemaIsReset"));
        suite.addTest(new J2EEDataSourceTest("testSchemaIsResetWhenDeleted"));
        suite.addTest(new J2EEDataSourceTest("testDerby3799"));
        return suite;
    }

    /**
     * Return a suite of tests that are run with client only
     * 
     * @return A suite of tests being run with client only
     */
    private static Test getClientSuite() {
        TestSuite suite = new TestSuite("Client/Server");
        suite.addTest(new J2EEDataSourceTest("testClientDSConnectionAttributes"));
        suite.addTest(new J2EEDataSourceTest(
                "testClientTraceFileDSConnectionAttribute"));
        suite.addTest(new J2EEDataSourceTest(
                "testClientMessageTextConnectionAttribute"));
        suite.addTest(new J2EEDataSourceTest("testConnectionFlowCommit"));
        suite.addTest(new J2EEDataSourceTest("testConnectionFlowCommitAlt"));
        suite.addTest(new J2EEDataSourceTest("testDerby2026LoginTimeout"));
        // Disabled because rollback flow optimization hasn't been implemented.
        // See DERBY-4687
        //suite.addTest(new J2EEDataSourceTest("testConnectionFlowRollbackAlt"));
        return suite;
    }
    
    /**
     * Return a suite of tests that are run with embedded only
     * 
     * @param postfix suite name postfix
     * @return A suite of tests being run with embedded only
     */
    private static Test getEmbeddedSuite(String postfix) {
        TestSuite suite = new TestSuite("Embedded" + postfix);
        suite.addTest(new J2EEDataSourceTest("testDSRequestAuthentication"));
        // Following cannot run with client because of DERBY-2533; it hangs
        // when fixed, this can be moved to baseSuite.
        suite.addTest(new J2EEDataSourceTest("testReuseAcrossGlobalLocal"));
        suite.addTest(new J2EEDataSourceTest("testXAHoldability"));
        return suite;
    }
    
    public static Test suite() {
        if (JDBC.vmSupportsJSR169())
        {
            // test uses unsupported classes like DriverManager, XADataSource,
            // ConnectionPoolDataSource, ConnectionEvenListenere, as well as
            // unsupported methods, like Connection.setTypeMap()...
            TestSuite suite = 
                new TestSuite("J2EEDatasourceTest cannot run with JSR169");
            return suite;
        }
        else
        {
            TestSuite suite = new TestSuite("J2EEDataSourceTest suite");
            // Add tests that will run with both embedded
            suite.addTest(baseSuite(":embedded"));
            //  and network server/client
            suite.addTest(TestConfiguration.clientServerDecorator(
                    baseSuite(":client")));
            // Add the tests that only run with client
            suite.addTest(new SupportFilesSetup(
                    TestConfiguration.clientServerDecorator(getClientSuite())));
            // Add the tests that only run with embedded
            suite.addTest(getEmbeddedSuite("embedded"));
            // Add the tests relying on getting timeouts.
            suite.addTest(getTimeoutSuite(":embedded"));
            suite.addTest(TestConfiguration.clientServerDecorator(
                    getTimeoutSuite(":client")));
            // wrap all in CleanDatabaseTestSetup that creates all database
            // objects any fixture might need.
            // Note that not all fixtures need (all of) these.
            return new CleanDatabaseTestSetup(suite) {
                /**
                 * Create and populate database objects
                 * 
                 * @see org.apache.derbyTesting.junit.CleanDatabaseTestSetup#decorateSQL(java.sql.Statement)
                 */
                protected void decorateSQL(Statement s) throws SQLException {
                    TestRoutines.installRoutines(getConnection());
                    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.J2EEDataSourceTest." +
                            getNestedMethodName() +
                    "'");
                    s.execute("create table derby3799 (dClob clob)");
                    s.executeUpdate("insert into derby3799 values (" +
                            "'myLittleTestClob')");
                }
            };
        }
    }
    
    public void tearDown() throws Exception {
        // 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;
            }
        });
        super.tearDown();
    }

    /* 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();
    }
     */
    
    /**
     * Test case for DERBY-3172
     * When the Derby engine is shutdown or Network Server is brought down, any
     * api on JDBC Connection object should generate a Connection error event.
     */
    public void testConnectionErrorEvent() throws SQLException, Exception
    {
        AssertEventCatcher aes12 = new AssertEventCatcher(12);
        
        ConnectionPoolDataSource ds = J2EEDataSource.getConnectionPoolDataSource();

        PooledConnection pc = ds.getPooledConnection();
        //Add a connection event listener to ConnectionPoolDataSource
        pc.addConnectionEventListener(aes12);
        Connection conn = pc.getConnection();
        
        dropTable(conn, "TAB1");

        //No event should have been generated at this point
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertFalse(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        //Shutdown the Derby engine or Network Server depending on what 
        //mode we are running in.
        if (usingEmbedded())
        {
        	getTestConfiguration().shutdownDatabase();
        } else
        {
        	getTestConfiguration().stopNetworkServer();
        }
        //Now try to use various apis on the JDBC Connection object created 
        //before shutdown and they all should generate connection error event.
        try {
            conn.prepareStatement("CREATE TABLE TAB1(COL1 INT NOT NULL)");
            fail("SQLException should be thrown!");
        } catch (SQLException e) {
            //The first call on JDBC Connection object after Network Server
            //shutdown will generate a communication error and that's why we
            //are checking for SQL State 08006 rather than No current connection
            //SQL State 08003. In embedded mode, we will get SQL State 08003
        	//meaning No current connection
            if (usingEmbedded())
                assertSQLState("08003", e);
            else
                assertSQLState("08006", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.prepareStatement("CREATE TABLE TAB1(COL1 INT NOT NULL)", 1);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
        	int[] columnIndexes = {1};
            conn.prepareStatement("CREATE TABLE TAB1(COL1 INT NOT NULL)", 
            		columnIndexes);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
        	String[] columnNames = {"col1"};
            conn.prepareStatement("CREATE TABLE TAB1(COL1 INT NOT NULL)", 
            		columnNames);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.prepareStatement("CREATE TABLE TAB1(COL1 INT NOT NULL)",
            		ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
                assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.prepareStatement("CREATE TABLE TAB1(COL1 INT NOT NULL)",
            		ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
            		ResultSet.CLOSE_CURSORS_AT_COMMIT);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
                assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.createStatement();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, 
            		ResultSet.CONCUR_READ_ONLY,
            		ResultSet.CLOSE_CURSORS_AT_COMMIT);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
                assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, 
                    ResultSet.CONCUR_READ_ONLY);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.prepareCall("CREATE TABLE TAB1(COL1 INT NOT NULL)",
                    ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
                assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.prepareCall("CREATE TABLE TAB1(COL1 INT NOT NULL)");
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
                assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.prepareCall("CREATE TABLE TAB1(COL1 INT NOT NULL)",
                    ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
                    ResultSet.CLOSE_CURSORS_AT_COMMIT);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
                assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.nativeSQL("CREATE TABLE TAB1(COL1 INT NOT NULL)");
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
                assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.getAutoCommit();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
                assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.setAutoCommit(false);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.getHoldability();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.setHoldability(1);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.commit();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.rollback();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
                assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.setSavepoint();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.setSavepoint("savept1");
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.rollback((Savepoint)null);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.releaseSavepoint((Savepoint)null);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.getTransactionIsolation();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.getWarnings();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.clearWarnings();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.getMetaData();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.isReadOnly();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.setReadOnly(true);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.setCatalog(null);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.getCatalog();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.getTypeMap();
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        try {
            conn.setTypeMap(null);
            fail("SQLException of 08003 should be thrown!");
        } catch (SQLException e) {
            assertSQLState("08003", e);
        }
        assertFalse(aes12.didConnectionClosedEventHappen());
        assertTrue(aes12.didConnectionErrorEventHappen());
        aes12.resetState();
        if (usingEmbedded())
        {
            Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
        }else
        {
        	getTestConfiguration().startNetworkServer();
        }

        // Get a new connection to the database
        conn = getConnection();
        conn.close();
    }

    /**
     * Test that event notification doesn't fail when a null listener has
     * been registered (DERBY-3307).
     */
    public void testConnectionEventListenerIsNull() throws SQLException {
        ConnectionPoolDataSource cpds =
            J2EEDataSource.getConnectionPoolDataSource();
        subtestCloseEventWithNullListener(cpds.getPooledConnection());
        subtestErrorEventWithNullListener(cpds.getPooledConnection());

        XADataSource xads = J2EEDataSource.getXADataSource();
        subtestCloseEventWithNullListener(xads.getXAConnection());
        subtestErrorEventWithNullListener(xads.getXAConnection());
    }

    /**
     * Test that notification of a close event doesn't fail when the
     * listener is null.
     */
    private void subtestCloseEventWithNullListener(PooledConnection pc)
        throws SQLException
    {
        pc.addConnectionEventListener(null);
        // Trigger a close event
        pc.getConnection().close();
        pc.close();
    }

    /**
     * Test that notification of an error event doesn't fail when the
     * listener is null.
     */
    private void subtestErrorEventWithNullListener(PooledConnection pc)
        throws SQLException
    {
        pc.addConnectionEventListener(null);
        Connection c = pc.getConnection();
        // Shut down the database to invalidate all connections
        getTestConfiguration().shutdownDatabase();
        try {
            // Should trigger an error event since the connection is no
            // longer valid
            c.prepareStatement("VALUES 1");
            fail("Statement should fail after database shutdown");
        } catch (SQLException e) {
            if (usingEmbedded()) {
                // No current connection is expected on embedded
                assertSQLState("08003", e);
            } else {
                // The client driver reports communication error
                assertSQLState("08006", e);
            }
        }
        c.close();
        pc.close();
    }

    /**
     * Test that {@code Connection.close()} behaves as expected when the
     * transaction is active (DERBY-3319).
     *
     * @param c the connection to test
     * @param autoCommit the expected auto-commit value. When auto-commit is
     * on, {@code close()} shouldn't fail when the transaction is active.
     * @param global tells whether the connection is part of a global XA
     * transaction. If it is, {@code close()} shouldn't fail, since the
     * transaction can be finished later without using the connection.
     */
    private void testCloseActiveConnection(Connection c, boolean autoCommit,
                                           boolean global)
        throws SQLException
    {
        if (global) {
            assertFalse("auto-commit should be false in XA", autoCommit);
        }
        assertEquals("auto-commit", autoCommit, c.getAutoCommit());
        Statement s = c.createStatement();
        JDBC.assertDrainResults(s.executeQuery("SELECT * FROM SYS.SYSTABLES"));
        s.close();
        try {
            c.close();
            // should not fail in auto-commit or global XA, but should fail
            // otherwise
            assertTrue("close() should fail", autoCommit || global);
        } catch (SQLException e) {
            // no exception expected in auto-commit or global XA, re-throw
            if (autoCommit || global) {
                throw e;
            }
            assertSQLState("25001", e);
        }
        if (!autoCommit && !global) {
            c.rollback();
        }
        c.close();
    }

    /**
     * Test that connections retrieved from {@code DataSource} behave as
     * expected when {@code close()} is called and the transaction is active.
     */
    public void testCloseActiveConnection_DS() throws SQLException {
        DataSource ds = JDBCDataSource.getDataSource();
        testCloseActiveConnection(ds.getConnection(), true, false);
        Connection c = ds.getConnection();
        c.setAutoCommit(false);
        testCloseActiveConnection(c, false, false);
    }

    /**
     * Test that connections retrieved from {@code ConnectionPoolDataSource}
     * behave as expected when {@code close()} is called and the transaction is
     * active.
     */
    public void testCloseActiveConnection_CP() throws SQLException {
        ConnectionPoolDataSource ds =
            J2EEDataSource.getConnectionPoolDataSource();
        PooledConnection pc = ds.getPooledConnection();
        testCloseActiveConnection(pc.getConnection(), true, false);
        Connection c = pc.getConnection();
        c.setAutoCommit(false);
        testCloseActiveConnection(c, false, false);
        pc.close();
    }

    /**
     * Test that connections retrieved from {@code XADataSource} that are not
     * part of a global XA transaction, behave as expected when {@code close()}
     * is called and the transaction is active.
     */
    public void testCloseActiveConnection_XA_local() throws SQLException {
        XADataSource ds = J2EEDataSource.getXADataSource();
        XAConnection xa = ds.getXAConnection();
        testCloseActiveConnection(xa.getConnection(), true, false);
        Connection c = xa.getConnection();
        c.setAutoCommit(false);
        testCloseActiveConnection(c, false, false);
        xa.close();
    }

    /**
     * Test that connections retrieved from {@code XADataSource} that are part
     * of a global XA transaction, behave as expected when {@code close()} is
     * called and the transaction is active.
     */
    public void testCloseActiveConnection_XA_global()
        throws SQLException, XAException
    {
        XADataSource ds = J2EEDataSource.getXADataSource();
        XAConnection xa = ds.getXAConnection();
        XAResource xar = xa.getXAResource();
        Xid xid = new cdsXid(1, (byte) 2, (byte) 3);
        xar.start(xid, XAResource.TMNOFLAGS);
        // auto-commit is always off in XA transactions, so we expect
        // getAutoCommit() to return false without having set it explicitly
        testCloseActiveConnection(xa.getConnection(), false, true);
        Connection c = xa.getConnection();
        c.setAutoCommit(false);
        testCloseActiveConnection(c, false, true);
        xar.end(xid, XAResource.TMSUCCESS);
        xa.close();
    }

    /**
     * Test that a connection to XADataSource can be established
     * successfully while creating a database using setDatabaseName()
     * with create=true
     *  
     * @throws SQLException
     * @throws XAException
     */
    public void testCreateInDatabaseName_XA() throws SQLException, XAException
    {
    	//test with XADataSource
    	XADataSource xads = J2EEDataSource.getXADataSource();
    	String dbName = TestConfiguration.getCurrent().getDefaultDatabaseName();    	
    	J2EEDataSource.setBeanProperty(xads,"databaseName",dbName +";create=true");       
    	XAConnection xa = xads.getXAConnection();
    	Connection c = xa.getConnection();  
    	c.setAutoCommit(false); 
    	c.close();
    }
    
    /**
     * Test that a connection to PoolDataSource can be established
     * successfully while creating a database using setDatabaseName()
     * with create=true
     * 
     * @throws SQLException
     */
    
    public void testCreateInDatabaseName_Pooled() throws SQLException
    {
    	//test with PooledConnection
    	ConnectionPoolDataSource cpds = J2EEDataSource.getConnectionPoolDataSource();
    	PooledConnection pc = cpds.getPooledConnection();
    	String dbName = TestConfiguration.getCurrent().getDefaultDatabaseName();
    	J2EEDataSource.setBeanProperty(cpds, "databaseName",dbName +";create=true");
    	Connection c;
    	c = pc.getConnection();
    	c.setAutoCommit(false);
    	c.close();
    	pc.close();
    }
    
    /**
     * Test that a connection to JDBCDataSource can be established
     * successfully while creating a database using setDatabaseName()
     * with create=true
     * 
     * @throws SQLException
     */
    
    public void testCreateInDatabaseName_DS() throws SQLException
    {
    	DataSource ds = JDBCDataSource.getDataSource();
    	String dbName = TestConfiguration.getCurrent().getDefaultDatabaseName();
    	JDBCDataSource.setBeanProperty(ds, "databaseName", dbName +";create=true");
        Connection c = ds.getConnection();
        c.setAutoCommit(false);
        c.close();
    }
        
    
    /**
     * Test that a PooledConnection can be reused and closed
     * (separately) during the close event raised by the
     * closing of its logical connection.
     * DERBY-2142.
     * @throws SQLException 
     *
     */
    public void testPooledReuseOnClose() throws SQLException
    {
    	// PooledConnection from a ConnectionPoolDataSource
    	ConnectionPoolDataSource cpds =
    		J2EEDataSource.getConnectionPoolDataSource();
    	subtestPooledReuseOnClose(cpds.getPooledConnection());
        subtestPooledCloseOnClose(cpds.getPooledConnection());
        // DERBY-3401 - removing a callback during a close causes problems.
        subtestPooledRemoveListenerOnClose(cpds.getPooledConnection());
        subtestPooledAddListenerOnClose(cpds.getPooledConnection());

    	// PooledConnection from an XDataSource
    	XADataSource xads = J2EEDataSource.getXADataSource();
    	subtestPooledReuseOnClose(xads.getXAConnection());
        subtestPooledCloseOnClose(xads.getXAConnection());
        // DERBY-3401 - removing a callback during a close causes problems.
        subtestPooledRemoveListenerOnClose(xads.getXAConnection());
        subtestPooledAddListenerOnClose(xads.getXAConnection());
    }
    
    /**
     * Tests that a pooled connection can successfully be reused
     * (a new connection obtained from it) during the processing
     * of its close event by its listener.
     * Sections 11.2 & 12.5 of JDBC 4 specification indicate that the
     * connection can be returned to the pool when the
     * ConnectionEventListener.connectionClosed() is called.
     */
    private void subtestPooledReuseOnClose(final PooledConnection pc) throws SQLException
    {
    	final Connection[] newConn = new Connection[1];
    	pc.addConnectionEventListener(new ConnectionEventListener() {

    		/**
    		 * Mimic a pool handler that returns the PooledConnection
    		 * to the pool and then reallocates it to a new logical connection.
    		 */
			public void connectionClosed(ConnectionEvent event) {
				PooledConnection pce = (PooledConnection) event.getSource();
				assertSame(pc, pce);
				try {
					// open a new logical connection and pass
					// back to the fixture.
					newConn[0] = pce.getConnection();
				} catch (SQLException e) {
                    // Need to catch the exception here because
                    // we cannot throw a checked exception through
                    // the api method. Wrap it in a RuntimeException.
                    throw new RuntimeException(e);
				}
			}

			public void connectionErrorOccurred(ConnectionEvent event) {
			}
    		
    	});
    	
    	// Open a connection then close it to trigger the
    	// fetching of a new connection in the callback.
    	Connection c1 = pc.getConnection();
    	c1.close();
    	
    	// Fetch the connection created in the close callback
    	Connection c2 = newConn[0];
    	assertNotNull(c2);
    	
    	// Ensure the connection is useable, this hit a NPE before DERBY-2142
    	// was fixed (for embedded).
    	c2.createStatement().close();
    	
    	pc.close();
    }
    
    /**
     * Tests that a pooled connection can successfully be closed
     * during the processing of its close event by its listener.
     */
    private void subtestPooledCloseOnClose(final PooledConnection pc) throws SQLException
    {
        pc.addConnectionEventListener(new ConnectionEventListener() {

            /**
             * Mimic a pool handler that closes the PooledConnection
             * (say it no longer needs it, pool size being reduced)
             */
            public void connectionClosed(ConnectionEvent event) {
                PooledConnection pce = (PooledConnection) event.getSource();
                assertSame(pc, pce);
                try {
                    pce.close();
                } catch (SQLException e) {
                    // Need to catch the exception here because
                    // we cannot throw a checked exception through
                    // the api method. Wrap it in a RuntimeException.
                    throw new RuntimeException(e);
                }
            }

            public void connectionErrorOccurred(ConnectionEvent event) {
            }
            
        });
        
        // Open and close a connection to invoke the logic above
        // through the callback
        pc.getConnection().close();
                
        // The callback closed the actual pooled connection
        // so subsequent requests to get a logical connection
        // should fail.
        try {
            pc.getConnection();
            fail("PooledConnection should be closed");
        } catch (SQLException sqle) {
            assertSQLState("08003", sqle);
        }
    }
    
    /**
     * Tests that a listener of a pooled connection can successfully
     * remove itself during the processing of its close event by its listener.
     * Failed before DERBY-3401 was fixed.
     */
    private void subtestPooledRemoveListenerOnClose(final PooledConnection pc) throws SQLException
    {
        
        final int[] count1 = new int[1];
        pc.addConnectionEventListener(new ConnectionEventListener() {

            /**
             * Mimic a pool handler that removes the listener during
             * a logical close.
             */
            public void connectionClosed(ConnectionEvent event) {
                PooledConnection pce = (PooledConnection) event.getSource();
                assertSame(pc, pce);
                count1[0]++;
                pce.removeConnectionEventListener(this);
            }

            public void connectionErrorOccurred(ConnectionEvent event) {
            }
            
        });
        
        // and have another listener to ensure removing one leaves
        // the other working and intact.
        final int[] count2 = new int[1];
        pc.addConnectionEventListener(new ConnectionEventListener() {

            /**
             * Mimic a pool handler that closes the PooledConnection
             * (say it no longer needs it, pool size being reduced)
             */
            public void connectionClosed(ConnectionEvent event) {             
                PooledConnection pce = (PooledConnection) event.getSource();
                assertSame(pc, pce);
                count2[0]++;
            }

            public void connectionErrorOccurred(ConnectionEvent event) {
            }
            
        });        
        // no callback yet
        assertEquals(0, count1[0]);
        assertEquals(0, count2[0]);
        
        // Open and close a connection to invoke the logic above
        // through the callback
        pc.getConnection().close();
        
        // one callback for each
        assertEquals(1, count1[0]);
        assertEquals(1, count2[0]);
              
        // the callback (count1) that was removed is not called on the
        // second close but the second callback (count2) is called.
        pc.getConnection().close();
        assertEquals(1, count1[0]);
        assertEquals(2, count2[0]);
        
        pc.close();
    }

    /**
     * Tests that a listener of a pooled connection can successfully add
     * another listener when processing a close event. Failed before DERBY-3401
     * was fixed.
     */
    private void subtestPooledAddListenerOnClose(final PooledConnection pc)
            throws SQLException {

        // Holder for the two counts { number of times the main listener
        // has been triggered, number of times added listeners have been
        // triggered }.
        final int[] count = new int[2];

        // Register the main listener
        pc.addConnectionEventListener(new ConnectionEventListener() {

            public void connectionClosed(ConnectionEvent event) {
                assertSame(pc, event.getSource());
                count[0]++;
                // Register a new listener
                pc.addConnectionEventListener(new ConnectionEventListener() {
                    public void connectionClosed(ConnectionEvent e) {
                        assertSame(pc, e.getSource());
                        count[1]++;
                    }
                    public void connectionErrorOccurred(ConnectionEvent e) {
                    }
                });
            }

            public void connectionErrorOccurred(ConnectionEvent event) {
            }
        });

        // Number of times we expect the added listener to have been called.
        int expectedAdded = 0;

        // Trigger some close events and check the count between each event.
        for (int i = 0; i < 5; i++) {
            assertEquals("close count (main)", i, count[0]);
            assertEquals("close count (added)", expectedAdded, count[1]);

            // In the next iteration, we expect that the number of times the
            // listeners added by the main listener have been called, has
            // increased by the number of times the main listener has been
            // called (i).
            expectedAdded = expectedAdded + i;

            // Trigger a close event
            pc.getConnection().close();
        }

        pc.close();
    }

    public void testAllDataSources() throws SQLException, Exception
    {
        Connection dmc = getConnection();
        CallableStatement cs = dmc.prepareCall("call checkConn2(?)");
        cs.setString(1,"Nested");
        try {
            cs.execute();
            fail("SQLException of 40XC0 should be thrown!");
        } catch (SQLException sqle) {
            assertSQLState("40XC0", sqle);
        }
        cs.setString(1,"Nested2");
        cs.execute();
        
        String EmptyMapValue = "OK";
        String NullMapValue = "XJ081";
        String 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();
        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();      
        
        if (usingEmbedded()) 
            assertToString(dsp);

        PooledConnection pc = dsp.getPooledConnection();
        // checks currently only implemented for embedded 
        if (usingEmbedded())
        {
            SecurityCheck.assertSourceSecurity(
                pc, "javax.sql.PooledConnection");
        }
        AssertEventCatcher aes1 = new AssertEventCatcher(1);
        pc.addConnectionEventListener(aes1);

        // DERBY-2531
        // with Network Server / DerbyNetClient, the assertConnectionOK check
        // returns a different connection object...
        assertConnectionOK(
            expectedValues, "ConnectionPoolDataSource", pc.getConnection());
        //Check if got connection closed event but not connection error event
        assertTrue(aes1.didConnectionClosedEventHappen());
        assertFalse(aes1.didConnectionErrorEventHappen());
        aes1.resetState();
        assertConnectionOK(
            expectedValues, "ConnectionPoolDataSource", pc.getConnection());
        //Check if got connection closed event but not connection error event
        assertTrue(aes1.didConnectionClosedEventHappen());
        assertFalse(aes1.didConnectionErrorEventHappen());
        aes1.resetState();

        XADataSource dsx = J2EEDataSource.getXADataSource();

        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();
            fail("SQLException of 40XC0 should be thrown!");
        } 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");
        }
        AssertEventCatcher aes3 = new AssertEventCatcher(3);
        xac.addConnectionEventListener(aes3);
        assertConnectionOK(
            expectedValues, "XADataSource", xac.getConnection());
        //Check if got connection closed event but not connection error event
        assertTrue(aes3.didConnectionClosedEventHappen());
        assertFalse(aes3.didConnectionErrorEventHappen());
        aes3.resetState();
                       
        pc = dsp.getPooledConnection();
        AssertEventCatcher aes2 = new AssertEventCatcher(2);
        pc.addConnectionEventListener(aes2);
        assertConnectionOK(
            expectedValues, "ConnectionPoolDataSource", pc.getConnection());
        //Check if got connection closed event but not connection error event
        assertTrue(aes2.didConnectionClosedEventHappen());
        assertFalse(aes2.didConnectionErrorEventHappen());
        aes2.resetState();

        // test "local" XAConnections
        xac = dsx.getXAConnection();
        AssertEventCatcher aes4 = new AssertEventCatcher(4);
        xac.addConnectionEventListener(aes4);
        assertConnectionOK(
            expectedValues, "XADataSource", xac.getConnection());
        //Check if got connection closed event but not connection error event
        assertTrue(aes4.didConnectionClosedEventHappen());
        assertFalse(aes4.didConnectionErrorEventHappen());
        aes4.resetState();
        assertConnectionOK(
            expectedValues, "XADataSource", xac.getConnection());
        //Check if got connection closed event but not connection error event
        assertTrue(aes4.didConnectionClosedEventHappen());
        assertFalse(aes4.didConnectionErrorEventHappen());
        aes4.resetState();
        xac.close();

        // test "global" XAConnections
        xac = dsx.getXAConnection();
        AssertEventCatcher aes5 = new AssertEventCatcher(5);
        xac.addConnectionEventListener(aes5);
        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());
        //Check if got connection closed event but not connection error event
        assertTrue(aes5.didConnectionClosedEventHappen());
        assertFalse(aes5.didConnectionErrorEventHappen());
        aes5.resetState();
        assertConnectionOK(
            expectedValues, "Global XADataSource", xac.getConnection());
        //Check if got connection closed event but not connection error event
        assertTrue(aes5.didConnectionClosedEventHappen());
        assertFalse(aes5.didConnectionErrorEventHappen());
        aes5.resetState();

        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());
        //Check if got connection closed event but not connection error event
        assertTrue(aes5.didConnectionClosedEventHappen());
        assertFalse(aes5.didConnectionErrorEventHappen());
        aes5.resetState();
        assertConnectionOK(expectedValues, 
            "Switch to local XADataSource", xac.getConnection());
        //Check if got connection closed event but not connection error event
        assertTrue(aes5.didConnectionClosedEventHappen());
        assertFalse(aes5.didConnectionErrorEventHappen());
        aes5.resetState();

        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);
        //Check if got connection closed event but not connection error event
        assertTrue(aes5.didConnectionClosedEventHappen());
        assertFalse(aes5.didConnectionErrorEventHappen());
        aes5.resetState();
        assertConnectionOK(expectedValues, 
            "Switch to global XADataSource", xac.getConnection());
        //Check if got connection closed event but not connection error event
        assertTrue(aes5.didConnectionClosedEventHappen());
        assertFalse(aes5.didConnectionErrorEventHappen());
        aes5.resetState();
        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();       
        PooledConnection pc = dsp.getPooledConnection();
        Connection c1 = pc.getConnection();
        Statement s = c1.createStatement();
        // start by deleting all rows from intTable
        s.executeUpdate("delete from intTable");
        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();
        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.

        XADataSource dsx = J2EEDataSource.getXADataSource();
        XAConnection xac = dsx.getXAConnection();
        AssertEventCatcher aes6 = new AssertEventCatcher(6);
        xac.addConnectionEventListener(aes6);
        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;
        // see DERBY-911, ReadOnly state different for Embedded/DerbyNetClient
        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
        //Confirm - no connection closed event & connection error event
        assertFalse(aes6.didConnectionClosedEventHappen());
        assertFalse(aes6.didConnectionErrorEventHappen());
        aes6.resetState();
        cs1.close();
        //Check if got connection closed event but not connection error event
        assertTrue(aes6.didConnectionClosedEventHappen());
        assertFalse(aes6.didConnectionErrorEventHappen());
        aes6.resetState();
        
        cs1 = xac.getConnection();
        // new handle - local
        assertConnectionState(
            ResultSet.HOLD_CURSORS_OVER_COMMIT, 
            Connection.TRANSACTION_READ_COMMITTED,
            true, false, cs1);
        cs1.close();
        //Check if got connection closed event but not connection error event
        assertTrue(aes6.didConnectionClosedEventHappen());
        assertFalse(aes6.didConnectionErrorEventHappen());
        aes6.resetState();
        
        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);
        //Check if got connection closed event but not connection error event
        assertTrue(aes6.didConnectionClosedEventHappen());
        assertFalse(aes6.didConnectionErrorEventHappen());
        aes6.resetState();

        // 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);
        //Confirm - no connection closed event & connection error event
        assertFalse(aes6.didConnectionClosedEventHappen());
        assertFalse(aes6.didConnectionErrorEventHappen());
        aes6.resetState();
        cs1.close();
        //Check if got connection closed event but not connection error event
        assertTrue(aes6.didConnectionClosedEventHappen());
        assertFalse(aes6.didConnectionErrorEventHappen());
        aes6.resetState();
    }
    
    // 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();
        XAConnection xac = dsx.getXAConnection();
        AssertEventCatcher aes6 = new AssertEventCatcher(6);
        xac.addConnectionEventListener(aes6);
        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);
        //DERBY-4314 create a statement(s2) and execute ddl sql
        Statement s2 = conn.createStatement();
        s2.executeUpdate("create table testglobal (i int)");
        //DERBY-4314 end test
        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);
        //Confirm - no connection closed event & connection error event
        assertFalse(aes6.didConnectionClosedEventHappen());
        assertFalse(aes6.didConnectionErrorEventHappen());
        aes6.resetState();
    }

    // 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 {

        // DERBY-2533 -
        // network server cannot run this test - it hits a protocol error
        // on tearDown. Embedded requires a database shutdown
        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();
        XAConnection xac = dsx.getXAConnection();
        AssertEventCatcher aes6 = new AssertEventCatcher(6);
        xac.addConnectionEventListener(aes6);
        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();
        //Confirm - no connection closed event & connection error event
        assertFalse(aes6.didConnectionClosedEventHappen());
        assertFalse(aes6.didConnectionErrorEventHappen());
        aes6.resetState();

        // attach the XA transaction to another connection and see what happens
        XAConnection xac2 = dsx.getXAConnection();
        AssertEventCatcher aes5 = new AssertEventCatcher(5);
        xac2.addConnectionEventListener(aes5);
        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);
        //Confirm - no connection closed event & connection error event
        assertFalse(aes5.didConnectionClosedEventHappen());
        assertFalse(aes5.didConnectionErrorEventHappen());
        aes5.resetState();
        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 {
            // (DERBY-2532)
            xac2.getXAResource();
            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();
    }

    /**
     * Verifies that the schema is reset when creating a new logical connection.
     * <p>
     * The test is run in a non-statement pooling configuration first,
     * and then with statement pooling enabled if the environment supports it.
     * <p>
     * Relevant Jira issue: DERBY-3690.
     * <p>
     * The current role also needs to be reset, but can't be tested here since
     * we need to run with SQL authorization.
     *
     * @see org.apache.derbyTesting.functionTests.tests.lang.RolesTest#testCurrentRoleIsReset
     *
     * @throws SQLException if something goes wrong
     */
    public void testSchemaIsReset()
            throws SQLException {
        final String userSchema = "USERSCHEMA";
        ConnectionPoolDataSource cpDs =
                J2EEDataSource.getConnectionPoolDataSource();
        J2EEDataSource.setBeanProperty(cpDs, "createDatabase", "create");
        // Connect with a user specified, which should cause the schema to be
        // set to the user name.
        // Test without statement pooling first.
        doTestSchemaIsReset(cpDs.getPooledConnection(userSchema, "secret"),
                userSchema);

        // Try to enable statement pooling.
        // This is currently only implemented in the client driver.
        if (usingDerbyNetClient()) {
            J2EEDataSource.setBeanProperty(
                    cpDs, "maxStatements",new Integer(7));
            doTestSchemaIsReset(cpDs.getPooledConnection(userSchema, "secret"),
                    userSchema);
        }
    }

    /**
     * Executes a test sequence to make sure the schema (and with DERBY-4551,
     * current user) is correctly reset between logical connections.
     *
     * @param pc pooled connection to get logical connections from
     * @param userSchema name of the default schema for the connection (user)
     * @throws SQLException if something goes wrong...
     */
    private void doTestSchemaIsReset(PooledConnection pc, String userSchema)
            throws SQLException {
        Connection con1 = pc.getConnection();
        JDBC.assertCurrentSchema(con1, userSchema);
        JDBC.assertCurrentUser(con1, userSchema);
        Statement stmt1 = con1.createStatement();
        // Change the schema.
        stmt1.execute("set schema APP");
        stmt1.close();
        JDBC.assertCurrentSchema(con1, "APP");
        JDBC.assertCurrentUser(con1, userSchema);
        // Close the logical connection and get a new one.
        con1.close();
        Connection con2 = pc.getConnection();
        // Make sure the schema has been reset from APP to the user name.
        JDBC.assertCurrentSchema(con2, userSchema);
        JDBC.assertCurrentUser(con2, userSchema);
        con2.close();
        // Try a third time, but don't change the schema now.
        Connection con3 = pc.getConnection();
        JDBC.assertCurrentSchema(con3, userSchema);
        JDBC.assertCurrentUser(con3, userSchema);
        con3.close();
        pc.close();
    }

    /**
     * Tests that deleting the current / default schema doesn't cause the next
     * logical connection to fail.
     * <p>
     * Relevant Jira issue: DERBY-3690.
     *
     * @throws SQLException if something goes wrong
     */
    public void testSchemaIsResetWhenDeleted()
            throws SQLException {
        final String userSchema = "AUSER";
        ConnectionPoolDataSource cpDs =
                J2EEDataSource.getConnectionPoolDataSource();
        J2EEDataSource.setBeanProperty(cpDs, "createDatabase", "create");
        PooledConnection pc = cpDs.getPooledConnection(userSchema, "secret");
        // Get first connection, create a table, then drop schema.
        Connection con = pc.getConnection();
        JDBC.assertCurrentSchema(con, userSchema);
        Statement stmt = con.createStatement();
        stmt.executeUpdate("create table schematest (id int)");
        stmt.executeUpdate("drop table schematest");
        stmt.executeUpdate("drop schema " + userSchema + " restrict");
        stmt.close();
        con.close();
        // Get second connection.
        con = pc.getConnection();
        JDBC.assertCurrentSchema(con, userSchema);
        stmt = con.createStatement();
        stmt.executeUpdate("create table schematest (id int)");
        stmt.executeUpdate("drop table schematest");
        stmt.close();
        JDBC.assertCurrentSchema(con, userSchema);
        con.close();
        pc.close();
    }
    /**
     * check whether commit without statement will flow by checking its transaction id
     * on client. This test is run only for client where commits without an
     * active transactions will not flow to the server.
     * DERBY-4653
     * 
     * @throws SQLException
     **/
    public void testConnectionFlowCommit()
            throws SQLException {
        ConnectionPoolDataSource ds = J2EEDataSource.getConnectionPoolDataSource();

        PooledConnection pc = ds.getPooledConnection();
        Connection conn = pc.getConnection();

        testConnectionFlowCommitWork(conn);
        conn.close();
        
        //Test for XADataSource
        XADataSource xs = J2EEDataSource.getXADataSource();
        XAConnection xc = xs.getXAConnection();
        conn = xc.getConnection();
        testConnectionFlowCommitWork(conn);
        conn.close();
        
        //Test for DataSource
        DataSource jds = JDBCDataSource.getDataSource();
        conn = jds.getConnection();
        testConnectionFlowCommitWork(conn);
        conn.close();       
    }

    /**
     * DERBY-2026 - Make sure login timeout does not impact 
     * queries.
     */
    public void testDerby2026LoginTimeout() throws SQLException {
        DataSource jds = null;
        try {
            jds = JDBCDataSource.getDataSource();
            jds.setLoginTimeout(10);
            Connection conn = jds.getConnection();
            CallableStatement cs = conn.prepareCall("CALL TESTROUTINE.SLEEP(20000)");
            cs.execute();
            //rollback to make sure our connection is ok.
            conn.rollback();
        } finally {
            if (jds != null)
                jds.setLoginTimeout(0);
        }

        ConnectionPoolDataSource cpds = null;
        try {
            cpds = J2EEDataSource.getConnectionPoolDataSource();        
            cpds.setLoginTimeout(10);
            PooledConnection pc = cpds.getPooledConnection();
            Connection conn = pc.getConnection();
            CallableStatement cs = conn.prepareCall("CALL TESTROUTINE.SLEEP(20000)");
            cs.execute();
            //rollback to make sure our connection is ok.
            conn.rollback();

            // Close the logical connection and get a new one.
            // This will invoke reset which also needs its timeout reset
            conn.close();
            conn = pc.getConnection();
            cs = conn.prepareCall("CALL TESTROUTINE.SLEEP(20000)");
            cs.execute();
            //rollback to make sure our connection is ok.
            conn.rollback();
        } finally {
            if (cpds != null)
                cpds.setLoginTimeout(0);
        }

        XADataSource xads = null;
        try {
            xads = J2EEDataSource.getXADataSource();        
            xads.setLoginTimeout(10);
            XAConnection xac = xads.getXAConnection();
            Connection conn = xac.getConnection();
            CallableStatement cs = conn.prepareCall("CALL TESTROUTINE.SLEEP(20000)");
            cs.execute();
            //rollback to make sure our connection is ok.
            conn.rollback();

            // Close the logical connection and get a new one.
            // This will invoke reset which also needs its timeout reset
            conn.close();
            conn = xac.getConnection();
            cs = conn.prepareCall("CALL TESTROUTINE.SLEEP(20000)");
            cs.execute();
            //rollback to make sure our connection is ok.
            conn.rollback();
        } finally {
            if (xads != null)
                xads.setLoginTimeout(0);
        }
    }
    
    /**
     * Doing the work for test Connection.flowcommit() and Connection.flowrollback()
     * @param conn
     * @throws SQLException
     **/  
    private void testConnectionFlowCommitWork(Connection conn) throws SQLException {
        //DERBY 4653 - make sure commit with no work does not flow in client
        conn.setAutoCommit(false);
        int startXactId = getClientTransactionID(conn);
        Statement s = conn.createStatement();
        ResultSet rs = s.executeQuery("values 1");
        rs.next();
        assertEquals(1, rs.getInt(1));
        rs.close();
        conn.commit();
        // second commit should not flow
        conn.commit();
        int endXactId = getClientTransactionID(conn);
        
        //to verify the fix for DERBY-4653. Only one transaction
        assertTrue("Should have had 1 xact, startXactId = "
                    + startXactId + " endXactId = " + endXactId ,
                    ((endXactId - startXactId) == 1) );
        
        s.close();
    }

    /**
     * Alternative test for making sure "redundant" rollbacks, i.e. rollbacks
     * invoked when no transaction is in progress, don't result in a rollback
     * command being flowed to the server.
     *
     * @throws IOException if reading/parsing the trace file fails
     * @throws SQLException if something goes wrong
     */
    public void testConnectionFlowRollbackAlt()
            throws IOException, SQLException {
        Object[] dataSources = new Object[] {
            JDBCDataSource.getDataSource(),
            J2EEDataSource.getConnectionPoolDataSource(),
            J2EEDataSource.getXADataSource()
        };
        for (int i=0; i < dataSources.length; i++) {
            Object ds = dataSources[i];
            // Run test sequence without invoking extra rollbacks.
            int flowsBase = testConnectionFlowCommitRollback(ds, false, false);
            // Run test sequence with extra rollbacks - these should not result
            // in a rollback command being flowed to the server.
            int flowsExtra = testConnectionFlowCommitRollback(ds, true, false);
            assertEquals("Rollback optimization not working for connections " +
                    "originating from " + ds.getClass().getName(),
                    flowsBase, flowsExtra);
        }
    }

    /**
     * Alternative test for making sure "redundant" commits, i.e. commits
     * invoked when no transaction is in progress, don't result in a commit
     * command being flowed to the server.
     *
     * @throws IOException if reading/parsing the trace file fails
     * @throws SQLException if something goes wrong
     */
    public void testConnectionFlowCommitAlt()
            throws IOException, SQLException {
        Object[] dataSources = new Object[] {
            JDBCDataSource.getDataSource(),
            J2EEDataSource.getConnectionPoolDataSource(),
            J2EEDataSource.getXADataSource()
        };
        for (int i=0; i < dataSources.length; i++) {
            Object ds = dataSources[i];
            // Run test sequence without invoking extra commits.
            int flowsBase = testConnectionFlowCommitRollback(ds, false, true);
            // Run test sequence with extra commits - these should not result in
            // a commit command being flowed to the server.
            int flowsExtra = testConnectionFlowCommitRollback(ds, true, true);
            assertEquals("Commit optimization not working for connections " +
                    "originating from " + ds.getClass().getName(),
                    flowsBase, flowsExtra);
        }
    }

    /**
     * Performs a test sequence accessing the server, then parses the client
     * connection trace file to obtain the number of commit or rollback
     * commands flowed from the client to the server.
     *
     * @param ds data source used to obtain a connection to the database
     *      (must be using the test framework defaults)
     * @param invokeExtra if {@code true} extra invocations of either commit or
     *      rollback are performed (depending on value of {@code isCommit})
     * @param isCommit if {@code true}, commits are invoked, otherwise
     *      rollbacks are invoked
     * @return The number of wire flows detected (depending on value of
     *      {@code isCommit}).
     * @throws IOException if reading/parsing the trace file fails
     * @throws SQLException if something goes wrong
     */
    private int testConnectionFlowCommitRollback(
                            Object ds, boolean invokeExtra, boolean isCommit)
            throws IOException, SQLException {
        final int extraInvokations = invokeExtra ? 25 : 0;
        final int rowCount = 10;
        final boolean isXA = ds instanceof XADataSource;
        final boolean isCP = ds instanceof ConnectionPoolDataSource;
        // Generate trace file name and define trace behavior.
        String dsType = (isXA ? "xa_" : (isCP ? "cp_" : ""));
        String tbl = "ds_" + dsType +
                (invokeExtra ? "base_" : "extra_") +
                (isCommit ? "commit" : "rollback");
        File traceFile = SupportFilesSetup.getReadWrite(tbl + ".trace");
        J2EEDataSource.setBeanProperty(ds, "traceFile",
                PrivilegedFileOpsForTests.getAbsolutePath(traceFile));
        J2EEDataSource.setBeanProperty(ds, "traceFileAppend", Boolean.FALSE);
        J2EEDataSource.setBeanProperty( ds, "traceLevel",
                new Integer(ClientDataSourceInterface.TRACE_ALL));

        // Obtain connection.
        PooledConnection physicalCon = null;
        Connection con;
        if (isXA) {
            physicalCon = ((XADataSource)ds).getXAConnection();
            con = physicalCon.getConnection();
        } else if (isCP) {
            physicalCon = ((ClientConnectionPoolDataSourceInterface)ds).
                    getPooledConnection();
            con = physicalCon.getConnection();
        } else {
            con = ((DataSource)ds).getConnection();
        }
        con.setAutoCommit(false);

        // Run test sequence.
        // step 0: create table
        Statement stmt = con.createStatement();
        stmt.executeUpdate("create table " + tbl + " (id int)");
        con.commit(); // Unconditional commit to persist table
        endTranscation(con, isCommit, extraInvokations);
        // step 1: insert data
        PreparedStatement ps =
                con.prepareStatement("insert into " + tbl + " values (?)");
        for (int i=0; i < rowCount; i++) {
            ps.setInt(1, i);
            ps.executeUpdate();
            endTranscation(con, isCommit, extraInvokations);
        }
        ps.close();
        // Unconditional commit, should catch "missed" rollbacks above when we
        // do a select with another connection at the end.
        con.commit();
        // step 2: select data
        ResultSet rs = stmt.executeQuery("select count(*) from " + tbl);
        rs.next();
        rs.getInt(1);
        rs.close();
        endTranscation(con, isCommit, extraInvokations);
        // step 3: values clause
        rs = stmt.executeQuery("values 7");
        assertTrue(rs.next());
        assertEquals(7, rs.getInt(1));
        rs.close();
        stmt.close();
        endTranscation(con, isCommit, extraInvokations);
        con.close();
        if (physicalCon != null) {
            physicalCon.close();
        }

        // step 4: table content validation
        stmt = createStatement();
        rs = stmt.executeQuery("select count(*) from " + tbl);
        rs.next();
        assertEquals("Potential COMMIT/ROLLBACK protocol error",
                isCommit ? rowCount : 0, rs.getInt(1));

        // Parse the trace file for commits or rollbacks.
        String token = "SEND BUFFER: " + (isXA ? "SYNCCTL" :
            (isCommit ? "RDBCMM" : "RDBRLLBCK"));
        int tokenCount = 0;
        BufferedReader r = new BufferedReader(
                PrivilegedFileOpsForTests.getFileReader(traceFile));
        String line;
        while ((line = r.readLine()) != null) {
            if (line.startsWith("[derby]") && line.indexOf(token) != -1) {
                println((isCommit ? "COMMIT: " : "ROLLBACK: ") + line);
                tokenCount++;
            }
        }
        r.close();
        assertTrue("Parsing failed, no COMMITS/ROLLBACKS detected",
                tokenCount > 0);
        println(ds.getClass().getName() + ", invokeExtra=" + invokeExtra +
                ", isCommit=" + isCommit + ", tokenCount=" + tokenCount);
        return tokenCount;
    }

    /**
     * Ends a transaction by invoking at least one commit or rollback.
     *
     * @param con the connection to work on
     * @param isCommit if {@code true} commit is invoked, otherwise rollback
     *      is invoked
     * @param count the number of extra commits or rollbacks to invoke
     * @throws SQLException if a commit/rollback fails
     */
    private void endTranscation(Connection con, boolean isCommit, int count)
            throws SQLException {
        if (isCommit) {
            con.commit();
            for (int i=0; i < count; i++) {
                con.commit();
            }
        } else {
            con.rollback();
            for (int i=0; i < count; i++) {
                con.rollback();
            }
        }
    }

    /**
     * Check setTransactioIsolation and with four connection in connection pool
     * for DERBY-4343 case
     * 
     * @throws SQLException
     */
    public void testIsolationWithFourConnections()
            throws SQLException {
        ConnectionPoolDataSource ds = J2EEDataSource.getConnectionPoolDataSource();

        PooledConnection pc = ds.getPooledConnection();
        //First connection
        Connection conn = pc.getConnection();
        conn.setAutoCommit(false);
        conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
        Statement s = conn.createStatement();
        ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM SYS.SYSTABLES");
        rs.next();
        int ri = rs.getInt(1);
        rs.close();
        conn.rollback();
        conn.close();
        
        //Second connection
        conn = pc.getConnection();
        conn.close();
        
        //Third connection
        conn = pc.getConnection();
        conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
        assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation());
        conn.close();
        
        //Fourth connetion
        conn = pc.getConnection();
        conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
        assertEquals(Connection.TRANSACTION_READ_UNCOMMITTED, conn.getTransactionIsolation());
        conn.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.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
        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
        xac4.getXAResource().start(xid4a, XAResource.TMNOFLAGS);
        xac4.getXAResource().end(xid4a, XAResource.TMSUCCESS);

        try {
            rs4.next();
            fail ("expected an exception indicating resultset is closed.");
        } catch (SQLException sqle) {
            // Embedded gets 08003. No current connection (DERBY-2620)        	
        	if (usingDerbyNetClient())
        		assertSQLState("XCL16",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);
        }
        
        rs4.next();
        assertEquals(3, rs4.getInt(1));
        rs4.close();

        conn4.rollback();
        conn4.close();
        xac4.close();
    }

    public void testReadOnlyToWritableTran() throws SQLException, Exception
    {
        // This fixture will run twice, once with embedded, once with client,
        // and insert 2 rows in addition to the 5 rows inserted during setup. 
        // The fixture tests a commit, so before running, try to remove row 
        // 6 and 7 in case this is the second run of the fixture.
        Statement s = createStatement();
        s.executeUpdate("delete from autocommitxastart where i = 6");
        s.executeUpdate("delete from autocommitxastart where i = 7");
        
        // 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();
        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   
    // with ConnectionPoolDataSource
    public void testJira95pds() throws Exception {
        try {
            ConnectionPoolDataSource pds = J2EEDataSource.getConnectionPoolDataSource();
            JDBCDataSource.setBeanProperty(pds, "databaseName", "jdbc:derby:boo");
            pds.getPooledConnection();
            fail ("expected an SQLException!");
        } catch (SQLException sqle) {
            assertSQLState("XCY00", sqle);
        } catch (Exception e) {
            throw e;
        }
    }
    
    // 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);
        }
    }
    
    // there is a corresponding fixture for datasources in DataSourceTest
    public void testBadConnectionAttributeSyntax() throws SQLException {
        
        // ConnectionPoolDataSource - bad connatr syntax
        ConnectionPoolDataSource cpds = J2EEDataSource.getConnectionPoolDataSource();
        JDBCDataSource.setBeanProperty(cpds, "ConnectionAttributes", "bad");
        try {
            cpds.getPooledConnection();
            fail ("should have seen an error");
        } catch (SQLException e) {
            assertSQLState("XJ028", e);
        } 

        // XADataSource - bad connattr syntax");
        XADataSource xads = J2EEDataSource.getXADataSource();
        JDBCDataSource.setBeanProperty(xads, "ConnectionAttributes", "bad");
        try {
            xads.getXAConnection();
            fail ("should have seen an error");
        } catch (SQLException e) {
            assertSQLState("XJ028", e);
        } 
    } // 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, ClassNotFoundException,
            IllegalAccessException, InstantiationException {
        if (usingEmbedded())
            return;

        // now with ConnectionPoolDataSource
        ClientConnectionPoolDataSourceInterface cpds;

        if (JDBC.vmSupportsJNDI()) {
            cpds = (ClientConnectionPoolDataSourceInterface)Class.forName(
               "org.apache.derby.jdbc.ClientConnectionPoolDataSource").
                    newInstance();
        } else {
            cpds = (ClientConnectionPoolDataSourceInterface)Class.forName(
               "org.apache.derby.jdbc.BasicClientConnectionPoolDataSource40").
                    newInstance();
        }

        cpds.setPortNumber(TestConfiguration.getCurrent().getPort());
        
        // ConnectionPoolDataSource - EMPTY
        dsCPConnectionRequests(new String[]
            {"08001","08001","08001","08001",
             "08001","08001","08001","08001","08001"}, 
            cpds);

        // ConnectionPoolDataSource 
        // - connectionAttributes=databaseName=<valid dbname>
        cpds.setConnectionAttributes("databaseName=" + dbName);
        dsCPConnectionRequests(new String[]
            {"08001","08001","08001","08001",
             "08001","08001","08001","08001","08001"},
            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);
        dsCPConnectionRequests(new String[]
            {"OK","08001","OK","OK","08001","08001","OK","OK","OK"},
            cpds);
        cpds.setConnectionAttributes(null);
        cpds.setDatabaseName(null);

        // now with XADataSource
        ClientXADataSourceInterface xads;
        
        if (JDBC.vmSupportsJNDI()) {
            xads = (ClientXADataSourceInterface)Class.forName(
                "org.apache.derby.jdbc.ClientXADataSource").
                    newInstance();
        } else {
            xads = (ClientXADataSourceInterface)Class.forName(
                "org.apache.derby.jdbc.BasicClientXADataSource40").
                    newInstance();
        }

        xads.setPortNumber(TestConfiguration.getCurrent().getPort());
        
        // XADataSource - EMPTY
        dsXAConnectionRequests(new String[]
            {"08001","08001","08001","08001",
             "08001","08001","08001","08001","08001"}, 
            xads);

        // XADataSource - connectionAttributes=databaseName=<valid dbname>
        xads.setConnectionAttributes("databaseName=wombat");
        dsXAConnectionRequests(new String[]
            {"08001","08001","08001","08001",
             "08001","08001","08001","08001","08001"},
            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");
        dsXAConnectionRequests(new String[]
            {"OK","08001","OK","OK","08001","08001","OK","OK","OK"},
            xads);
        xads.setConnectionAttributes(null);
        xads.setDatabaseName(null);
    } // End testClientDSConnectionAttributes
            
    // Following test is similar to testClientDSConnectionAttributes, but
    // for embedded datasources.
    // This subtest does not run for network server, it uses
    // setAttributesAsPassword, which isn't supported for client datasources.
    //
    // Note that DataSourceTest has some more basic testing of
    // an empty DataSource in a fixture with similar name - however
    // that fixture does not test setAttributesAsPassword
    public void testDSRequestAuthentication() throws Exception {

//        if (usingDerbyNetClient())
//            return;
        
        JDBCClient dsclient = getTestConfiguration().getJDBCClient();
        String dsName = dsclient.getDataSourceClassName();
        DataSource ds = (DataSource) Class.forName(dsName).newInstance();

        // DataSource - attributesAsPassword=true");
        JDBCDataSource.setBeanProperty(ds, "attributesAsPassword", Boolean.TRUE);
        dsConnectionRequests(new String[] {  
            "XJ004","XJ004","XJ004","XJ028",
            "XJ028","XJ004","XJ004","XJ004","XJ004"}, ds);
        JDBCDataSource.setBeanProperty(ds, "attributesAsPassword", Boolean.FALSE);

        // DataSource - attributesAsPassword=true, 
        // connectionAttributes=databaseName=kangaroo");
        JDBCDataSource.setBeanProperty(ds, "attributesAsPassword", Boolean.TRUE);
        JDBCDataSource.setBeanProperty(ds, "connectionAttributes", "databaseName=kangaroo");
        dsConnectionRequests(new String[] {  
            "XJ004","XJ004","XJ004","XJ028",
            "XJ028","XJ004","XJ004","XJ004","XJ004"}, ds);
        JDBCDataSource.setBeanProperty(ds, "attributesAsPassword", Boolean.FALSE);
        JDBCDataSource.clearStringBeanProperty(ds, "connectionAttributes");

        // Enable Authentication;

        setDatabaseProperty("derby.user.fred", "wilma");
        setDatabaseProperty("derby.user.APP", "APP");
        setDatabaseProperty("derby.authentication.provider", "BUILTIN");
        setDatabaseProperty("derby.connection.requireAuthentication", "true");
        
        JDBCDataSource.setBeanProperty(ds, "shutdownDatabase", "shutdown");
        try {
            ds.getConnection();
            fail("shutdown should raise exception");
        } catch (SQLException sqle) {
            assertSQLState("XJ015", sqle);
        }

        JDBCDataSource.clearStringBeanProperty(ds, "databaseName");
        JDBCDataSource.clearStringBeanProperty(ds, "shutdownDatabase");

        // "AUTHENTICATION NOW ENABLED");

        // DataSource - attributesAsPassword=true
        JDBCDataSource.setBeanProperty(ds, "attributesAsPassword", Boolean.TRUE);
        dsConnectionRequests(new String[] {  
            "XJ004","XJ004","XJ004","XJ028",
            "XJ028","XJ004","XJ004","XJ004","XJ004"}, ds);
        JDBCDataSource.setBeanProperty(ds, "attributesAsPassword", Boolean.FALSE);

        // ensure the DS property password is not treated as a set of 
        // attributes.
        // DataSource - attributesAsPassword=true, user=fred, 
        //     password=databaseName=wombat;password=wilma
        JDBCDataSource.setBeanProperty(ds, "attributesAsPassword", Boolean.TRUE);
        JDBCDataSource.setBeanProperty(ds, "user", "fred");
        JDBCDataSource.setBeanProperty(ds, "password", "databaseName=" + dbName + ";password=wilma");
        dsConnectionRequests(new String[] {  
            "XJ004","XJ004","XJ004","XJ028",
            "XJ028","XJ004","XJ004","XJ004","XJ004"}, ds);
        JDBCDataSource.setBeanProperty(ds, "attributesAsPassword", Boolean.FALSE);
        JDBCDataSource.clearStringBeanProperty(ds, "user");
        JDBCDataSource.clearStringBeanProperty(ds, "password");
        ds = null;

        // now with ConnectionPoolDataSource
        String cpdsName = dsclient.getConnectionPoolDataSourceClassName();
        ConnectionPoolDataSource cpds =
              (ConnectionPoolDataSource) Class.forName(cpdsName).newInstance();

        // ConnectionPoolDataSource - EMPTY
        dsCPConnectionRequests(new String[] {
            "XJ004","XJ004","XJ004","XJ004",
            "XJ004","XJ004","XJ004","XJ004","XJ004"},
            cpds);

        // ConnectionPoolDataSource - 
        // connectionAttributes=databaseName=wombat
        JDBCDataSource.setBeanProperty(cpds, "connectionAttributes", "databaseName=" + dbName);
        dsCPConnectionRequests(new String[] {
            "XJ004","XJ004","XJ004","XJ004",
            "XJ004","XJ004","XJ004","XJ004","XJ004"},
            cpds);
        JDBCDataSource.clearStringBeanProperty(cpds, "connectionAttributes");

        // ConnectionPoolDataSource - attributesAsPassword=true
        JDBCDataSource.setBeanProperty(cpds, "attributesAsPassword", Boolean.TRUE);
        dsCPConnectionRequests(new String[] {
            "XJ004","XJ004","XJ004","XJ028",
            "XJ028","XJ004","XJ004","XJ004","XJ004"},
            cpds);
        JDBCDataSource.setBeanProperty(cpds, "attributesAsPassword", Boolean.FALSE);
        
        // ensure the DS property password is not treated as a set of
        // attributes.
        // ConnectionPoolDataSource - attributesAsPassword=true, 
        //     user=fred, password=databaseName=wombat;password=wilma");
        JDBCDataSource.setBeanProperty(cpds, "attributesAsPassword", Boolean.TRUE);
        JDBCDataSource.setBeanProperty(cpds, "user", "fred");
        JDBCDataSource.setBeanProperty(cpds, "password", "databaseName=" + dbName + ";password=wilma");
        dsCPConnectionRequests(new String[] {
            "XJ004","XJ004","XJ004","XJ028",
            "XJ028","XJ004","XJ004","XJ004","XJ004"},
            cpds);
        JDBCDataSource.setBeanProperty(cpds, "attributesAsPassword", Boolean.FALSE);
        JDBCDataSource.clearStringBeanProperty(cpds, "user");
        JDBCDataSource.clearStringBeanProperty(cpds, "password");
        cpds = null;

        // now with XADataSource
//        EmbeddedXADataSource xads = new EmbeddedXADataSource();
        String xadsName = dsclient.getXADataSourceClassName();
        XADataSource xads =
                (XADataSource) Class.forName(xadsName).newInstance();

        // XADataSource - EMPTY
        dsXAConnectionRequests(new String[] {
            "08006","08006","08006","08006",
            "08006","08006","08006","08006","08006"},
            xads);

        // XADataSource - databaseName=wombat
        JDBCDataSource.setBeanProperty(xads, "databaseName", dbName);
        dsXAConnectionRequests(new String[] {
            "08004","08004","08004","OK",
            "08004","08004","08004","08004","08004"},
            xads);
        JDBCDataSource.clearStringBeanProperty(xads, "databaseName");

        // XADataSource - connectionAttributes=databaseName=wombat");
        JDBCDataSource.setBeanProperty(xads, "connectionAttributes", "databaseName=" + dbName);
        dsXAConnectionRequests(new String[] {
            "08006","08006","08006","08006",
            "08006","08006","08006","08006","08006"},
            xads);
        JDBCDataSource.clearStringBeanProperty(xads, "connectionAttributes");

        // XADataSource - attributesAsPassword=true
        JDBCDataSource.setBeanProperty(xads, "attributesAsPassword", Boolean.TRUE);
        dsXAConnectionRequests(new String[] {
            "08006","08006","08006","08006",
            "08006","08006","08006","08006","08006"},
            xads);
        JDBCDataSource.setBeanProperty(xads, "attributesAsPassword", Boolean.FALSE);

        // XADataSource - databaseName=wombat, attributesAsPassword=true
        JDBCDataSource.setBeanProperty(xads, "databaseName", dbName);
        JDBCDataSource.setBeanProperty(xads, "attributesAsPassword", Boolean.TRUE);
        dsXAConnectionRequests(new String[] {
            "08004","08004","08004","XJ028",
            "XJ028","08004","08004","OK","08004"},
            xads);
        JDBCDataSource.setBeanProperty(xads, "attributesAsPassword", Boolean.FALSE);
        JDBCDataSource.clearStringBeanProperty(xads, "databaseName");
        
        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.
     * <p>
     * This is also a regression test for DERBY-4717.
     *  
     * @throws SQLException
     */
    public void testClientTraceFileDSConnectionAttribute() throws SQLException
    {
        String traceFile;

        // with ConnectionPoolDataSource
        ConnectionPoolDataSource cpds = J2EEDataSource.getConnectionPoolDataSource();

        traceFile = "trace3.out";
        JDBCDataSource.setBeanProperty(cpds, "connectionAttributes",
        		"traceFile="+traceFile);
        // DERBY-2468 - trace3.out does not get created
        ((PooledConnection)getPhysicalConnection(cpds)).close();
        JDBCDataSource.clearStringBeanProperty(cpds, "connectionAttributes");

        traceFile = "trace4.out";
        JDBCDataSource.setBeanProperty(cpds, "traceFile", traceFile);
        ((PooledConnection)getPhysicalConnection(cpds)).close();
        cpds = null;

        // now with XADataSource
        XADataSource xads = J2EEDataSource.getXADataSource();

        traceFile = "trace5.out";
        JDBCDataSource.setBeanProperty(xads, "connectionAttributes",
        		"traceFile="+traceFile);
        ((XAConnection)getPhysicalConnection(xads)).close();
        // DERBY-2468 - trace5.out does not get created
        JDBCDataSource.clearStringBeanProperty(xads, "connectionAttributes");

        traceFile = "trace6.out";
        JDBCDataSource.setBeanProperty(xads, "traceFile", traceFile);
        ((XAConnection)getPhysicalConnection(xads)).close();

        assertTraceFilesExistAndCanBeDeleted();
    }
        
    /* -- Helper Methods for testClientTraceFileDSConnectionAttribute -- */
    
    /**
     * Check that trace file exists in <framework> directory
     */
    private static void assertTraceFilesExistAndCanBeDeleted()
    {
        AccessController.doPrivileged(new java.security.PrivilegedAction() {
            public Object run() {
                for (int i=3 ; i <= 6 ; i++) {
                    File traceFile = new File("trace" + i + ".out");
                    assertTrue("Doesn't exist", traceFile.exists());
                    assertTrue("Delete failed", traceFile.delete());
                } 
                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. 
     * 
     * There is a corresponding fixture for clientDataSource in DataSourceTest
     *  
     * @throws SQLException
     */
    public void testClientMessageTextConnectionAttribute()
            throws SQLException, ClassNotFoundException, IllegalAccessException,
            InstantiationException
    {
        String retrieveMessageTextProperty = "retrieveMessageText";
        // with ConnectionPoolDataSource
        // ConnectionPoolDataSource - retrieveMessageTextProperty
        ClientConnectionPoolDataSourceInterface cpds;

        if (JDBC.vmSupportsJNDI()) {
            cpds = (ClientConnectionPoolDataSourceInterface)Class.forName(
               "org.apache.derby.jdbc.ClientConnectionPoolDataSource").
                    newInstance();
        } else {
            cpds = (ClientConnectionPoolDataSourceInterface)Class.forName(
               "org.apache.derby.jdbc.BasicClientConnectionPoolDataSource40").
                    newInstance();
        }

        cpds.setPortNumber(TestConfiguration.getCurrent().getPort());
        
        cpds.setDatabaseName(dbName);
        cpds.setConnectionAttributes(
                retrieveMessageTextProperty + "=false");
        PooledConnection cpConn = cpds.getPooledConnection();
        assertMessageText(cpConn.getConnection(), "false");
        cpConn.close();
        cpds.setConnectionAttributes(
                retrieveMessageTextProperty + "=true");
        cpConn = cpds.getPooledConnection();
        assertMessageText(cpConn.getConnection(), "true");
        cpds.setConnectionAttributes(null);
        cpConn.close();

        // now with XADataSource
        ClientXADataSourceInterface xads;
        if (JDBC.vmSupportsJNDI()) {
            xads = (ClientXADataSourceInterface)Class.forName(
                "org.apache.derby.jdbc.ClientXADataSource").
                    newInstance();
        } else {
            xads = (ClientXADataSourceInterface)Class.forName(
                "org.apache.derby.jdbc.BasicClientXADataSource40").
                    newInstance();
        }
        //XADataSource - retrieveMessageTextProperty
        xads.setPortNumber(TestConfiguration.getCurrent().getPort());
        xads.setDatabaseName(dbName);
        xads.setConnectionAttributes(
                retrieveMessageTextProperty + "=false");
        XAConnection xaConn = xads.getXAConnection();
        assertMessageText(xaConn.getConnection(), "false");
        xaConn.close();
        xads.setConnectionAttributes(
                retrieveMessageTextProperty + "=true");
        xaConn = xads.getXAConnection();
        assertMessageText(xaConn.getConnection(), "true");
        xaConn.close();
        xads.setConnectionAttributes(null);
    }

    /* -- Helper Method for testClientMessageTextDSConnectionAttribute -- */

    /**
     * Checks if <tt>retrieveMessageText</tt> takes effect.
     *
     * @param conn the connection to use, will be closed
     * @param retrieveMessageTextValue the current value
     * @throws SQLException if something goes wrong
     */
    private static void assertMessageText(
            Connection conn, String retrieveMessageTextValue) 
    throws SQLException
    {
        try {
            conn.createStatement().executeQuery("SELECT * FROM APP.NOTTHERE");
            fail("SQLException of 42X05 should be thrown!");
        }
        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);
            }
        } finally {
            try {
                conn.close();
            } catch (SQLException ignore) {
                // Ignore error on close
                println("Ignored error on close: " + ignore.getMessage());
            }
        }
    }

    /**
     * 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. 
     * 
     * there is a corresponding method call for datasources in DataSourceTest
     *  
     * @throws SQLException
     */
    public void testDescriptionProperty() 
    throws SQLException, Exception {
        
        // ConnectionPoolDataSource - setDescription
        subTestDataSourceDescription(
        		(DataSource) J2EEDataSource.getConnectionPoolDataSource());

        // XADataSource - setDescription
        subTestDataSourceDescription(
        		(DataSource) J2EEDataSource.getXADataSource());

    }
    
    /**
     * Utility method for testing setting and fetching the description
     * property on a data source.
     */
    private void subTestDataSourceDescription(DataSource ds) throws Exception
    {
        String setDescription = 
            "Everything you ever wanted to know about this datasource";
        
        JDBCDataSource.setBeanProperty(ds, "description", setDescription);
        getPhysicalConnection(ds);
        assertEquals(setDescription, JDBCDataSource.getBeanProperty(ds, "description"));
        JDBCDataSource.clearStringBeanProperty(ds, "description");
        assertNull(JDBCDataSource.getBeanProperty(ds, "description"));    	
    }

    /* ------------------ JDBC30 (and up) Fixtures ------------------ */
    
    public void testXAHoldability() throws SQLException, XAException {
        // DERBY-2533 - 
        // 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();

        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:
        // DERBY-2531: network server / DerbyNetClient has a different value 
        // than embedded.
        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();
            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();
            fail("rsh's connection not active id ");
        } catch (SQLException sqle) {
            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(); 
            fail("rsx's connection not active id (B)");
        } catch (SQLException sqle) {
            assertSQLState("XCL16", sqle);
        }
        try {
            rsh.next(); 
            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());
        assertErrorCode(10000, conn.getWarnings());
        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());
        assertErrorCode(10000, conn.getWarnings());
        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());
        assertErrorCode(10000, conn.getWarnings());
        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 that DatabaseMetaData.getConnection does not leak references to
     * physical connections or other logical connections.
     *
     * @throws SQLException if something goes wrong
     */
    public void testConnectionLeakInDatabaseMetaData()
            throws SQLException {
        ConnectionPoolDataSource cpDs =
                J2EEDataSource.getConnectionPoolDataSource();
        PooledConnection pc = cpDs.getPooledConnection();
        // Get first logical connection and a meta data object.
        Connection con1 = pc.getConnection();
        DatabaseMetaData dmd1 = con1.getMetaData();
        assertSame(con1, dmd1.getConnection());
        con1.close();
        // Get second logical connection and a meta data object.
        Connection con2 = pc.getConnection();
        DatabaseMetaData dmd2 = con2.getMetaData();
        // The first meta data object should not return a reference to the
        // second logical connection.
        assertSame(con2, dmd2.getConnection());
        try {
            dmd1.getConnection();
            fail("Should have thrown no current connection exception");
        } catch (SQLException sqle) {
            assertSQLState("08003", sqle);
        }
        con2.close();
        pc.close();
        try {
            dmd2.getConnection();
            fail("Should have thrown no current connection exception");
        } catch (SQLException sqle) {
            assertSQLState("08003", sqle);
        }
    }

    /**
     * Regression test for a NullPointerException when trying to use the LOB
     * stored procedures after closing and then getting a new logical
     * connection. The problem was that the LOB stored procedure objects on the
     * server side were closed and not reprepared.
     * See Jira issue DERBY-3799.
     */
    public void testDerby3799() throws SQLException {
        ConnectionPoolDataSource cpDs =
                J2EEDataSource.getConnectionPoolDataSource();
        PooledConnection pc = cpDs.getPooledConnection();
        // Get first logical connection.
        Connection con1 = pc.getConnection();
        Statement stmt = con1.createStatement();
        ResultSet rs = stmt.executeQuery("select dClob from derby3799");
        assertTrue(rs.next());
        rs.getString(1);
        rs.close();
        con1.close();
        // Get second logical connection.
        Connection con2 = pc.getConnection();
        stmt = con2.createStatement();
        rs = stmt.executeQuery("select dClob from derby3799");
        assertTrue(rs.next());
        rs.getString(1); // NPE happened here.
        con2.close();
    }

    /**
     * Tests for DERBY-1144
     * 
     * This test tests that holdability, autocomit, and transactionIsolation 
     * are reset on getConnection for PooledConnections obtaind from 
     * connectionPoolDataSources 
     * 
     * DERBY-1134 has been filed for more comprehensive testing of client 
     * connection state. 
     * 
     * @throws SQLException
     */
    public void timeoutTestDerby1144PooledDS() throws SQLException {
    
        PooledConnection pc1 = null;

        // Test holdability   
        ConnectionPoolDataSource ds = 
            J2EEDataSource.getConnectionPoolDataSource();
        pc1 = ds.getPooledConnection();
        assertPooledConnHoldability("PooledConnection", pc1);
        pc1.close();
        
        // Test autocommit
        pc1 = ds.getPooledConnection();
        assertPooledConnAutoCommit("PooledConnection", pc1);
        pc1.close();
        
        // Test pooled connection isolation
        pc1 = ds.getPooledConnection();
        assertPooledConnIso("PooledConnection" , pc1);   
        pc1.close();
    }
    
    public void timeoutTestDerby1144XADS() throws SQLException {
       
        XADataSource xds = J2EEDataSource.getXADataSource();
        // Test xa connection isolation
        XAConnection xpc1 = xds.getXAConnection();        
        assertPooledConnIso("XAConnection", xpc1);                 
        xpc1.close();
    }

    /* -------------- Helper Methods for testDerby1144 -------------- */
    
    /**
     * Make sure autocommit gets reset on PooledConnection.getConnection()
     * @param desc      description of connection
     * @param pc1       pooled connection to test
     * @throws SQLException
     */
    private static void assertPooledConnAutoCommit(
        String desc, PooledConnection pc1) throws SQLException 
    {
        // ** Verify autoCommit state
        Connection conn  = pc1.getConnection();
        conn.setAutoCommit(true);
        // reset the connection and see if the autocommit has changed 
        conn = pc1.getConnection();
        boolean autocommit  = conn.getAutoCommit();
        // autocommit should get reset on getConnection
        assertTrue(autocommit);
        conn.close();
    }


    /**
     * Checks that Holdability gets reset on PooledConnection.getConnection()
     * @param desc
     * @param pc1
     * @throws SQLException
     */
    private static void assertPooledConnHoldability(
        String desc, PooledConnection pc1) throws SQLException 
    { 
        // **Test holdability state
        Connection conn  = pc1.getConnection();
        conn.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
        // reset the connection and see if the holdability gets reset
        // to HOLD_CURSORS_OVER_COMMIT
        conn = pc1.getConnection();
        assertConnHoldability(conn, ResultSet.HOLD_CURSORS_OVER_COMMIT);
        conn.close();
    }


    /**
     * Verify connection holdablity is expected holdability
     * @param conn
     * @param expectedHoldability 
     *   * @throws SQLException
     */
    private static void assertConnHoldability(
        Connection conn, int expectedHoldability) throws SQLException 
    {
        int holdability = conn.getHoldability();
        assertEquals (expectedHoldability, holdability);
    }

    /**
     * Test that isolation is reset on PooledConnection.getConnection()
     * @param pooledConnType   Descripiton of the type of pooled connection
     * @param pc               PooledConnection or XAConnection  
     * @throws SQLException
     */
    private void assertPooledConnIso(
        String pooledConnType, PooledConnection pc) throws SQLException {
        Connection conn = pc.getConnection();

        setupDerby1144Table(conn);

        // *** Test isolation level reset on conntype.getConnection()          
        conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
        assertIsoLocks(conn, Connection.TRANSACTION_READ_UNCOMMITTED);

        conn.close();
        //Get a new connection with pooledConnType.getConnection()
        // Isolation level should be reset to READ_COMMITTED
        Connection newconn = pc.getConnection();
        assertIsoLocks(newconn, Connection.TRANSACTION_READ_COMMITTED);
    }

    /**
     * insert two rows into the simple table for DERBY-1144 tests
     * @param conn
     * @throws SQLException
     */
    private static void  setupDerby1144Table(Connection conn) 
    throws SQLException {
        Statement stmt = conn.createStatement();
        stmt.executeUpdate("INSERT INTO intTable VALUES(1)");
        stmt.executeUpdate("INSERT INTO intTable VALUES(2)");

        conn.commit ();
    }
    
    /**
     * Checks locks for designated isolation level on the connection.
     * Currently only supports TRANSACTION_READ_COMMITTED and 
     * TRANSACTION_READ_UNCOMMITTED
     * @param conn   Connection to test
     * @param expectedIsoLevel expected isolation level
     *
     */
    private void assertIsoLocks(Connection conn, int expectedIsoLevel)
    throws SQLException {
        int conniso = conn.getTransactionIsolation();
        assertEquals(expectedIsoLevel, conniso);

        boolean selectTimedOut = selectTimesoutDuringUpdate(conn);
        // expect a lock timeout for READ_COMMITTED
        switch (conniso) {
            case Connection.TRANSACTION_READ_UNCOMMITTED:
                assertFalse(selectTimedOut); break;
            case Connection.TRANSACTION_READ_COMMITTED:
                assertTrue(selectTimedOut); break;
            default:
                System.out.println("No test support for isolation level");
        }
    }
    
    /**
     * Determine if a select on this connection during update will timeout.
     * Used to establish isolation level.  If the connection isolation level
     * is <code> Connection.TRANSACTION_READ_UNCOMMITTED </code> it will not
     * timeout.  Otherwise it should.  
     * 
     * @param conn   Connection to test.
     * @return  true if the select got a lock timeout, false otherwise.
     */
    private boolean selectTimesoutDuringUpdate(Connection conn) 
    throws SQLException {

        Connection updateConn=null;
        conn.setAutoCommit(false);

        try {
            // create another connection and do an update but don't commit
            updateConn = openDefaultConnection();
            updateConn.setAutoCommit(false);

            // First update the rows on the update connection
            Statement upStmt = updateConn.createStatement();
            upStmt.executeUpdate("update intTable set i = 3");

            // now see if we can select them
            Statement stmt = conn.createStatement();
            JDBC.assertDrainResults(
                stmt.executeQuery("Select * from intTable"));
            stmt.close();
        }
        catch (SQLException e)
        {
            if (e.getSQLState().equals("40XL1"))
            {
                // If we got a lock timeout this is not read uncommitted
                return true;
            }   
        }
        finally {
            try {
                conn.rollback();
                updateConn.rollback();
            }catch (SQLException  se) {
                se.printStackTrace();
            }
        }
        return false;
    }
    
    /* -------------------- Other Helper Methods -------------------- */
    
    private void assertConnectionState(
        int expectedHoldability, int expectedIsolation,
        boolean expectedCommitSetting, boolean expectedReadOnly, 
        Connection conn) throws SQLException 
    {
        assertEquals(expectedHoldability, conn.getHoldability());
        assertEquals(expectedIsolation, conn.getTransactionIsolation());
        assertEquals(expectedCommitSetting, conn.getAutoCommit());
        assertEquals(expectedReadOnly, conn.isReadOnly());
    }

    private static void setDatabaseProperty(String property, String value) 
    throws SQLException
    {
        DataSource ds = JDBCDataSource.getDataSource();
        Connection cadmin = ds.getConnection();
        CallableStatement cs = cadmin.prepareCall(
            "CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY(?, ?)");
        cs.setString(1, property);
        cs.setString(2, value);
        cs.execute();
        
        cs.close();
        cadmin.close();
    }
    
    private void setHoldability(Connection conn, boolean hold) throws SQLException {

        conn.setHoldability(hold ? ResultSet.HOLD_CURSORS_OVER_COMMIT : ResultSet.CLOSE_CURSORS_AT_COMMIT);
    }
    
    private static void dsConnectionRequests(
        String[] expectedValues, DataSource ds) {

        // checks currently only implemented for embedded 
        if (usingEmbedded())
        {
            SecurityCheck.assertSourceSecurity(ds, "javax.sql.DataSource");
        }
        
        try {
            ds.getConnection();
            if (!expectedValues[0].equals("OK"))
                fail (" expected connection to fail, but was OK");
        } catch (SQLException sqle) {
            assertSQLState(expectedValues[0], sqle);
        }
        dsConnectionRequest(expectedValues[1], ds, null, null);
        dsConnectionRequest(expectedValues[2], ds, "fred", null);
        dsConnectionRequest(expectedValues[3], ds, "fred", "wilma");
        dsConnectionRequest(expectedValues[4], ds, null, "wilma");
        dsConnectionRequest(
            expectedValues[5], ds, null, "databaseName=wombat");
        dsConnectionRequest(
            expectedValues[6], ds, "fred", "databaseName=wombat");
        dsConnectionRequest(expectedValues[7], 
            ds, "fred", "databaseName=wombat;password=wilma");
        dsConnectionRequest(expectedValues[8], 
            ds, "fred", "databaseName=wombat;password=betty");
    }

    private static void dsConnectionRequest(
        String expectedValue, DataSource ds, String user, String ConnAttr)
    {
        try {
            ds.getConnection(user, ConnAttr);
            if (!expectedValue.equals("OK"))
                fail (" expected connection to fail, but was OK");
        } catch (SQLException sqle) {
            assertSQLState(expectedValue, sqle);
        }
    }
    
    private static void dsCPConnectionRequests(
        String[] expectedValues, ConnectionPoolDataSource ds) {
        try {
            ds.getPooledConnection();
            if (!expectedValues[0].equals("OK"))
                fail (" expected connection to fail, but was OK");
        } catch (SQLException sqle) {
            assertSQLState(expectedValues[0], sqle);
        }

        dsConnectionRequest(expectedValues[1], ds, null, null);
        dsConnectionRequest(expectedValues[2], ds, "fred", null);
        dsConnectionRequest(expectedValues[3], ds, "fred", "wilma");
        dsConnectionRequest(expectedValues[4], ds, null, "wilma");
        dsConnectionRequest(
            expectedValues[5], ds, null, "databaseName=wombat");
        dsConnectionRequest(
            expectedValues[6], ds, "fred", "databaseName=wombat");
        dsConnectionRequest(expectedValues[7], 
            ds, "fred", "databaseName=wombat;password=wilma");
        dsConnectionRequest(expectedValues[8], 
            ds, "fred", "databaseName=wombat;password=betty");
    }
    
    private static void dsConnectionRequest(String expectedValue, 
        ConnectionPoolDataSource ds, String user, String ConnAttr)
    {
        try {
            ds.getPooledConnection(user, ConnAttr);
            if (!expectedValue.equals("OK"))
                fail (" expected connection to fail, but was OK");
        } catch (SQLException sqle) {
            assertSQLState(expectedValue, sqle);
        }
    }
        
    private static void dsXAConnectionRequests(
        String[] expectedValues, XADataSource ds) {
        try {
            ds.getXAConnection();
            if (!expectedValues[0].equals("OK"))
                fail (" expected connection to fail, but was OK");
        } catch (SQLException sqle) {
            assertSQLState(expectedValues[0], sqle);
        }

        dsConnectionRequest(expectedValues[1], ds, null, null);
        dsConnectionRequest(expectedValues[2], ds, "fred", null);
        dsConnectionRequest(expectedValues[3], ds, "fred", "wilma");
        dsConnectionRequest(expectedValues[4], ds, null, "wilma");
        dsConnectionRequest(
            expectedValues[5], ds, null, "databaseName=" + dbName);
        dsConnectionRequest(
            expectedValues[6], ds, "fred", "databaseName=" + dbName);
        dsConnectionRequest(expectedValues[7], 
            ds, "fred", "databaseName=" + dbName + ";password=wilma");
        dsConnectionRequest(expectedValues[8], 
            ds, "fred", "databaseName=" + dbName + ";password=betty");
    }
    
    private static void dsConnectionRequest(String expectedValue, 
            XADataSource ds, String user, String ConnAttr)
    {
        try {
            ds.getXAConnection(user, ConnAttr);
            if (!expectedValue.equals("OK"))
                fail (" expected connection to fail, but was OK");
        } catch (SQLException sqle) {
            assertSQLState(expectedValue, sqle);
        }
    }

    protected void assertXAException(String tag, XAException xae) {

        // for all our cases, we expect some kind of closed con error
        // but the message is different for embedded vs. network server
        if (usingEmbedded())
            assertEquals("No current connection.", xae.getMessage());
        else if (usingDerbyNetClient())
            assertEquals(
                "XAER_RMFAIL : No current connection.", xae.getMessage());
        Throwable t = xae.getCause();
        if (t instanceof SQLException)
            assertSQLState("08003", (SQLException)t);
    }

    private static void queryOnStatement(String expectedCursorName,
        int[] expectedValues, Connection conn, Statement s) 
    throws SQLException {

        // DERBY-2531
        // network server gives mismatched connections. See also
        // comment in testAllDataSources()
        if (usingEmbedded()) {
            assertEquals(conn, s.getConnection());
        }
        resultSetQuery(expectedCursorName, expectedValues,
                       s.executeQuery("select * from intTable"));
    }

    private static void resultSetQuery(String expectedCursorName, 
        int[] expectedValues, ResultSet rs) throws SQLException 
    {
        // checks currently only implemented for embedded 
        if (usingEmbedded())
        {
            SecurityCheck.assertSourceSecurity(rs, "java.sql.ResultSet");
        }
        assertEquals(expectedCursorName, rs.getCursorName());
        int index=0;
        while (rs.next()) {
            assertEquals(expectedValues[index], rs.getInt(1));
            index++;
        }
        assertEquals(expectedValues.length, index++);
        rs.close();
    }

    private static void assertLocks(int[] expectedValues, Connection conn) 
    throws SQLException {
        Statement s = conn.createStatement();
        ResultSet rs = s.executeQuery(
            "SELECT XID, sum(cast (LOCKCOUNT AS INT)) " +
            "FROM SYSCS_DIAG.LOCK_TABLE AS L GROUP BY XID");

        // Don't output actual XID's as they tend for every catalog change
        // to the system.
        int xact_index = 0;
        while (rs.next()) {
            if (expectedValues != null)
                assertEquals(expectedValues[xact_index], rs.getInt(2));
            else 
                fail("expected no locks");
            xact_index++;
        }
        if (expectedValues != null)
            assertEquals(expectedValues.length, xact_index);
        
        rs.close();
        s.close();
    }

    private void assertStatementState(int[] parameterExpectedValues, 
        int[] expectedValues, Statement s) 
    throws SQLException {
        assertEquals(expectedValues[0], s.getResultSetType());
        assertEquals(
            expectedValues[1], s.getResultSetConcurrency());
        assertEquals(
            expectedValues[2], s.getFetchDirection());
        assertEquals(expectedValues[3], s.getFetchSize());
        assertEquals(expectedValues[4], s.getMaxFieldSize());
        assertEquals(expectedValues[5], s.getMaxRows());
        assertEquals(expectedValues[6], s.getResultSetHoldability());

        if (s instanceof PreparedStatement) {
            PreparedStatement ps = (PreparedStatement) s;
            ParameterMetaData psmd = ps.getParameterMetaData();
            // Parameter count:
            assertEquals(parameterExpectedValues[0], psmd.getParameterCount());
            for (int i = 1; i <= psmd.getParameterCount(); i++) {
                assertEquals(parameterExpectedValues[i], psmd.getParameterType(i));
            }
        }
    }

    /**
    Create a statement with modified State.
     */
    private Statement createFloatStatementForStateChecking(
        int[] StatementExpectedValues, Connection conn)
    throws SQLException {
        Statement s = internalCreateFloatStatementForStateChecking(conn);
        s.setCursorName("StokeNewington");
        s.setFetchDirection(ResultSet.FETCH_REVERSE);
        s.setFetchSize(444);
        s.setMaxFieldSize(713);
        s.setMaxRows(19);

        // Create
        assertStatementState(null, StatementExpectedValues, s);
        return s;
    }

    private Statement internalCreateFloatStatementForStateChecking(
        Connection conn) throws SQLException {
        return conn.createStatement(
            ResultSet.TYPE_SCROLL_INSENSITIVE, 
            ResultSet.CONCUR_READ_ONLY, 
            ResultSet.HOLD_CURSORS_OVER_COMMIT);
    }

    private PreparedStatement createFloatStatementForStateChecking(
        int[] parameterExpectedValues, int[] PreparedStatementExpectedValues,
        Connection conn, String sql) 
    throws SQLException {
        PreparedStatement s = 
            internalCreateFloatStatementForStateChecking(conn, sql);
        s.setCursorName("StokeNewington");
        s.setFetchDirection(ResultSet.FETCH_REVERSE);
        s.setFetchSize(888);
        s.setMaxFieldSize(317);
        s.setMaxRows(91);

        // PreparedStatement Create        
        assertStatementState(
            parameterExpectedValues, PreparedStatementExpectedValues, s);
        return s;
    }
    
    private PreparedStatement internalCreateFloatStatementForStateChecking(
        Connection conn, String sql) throws SQLException {
        return conn.prepareStatement(sql, 
            ResultSet.TYPE_SCROLL_INSENSITIVE, 
            ResultSet.CONCUR_READ_ONLY, 
            ResultSet.HOLD_CURSORS_OVER_COMMIT);
    }

    private CallableStatement createFloatCallForStateChecking(
        int[] parameterExpectedValues, int[] CallableStatementExpectedValues,
        Connection conn, String sql) 
    throws SQLException 
    {
        CallableStatement s = 
            internalCreateFloatCallForStateChecking(conn, sql);
        s.setCursorName("StokeNewington");
        s.setFetchDirection(ResultSet.FETCH_REVERSE);
        s.setFetchSize(999);
        s.setMaxFieldSize(137);
        s.setMaxRows(85);

        // Callable Statement Create
        assertStatementState(
            parameterExpectedValues, CallableStatementExpectedValues, s);
        return s;
    }
    
    private CallableStatement internalCreateFloatCallForStateChecking(
        Connection conn, String sql) throws SQLException {
        return conn.prepareCall(sql, 
            ResultSet.TYPE_SCROLL_INSENSITIVE, 
            ResultSet.CONCUR_READ_ONLY, 
            ResultSet.HOLD_CURSORS_OVER_COMMIT);
    }

    private void assertConnectionOK(
        Object[] expectedValues, String dsName, Connection conn) 
    throws SQLException { 
        
        assertEquals(
            ((Integer)expectedValues[0]).intValue(), conn.getHoldability());

        // check it's a 3.0 connection object by checking if 
        // set & release Savepoint is ok.
        try {
            conn.releaseSavepoint(conn.setSavepoint());
            if (conn.getAutoCommit())
                fail("expected a SQLExpection (savepoint with autocommit on");
            if (!((String)expectedValues[1]).equals("OK"))
                fail("expected a SQLExpection (savepoint with autocommit on");
        } catch (SQLException sqle) {
            // we expect savepoints exceptions because either
            // it's a global transaction, or it's in auto commit mode.
            if (conn.getAutoCommit())
                assertSQLState("XJ010", sqle);
            else if (((String)expectedValues[1]).equals("OK"))
                throw sqle;
            else 
                assertSQLState((String)expectedValues[1], sqle);
        }

        // Running connection checks
        // connection checks currently only implemented for Embedded
        if (usingEmbedded())
        {
            SecurityCheck.assertSourceSecurity(conn, "java.sql.Connection");
            SecurityCheck.assertSourceSecurity(
                conn.getMetaData(), "java.sql.DatabaseMetaData");
        }

        assertEquals(((Integer)expectedValues[2]).intValue(), 
            conn.getTransactionIsolation());
        assertEquals(((Boolean)expectedValues[3]).booleanValue(), 
            conn.getAutoCommit());
        assertEquals(((Boolean)expectedValues[4]).booleanValue(), 
            conn.isReadOnly());

        if (dsName.endsWith("DataSource"))
            assertNull(conn.getWarnings());

        Statement s1 = conn.createStatement();
        assertStatementOK(dsName, conn, s1);
        assertStatementOK(dsName, conn, conn.createStatement
            (ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY));

        Connection c1 = conn.getMetaData().getConnection();
        // c1 and conn should be the same connection object.
        if (!usingDerbyNetClient() && dsName.indexOf("DataSource")>=0)
            assertEquals(c1, conn);

        // Derby-33 - setTypeMap on connection
        try {
            conn.setTypeMap(java.util.Collections.EMPTY_MAP);
            if (!((String)expectedValues[5]).equals("OK"))
                fail (" expected an sqlexception on setTypeMap(EMPTY_MAP)");
        } catch (SQLException sqle) {
            if (((String)expectedValues[5]).equals("OK"))
                throw sqle;
            else
                assertSQLState((String)expectedValues[5], sqle);
        }
        try {
            // expect 0A000 - not implemented for client,
            //        XJ081 - invalid null value passed as map for embedded
            conn.setTypeMap(null);
            fail ("setTypeMap(null) should throw exception");
        } catch (SQLException sqle) {
            assertSQLState((String)expectedValues[6], sqle);
        }
        try {
            // a populated map, not implemented
            java.util.Map map = new java.util.HashMap();
            map.put("name", "class");
            conn.setTypeMap(map);
            if (!((String)expectedValues[7]).equals("OK"))
                fail (" expected an sqlexception on setTypeMap(map)");
        } catch (SQLException sqle) {
            if (((String)expectedValues[7]).equals("OK"))
                throw sqle;
            else
                assertSQLState((String)expectedValues[7], sqle);
        }

        assertConnectionPreClose(dsName, conn);
        conn.close();

        // method calls on a closed connection
        conn.close(); // expect no error

        try {
            conn.createStatement();
            fail (dsName + " <closedconn>.createStatement(), " +
                "expected 08003 - No current connection");
        } catch (SQLException sqle) {
            assertSQLState("08003", sqle);
        }
        try {
            s1.execute("values 1");
            fail(dsName + " <closedstmt>.execute(), " +
                "expected 08003 - No current connection");
        } catch (SQLException sqle) {
            assertSQLState("08003", sqle);
        }
    }

    private void assertConnectionPreClose(String dsName, Connection conn) 
    throws SQLException {

        // before closing the connection, attempt to change holdability
        // and readOnly
        conn.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);

        if (!dsName.equals("Nested2"))
        {
            try {
                conn.setReadOnly(true);
            } catch (SQLException sqle) {
                // cannot set read-only in an active transaction, & sometimes
                // connections are active at this point.
                assertSQLState("25501", sqle);
            }
        }
    }
    
    private void assertStatementOK(String dsName, Connection conn, Statement s)
    throws SQLException {

        // checks currently only implemented for embedded 
        if (usingEmbedded())
        {
            SecurityCheck.assertSourceSecurity(s, "java.sql.Statement");
        }

        Connection c1 = s.getConnection();
        if (c1 != conn)
        {
            // with DerbyNetClient and any kind of DataSource, this goes wrong
            if (!usingDerbyNetClient() && (dsName.indexOf("DataSource") >= 0))
                fail ("incorrect connection object returned for Statement.getConnection()");
        }

        s.addBatch("insert into intTable values 1");
        s.addBatch("insert into intTable values 2,3");
        int[] states = s.executeBatch();
        if (states[0] != 1)
            fail ("invalid update count for first batch statement");
        if (states[1] != 2)
            fail ("invalid update count for second batch statement");

        ResultSet rs = s.executeQuery("VALUES 1");
        if (rs.getStatement() != s)
            fail ("incorrect Statement object returned for ResultSet.getStatement for " + dsName);
        rs.close();
        s.close();
    }

    /**
    When a connection is being pooled, the underlying JDBC embedded
    connection object is re-used. As each application gets a new
    Connection object, that is really a wrapper around the old connection
    it should reset any connection spoecific state on the embedded connection
    object.
     */
    private static void PoolReset(String type, PooledConnection pc) throws SQLException
    {
        PoolResetWork("1", "C", pc.getConnection());
        PoolResetWork("2", "", pc.getConnection());
        PoolResetWork("3", "D", pc.getConnection());

        pc.close();
    }

    private static void PoolResetWork(
        String expectedID, String tableAction, Connection conn) 
    throws SQLException
    {
        Statement s = conn.createStatement();
        if (tableAction.equals("C"))
        {
            s.execute("CREATE TABLE PoolResetWork (id int generated always as identity, name varchar(25))");
        }

        ResultSet rs = s.executeQuery("VALUES IDENTITY_VAL_LOCAL()");
        rs.next();
        String val = rs.getString(1);
        if (!rs.wasNull() || (val != null))
            fail ("initial call to IDENTITY_VAL_LOCAL is not NULL!" + val);
        rs.close();

        s.executeUpdate("INSERT INTO PoolResetWork(name) values ('derby-222')");

        rs = s.executeQuery("VALUES IDENTITY_VAL_LOCAL()");
        rs.next();
        val = rs.getString(1);
        assertEquals(expectedID, val);
        rs.close();

        if (tableAction.equals("D"))
        {
            s.execute("DROP TABLE PoolResetWork");
        }

        s.close();
        conn.close();
    }

    /**
     * Make sure this connection's string is unique (DERBY-243)
     */
    private static void assertToString(Connection conn) throws Exception
    {
        assertStringFormat(conn);
        String str = conn.toString();

        if ( conns.containsKey(str))
        {
            throw new Exception("ERROR: Connection toString() is not unique: " 
                    + str);
        }
        conns.put(str, conn);
    }

    /** 
     * Check the format of a pooled connection
     **/
    private static void assertStringFormat(PooledConnection pc) throws Exception
    {
        String prefix = assertStringPrefix(pc);
        String connstr = pc.toString();
        String format = prefix + " \\(ID = [0-9]+\\), Physical Connection = " +
            "<none>|" + CONNSTRING_FORMAT;
        assertTrue(connstr.matches(format));
    }

    /**
     * Check the format of the connection string.  This is the default test
     * to run if this is not a BrokeredConnection class
     */
    private static void assertStringFormat(Connection conn) //throws Exception
    {
        assertStringPrefix(conn);
        String str = conn.toString(); 
        assertTrue("\nexpected format:\n " + CONNSTRING_FORMAT + "\nactual value:\n " + str,
            str.matches(CONNSTRING_FORMAT));
    }

    /**
     * Make sure the connection string starts with the right prefix, which
     * is the classname@hashcode.
     *
     * @return the expected prefix string, this is used in further string
     *   format checking
     */
    private static String assertStringPrefix(Object conn) //throws Exception
    {
        String connstr = conn.toString();
        String prefix = conn.getClass().getName() + "@" + conn.hashCode();
        // Connection class and has code for connection string should
        // match prefix
        assertTrue(connstr.startsWith(prefix));

        return prefix;
    }

    /**
     * Check uniqueness of connection strings coming from a
     * DataSouce
     */
    private static void assertToString(DataSource ds) throws Exception
    {
        clearConnections();

        int numConnections = 10;
        for ( int i = 0 ; i < numConnections ; i++ )
        {
            Connection conn = ds.getConnection();
            assertToString(conn);
        }

        clearConnections();
    }

    /**
     * Clear out and close connections in the connections
     * hashtable. 
     */
    private static void clearConnections() throws SQLException
    {
        java.util.Iterator it = conns.values().iterator();
        while ( it.hasNext() )
        {
            Connection conn = (Connection)it.next();
            conn.close();
        }
        conns.clear();
    }

    /**
     * Get connections  using getConnection() and make sure
     * they're unique
     */
    private void assertTenConnectionsUnique() throws Exception
    {
        clearConnections();
        // Open ten connections rather than just two to
        // try and catch any odd uniqueness bugs.  Still
        // no guarantee but is better than just two.
        int numConnections = 10;
        for ( int i = 0 ; i < numConnections ; i++ )
        {
            Connection conn = openDefaultConnection();
            assertToString(conn);
        }

        // Now close the connections
        clearConnections();
    }

    /**
     * Check uniqueness of strings for an XA data source
     */
    private static void assertToString(XADataSource xds) throws Exception
    {
        int numConnections = 10;

        //  First get a bunch of pooled connections
        //  and make sure they're all unique
        Hashtable xaConns = new Hashtable();
        for ( int i = 0 ; i < numConnections ; i++ )
        {
            XAConnection xc = xds.getXAConnection();
            assertStringFormat(xc);
            String str = xc.toString();
            // XA connection toString should be unique
            assertNull(xaConns.get(str));
            xaConns.put(str, xc);
        }

        // Now check that connections from each of these
        // pooled connections have different string values
        Iterator it = xaConns.values().iterator();
        clearConnections();
        while ( it.hasNext() )
        {
            XAConnection xc = (XAConnection)it.next();
            Connection conn = xc.getConnection();
            assertToString(conn);
        }
        clearConnections();

        // Now clear out the pooled connections
        it = xaConns.values().iterator();
        while ( it.hasNext() )
        {
            XAConnection xc = (XAConnection)it.next();
            xc.close();
        }
        xaConns.clear();
    }

    /**
     * Check uniqueness of strings with a pooled data source.
     * We want to check the PooledConnection as well as the
     * underlying physical connection. 
     */
    private static void assertToString(ConnectionPoolDataSource pds)
    throws Exception
    {
        int numConnections = 10;

        //  First get a bunch of pooled connections
        //  and make sure they're all unique
        Hashtable pooledConns = new Hashtable();
        for ( int i = 0 ; i < numConnections ; i++ )
        {
            PooledConnection pc = pds.getPooledConnection();
            assertStringFormat(pc);
            String str = pc.toString();
            // Pooled connection toString should be unique
            assertNull( pooledConns.get(str));
            pooledConns.put(str, pc);
        }

        // Now check that connections from each of these
        // pooled connections have different string values
        Iterator it = pooledConns.values().iterator();
        clearConnections();
        while ( it.hasNext() )
        {
            PooledConnection pc = (PooledConnection)it.next();
            Connection conn = pc.getConnection();
            assertToString(conn);
        }
        clearConnections();

        // Now clear out the pooled connections
        it = pooledConns.values().iterator();
        while ( it.hasNext() )
        {
            PooledConnection pc = (PooledConnection)it.next();
            pc.close();
        }
        pooledConns.clear();
    }

    /**
     * Return the Java class and method for the procedure
     * for the nested connection test.
     */
    private static String getNestedMethodName()
    {
        return "checkNesConn";
    }

    // calling checkConnection 
    // - for use in a procedure to get a nested connection.
    public static void checkNesConn (String dsName) throws SQLException {
        Connection conn = DriverManager.getConnection("jdbc:default:connection");
        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), "OK",
            new Integer(2), new Boolean(false), new Boolean(false), 
            EmptyMapValue, NullMapValue, MapMapValue};

        new J2EEDataSourceTest("J2EEDataSourceTest").assertConnectionOK(
            expectedValues, dsName, conn);
    }

    /**
     * Creates a physical connection from the given data source.
     * <p>
     * For a XADataSource, <tt>getXAConnection</tt> is invoked, for a
     * ConnectionPoolDataSource <tt>getPooledConnection</tt> is invoked, and
     * for a DataSource <tt>getConnection</tt> is invoked.
     *
     * @param ds the data source to get the physical connection from
     * @return A pysical connection, which can be an instance of
     *      <tt>XAConnection</tt>, <tt>PooledConnection</tt>, or
     *      <tt>Connection</tt>
     * @throws SQLException if getting a connection fails
     * @throws IllegalArgumentException if the object isn't a data source
     */
    public static Object getPhysicalConnection(Object ds)
            throws SQLException {
        if (ds instanceof XADataSource) {
            return ((XADataSource)ds).getXAConnection();
        } else if (ds instanceof ConnectionPoolDataSource) {
            return ((ConnectionPoolDataSource)ds).getPooledConnection();
        } else if (ds instanceof DataSource) {
            return ((DataSource)ds).getConnection();
        } else {
            throw new IllegalArgumentException(
                    "Not a data source: " + ds.getClass());
        }
    }
}

class cdsXid implements Xid, Serializable
{
  private static final long serialVersionUID = 64467338100036L;

    private final int format_id;
    private byte[] global_id;
    private byte[] branch_id;


    cdsXid(int xid, byte b1, byte b2)
    {
        format_id = xid;
        global_id = new byte[Xid.MAXGTRIDSIZE];
        branch_id = new byte[Xid.MAXBQUALSIZE];

        for (int i = 0; i < global_id.length; i++) {
            global_id[i] = b1;
        }

        for (int i = 0; i < branch_id.length; i++) {
            branch_id[i] = b2;
        }
    }

    /**
     * Obtain the format id part of the Xid.
     * <p>
     *
     * @return Format identifier. O means the OSI CCR format.
     **/
    public int getFormatId()
    {
        return(format_id);
    }

    /**
     * Obtain the global transaction identifier part of XID as an array of 
     * bytes.
     * <p>
     *
     * @return A byte array containing the global transaction identifier.
     **/
    public byte[] getGlobalTransactionId()
    {
        return(global_id);
    }

    /**
     * Obtain the transaction branch qualifier part of the Xid in a byte array.
     * <p>
     *
     * @return A byte array containing the branch qualifier of the transaction.
     **/
    public byte[] getBranchQualifier()
    {
        return(branch_id);
    }
}
