Parent Directory | Revision Log | Patch
--- incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Connection.java 2005/05/02 05:18:08 165584 +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Connection.java 2005/05/02 06:25:59 165585 @@ -21,1523 +21,1639 @@ package org.apache.derby.client.am; import org.apache.derby.jdbc.ClientDataSource; -import org.apache.derby.client.am.Section; public abstract class Connection implements java.sql.Connection, - ConnectionCallbackInterface -{ - //---------------------navigational members----------------------------------- - - - public Agent agent_; - - public DatabaseMetaData databaseMetaData_; - // Since DERBY prepared statements must be re-prepared after a commit, - // then we must traverse this list after a commit and notify statements - // that they are now in an un-prepared state. - final java.util.LinkedList openStatements_ = new java.util.LinkedList(); - - // Some statuses of DERBY objects may be invalid on server either after only rollback - // or after both commit and rollback. For example, - // (1) prepared statements need to be re-prepared - // after both commit and rollback - // (2) result set will be unpositioned on server after both commit and rollback. - // If they only depend on rollback, they need to get on RollbackOnlyListeners_. - // If they depend on both commit and rollback, they need to get on CommitAndRollbackListeners_. - final java.util.LinkedList RollbackOnlyListeners_ = new java.util.LinkedList(); - final java.util.LinkedList CommitAndRollbackListeners_ = new java.util.LinkedList(); - private SqlWarning warnings_ = null; - - // ------------------------properties set for life of connection-------------- - - // See ClientDataSource pre-connect settings - public transient String user_; - public boolean retrieveMessageText_; - protected boolean jdbcReadOnly_; - public int resultSetHoldability_; - public String databaseName_; - - // Holds the Product-Specific Identifier which specifies - // the product release level of a DDM Server. - // The max length is 8. - public String productID_; - - // Used to get the public key and encrypt password and/or userid - protected EncryptionManager encryptionManager_; - - // used to set transaction isolation level - private Statement setTransactionIsolationStmt = null; - // ------------------------dynamic properties--------------------------------- - - protected boolean open_ = true; - protected boolean availableForReuse_ = false; - - public int isolation_ = Configuration.defaultIsolation; - public boolean autoCommit_ = true; - protected boolean inUnitOfWork_ = false; // This means a transaction is in progress. - - private boolean accumulated440ForMessageProcFailure_ = false; - private boolean accumulated444ForMessageProcFailure_ = false; - private boolean accumulatedSetReadOnlyWarning_ = false; - - - - //---------------------XA----------------------------------------------------- - - protected boolean isXAConnection_ = false; // Indicates an XA connection - - // XA States - public static final int XA_OPEN_IDLE = 0; - public static final int XA_LOCAL = 1; // local transaction started by DNC - public static final int XA_LOCAL_CCC = 2; // local transaction started by CCC - public static final int XA_ACTIVE = 3; - public static final int XA_ENDED = 4; - public static final int XA_HEUR_COMP = 5; - public static final int XA_SUSPENDED = 6; - public static final int XA_PREPARED = 7; - public static final int XA_ROLLBACK = 8; - public static final int XA_LOCAL_START_SENT = 9; - public static final int XA_UNKNOWN = 10; - public static final int XA_GLOBAL_START_SENT = 11; - public static final int XA_PENDING_END = 12; - public static final int XA_RBATHER = 13; - public static final int XA_RECOVER = 14; - public static final int XA_EMPTY_TRANSACTION = 15; - public static final int XA_RBROLLBACK = 16; - public static final int XA_PENDING_START = 17; - public static final int XA_EMPTY_SUSPENDED = 18; - - - protected int xaState_ = XA_OPEN_IDLE; - - // XA Host Type - public int xaHostVersion_ = 0; - - public int loginTimeout_; - public org.apache.derby.jdbc.ClientDataSource dataSource_; - public String serverNameIP_; - public int portNumber_; - - public java.util.Hashtable clientCursorNameCache_ = new java.util.Hashtable(); - public boolean canUseCachedConnectBytes_ = false; - public int commBufferSize_ = 32767; - - // indicates if a deferred reset connection is required - public boolean resetConnectionAtFirstSql_ = false; - - //---------------------constructors/finalizer--------------------------------- - - // For jdbc 2 connections - protected Connection (org.apache.derby.client.am.LogWriter logWriter, - String user, - String password, - org.apache.derby.jdbc.ClientDataSource dataSource) throws SqlException - { - initConnection(logWriter, user, dataSource); - } - - protected Connection (org.apache.derby.client.am.LogWriter logWriter, - String user, - String password, - boolean isXAConn, - org.apache.derby.jdbc.ClientDataSource dataSource) throws SqlException - { - isXAConnection_ = isXAConn; - initConnection(logWriter, user, dataSource); - } - - // For jdbc 2 connections - protected void initConnection (org.apache.derby.client.am.LogWriter logWriter, - String user, - org.apache.derby.jdbc.ClientDataSource dataSource) throws SqlException - { - if (logWriter != null) logWriter.traceConnectEntry (dataSource); - org.apache.derby.client.am.Configuration.checkForExceptionsFromLoadConfiguration (logWriter); - - user_ = user; - - // Extract common properties. - databaseName_ = dataSource.getDatabaseName() + dataSource.getConnectionAttributes(); - retrieveMessageText_ = dataSource.getRetrieveMessageText(); - - loginTimeout_ = dataSource.getLoginTimeout(); - dataSource_ = dataSource; - - serverNameIP_ = dataSource.getServerName(); - portNumber_ = dataSource.getPortNumber(); - - - agent_ = newAgent_ (logWriter, - loginTimeout_, - serverNameIP_, - portNumber_); - } - - // For jdbc 2 connections - protected Connection (org.apache.derby.client.am.LogWriter logWriter, - boolean isXAConn, - org.apache.derby.jdbc.ClientDataSource dataSource) throws SqlException - { - if (logWriter != null) logWriter.traceConnectEntry (dataSource); - isXAConnection_ = isXAConn; - org.apache.derby.client.am.Configuration.checkForExceptionsFromLoadConfiguration (logWriter); - - user_ = ClientDataSource.propertyDefault_user; - - // Extract common properties. - databaseName_ = dataSource.getDatabaseName(); - retrieveMessageText_ = dataSource.getRetrieveMessageText(); - - loginTimeout_= dataSource.getLoginTimeout(); - dataSource_ = dataSource; - - serverNameIP_ = dataSource.getServerName(); - portNumber_ = dataSource.getPortNumber(); - - - agent_ = newAgent_ (logWriter, - loginTimeout_, - serverNameIP_, - portNumber_); - } + ConnectionCallbackInterface { + //---------------------navigational members----------------------------------- - // This is a callback method, called by subsystem - NetConnection - protected void resetConnection (LogWriter logWriter, - String user, - ClientDataSource ds, - boolean recomputeFromDataSource) throws SqlException - { - // clearWarningsX() will re-initialize the following properties - clearWarningsX(); - - user_ = (user != null) ? user : user_; - - if (ds != null && recomputeFromDataSource) { // no need to reinitialize connection state if ds hasn't changed - user_ = (user != null) ? user : ds.getUser();; - retrieveMessageText_ = ds.getRetrieveMessageText(); + public Agent agent_; + public DatabaseMetaData databaseMetaData_; + // Since DERBY prepared statements must be re-prepared after a commit, + // then we must traverse this list after a commit and notify statements + // that they are now in an un-prepared state. + final java.util.LinkedList openStatements_ = new java.util.LinkedList(); + + // Some statuses of DERBY objects may be invalid on server either after only rollback + // or after both commit and rollback. For example, + // (1) prepared statements need to be re-prepared + // after both commit and rollback + // (2) result set will be unpositioned on server after both commit and rollback. + // If they only depend on rollback, they need to get on RollbackOnlyListeners_. + // If they depend on both commit and rollback, they need to get on CommitAndRollbackListeners_. + final java.util.LinkedList RollbackOnlyListeners_ = new java.util.LinkedList(); + final java.util.LinkedList CommitAndRollbackListeners_ = new java.util.LinkedList(); + private SqlWarning warnings_ = null; + + // ------------------------properties set for life of connection-------------- + + // See ClientDataSource pre-connect settings + public transient String user_; + public boolean retrieveMessageText_; + protected boolean jdbcReadOnly_; + public int resultSetHoldability_; + public String databaseName_; + + // Holds the Product-Specific Identifier which specifies + // the product release level of a DDM Server. + // The max length is 8. + public String productID_; + + // Used to get the public key and encrypt password and/or userid + protected EncryptionManager encryptionManager_; + + // used to set transaction isolation level + private Statement setTransactionIsolationStmt = null; + // ------------------------dynamic properties--------------------------------- + + protected boolean open_ = true; + protected boolean availableForReuse_ = false; + + public int isolation_ = Configuration.defaultIsolation; + public boolean autoCommit_ = true; + protected boolean inUnitOfWork_ = false; // This means a transaction is in progress. + + private boolean accumulated440ForMessageProcFailure_ = false; + private boolean accumulated444ForMessageProcFailure_ = false; + private boolean accumulatedSetReadOnlyWarning_ = false; + + + + //---------------------XA----------------------------------------------------- + + protected boolean isXAConnection_ = false; // Indicates an XA connection + + // XA States + public static final int XA_OPEN_IDLE = 0; + public static final int XA_LOCAL = 1; // local transaction started by DNC + public static final int XA_LOCAL_CCC = 2; // local transaction started by CCC + public static final int XA_ACTIVE = 3; + public static final int XA_ENDED = 4; + public static final int XA_HEUR_COMP = 5; + public static final int XA_SUSPENDED = 6; + public static final int XA_PREPARED = 7; + public static final int XA_ROLLBACK = 8; + public static final int XA_LOCAL_START_SENT = 9; + public static final int XA_UNKNOWN = 10; + public static final int XA_GLOBAL_START_SENT = 11; + public static final int XA_PENDING_END = 12; + public static final int XA_RBATHER = 13; + public static final int XA_RECOVER = 14; + public static final int XA_EMPTY_TRANSACTION = 15; + public static final int XA_RBROLLBACK = 16; + public static final int XA_PENDING_START = 17; + public static final int XA_EMPTY_SUSPENDED = 18; + + + protected int xaState_ = XA_OPEN_IDLE; + + // XA Host Type + public int xaHostVersion_ = 0; + + public int loginTimeout_; + public org.apache.derby.jdbc.ClientDataSource dataSource_; + public String serverNameIP_; + public int portNumber_; + + public java.util.Hashtable clientCursorNameCache_ = new java.util.Hashtable(); + public boolean canUseCachedConnectBytes_ = false; + public int commBufferSize_ = 32767; + + // indicates if a deferred reset connection is required + public boolean resetConnectionAtFirstSql_ = false; + + //---------------------constructors/finalizer--------------------------------- + + // For jdbc 2 connections + protected Connection(org.apache.derby.client.am.LogWriter logWriter, + String user, + String password, + org.apache.derby.jdbc.ClientDataSource dataSource) throws SqlException { + initConnection(logWriter, user, dataSource); + } + + protected Connection(org.apache.derby.client.am.LogWriter logWriter, + String user, + String password, + boolean isXAConn, + org.apache.derby.jdbc.ClientDataSource dataSource) throws SqlException { + isXAConnection_ = isXAConn; + initConnection(logWriter, user, dataSource); + } - // property encryptionManager_ - // if needed this will later be initialized by NET calls to initializePublicKeyForEncryption() - encryptionManager_ = null; - - // property: open_ - // this should already be true + // For jdbc 2 connections + protected void initConnection(org.apache.derby.client.am.LogWriter logWriter, + String user, + org.apache.derby.jdbc.ClientDataSource dataSource) throws SqlException { + if (logWriter != null) { + logWriter.traceConnectEntry(dataSource); + } + org.apache.derby.client.am.Configuration.checkForExceptionsFromLoadConfiguration(logWriter); + + user_ = user; + + // Extract common properties. + databaseName_ = dataSource.getDatabaseName() + dataSource.getConnectionAttributes(); + retrieveMessageText_ = dataSource.getRetrieveMessageText(); + + loginTimeout_ = dataSource.getLoginTimeout(); + dataSource_ = dataSource; + + serverNameIP_ = dataSource.getServerName(); + portNumber_ = dataSource.getPortNumber(); + + + agent_ = newAgent_(logWriter, + loginTimeout_, + serverNameIP_, + portNumber_); + } + + // For jdbc 2 connections + protected Connection(org.apache.derby.client.am.LogWriter logWriter, + boolean isXAConn, + org.apache.derby.jdbc.ClientDataSource dataSource) throws SqlException { + if (logWriter != null) { + logWriter.traceConnectEntry(dataSource); + } + isXAConnection_ = isXAConn; + org.apache.derby.client.am.Configuration.checkForExceptionsFromLoadConfiguration(logWriter); + + user_ = ClientDataSource.propertyDefault_user; + + // Extract common properties. + databaseName_ = dataSource.getDatabaseName(); + retrieveMessageText_ = dataSource.getRetrieveMessageText(); + + loginTimeout_ = dataSource.getLoginTimeout(); + dataSource_ = dataSource; + + serverNameIP_ = dataSource.getServerName(); + portNumber_ = dataSource.getPortNumber(); + + + agent_ = newAgent_(logWriter, + loginTimeout_, + serverNameIP_, + portNumber_); + } + + // This is a callback method, called by subsystem - NetConnection + protected void resetConnection(LogWriter logWriter, + String user, + ClientDataSource ds, + boolean recomputeFromDataSource) throws SqlException { + // clearWarningsX() will re-initialize the following properties + clearWarningsX(); + + user_ = (user != null) ? user : user_; + + if (ds != null && recomputeFromDataSource) { // no need to reinitialize connection state if ds hasn't changed + user_ = (user != null) ? user : ds.getUser(); + ; + + retrieveMessageText_ = ds.getRetrieveMessageText(); + + + // property encryptionManager_ + // if needed this will later be initialized by NET calls to initializePublicKeyForEncryption() + encryptionManager_ = null; + + // property: open_ + // this should already be true + + isolation_ = Configuration.defaultIsolation; + autoCommit_ = true; + inUnitOfWork_ = false; + + loginTimeout_ = ds.getLoginTimeout(); + dataSource_ = ds; + } + + // property isXAConnection_ + // leave set to current value. this will impact which connect reset flows are used. + + xaState_ = XA_OPEN_IDLE; + if (recomputeFromDataSource) { + this.agent_.resetAgent(this, logWriter, loginTimeout_, serverNameIP_, portNumber_); + } + } + + protected void resetConnection(LogWriter logWriter, + String databaseName, + java.util.Properties properties) throws SqlException { + // clearWarningsX() will re-initialize the following properties + // warnings_, accumulated440ForMessageProcFailure_, + // accumulated444ForMessageProcFailure_, and accumulatedSetReadOnlyWarning_ + clearWarningsX(); + + databaseName_ = databaseName; + user_ = ClientDataSource.getUser(properties); + + retrieveMessageText_ = ClientDataSource.getRetrieveMessageText(properties); + + + // property encryptionManager_ + // if needed this will later be initialized by NET calls to initializePublicKeyForEncryption() + encryptionManager_ = null; + + // property: open_ + // this should already be true + + isolation_ = Configuration.defaultIsolation; + autoCommit_ = true; + inUnitOfWork_ = false; + + // property isXAConnection_ + // leave set to current value. this will impact which connect reset flows are used. + + xaState_ = XA_OPEN_IDLE; + + this.agent_.resetAgent(this, logWriter, loginTimeout_, serverNameIP_, portNumber_); + + } + + + // For jdbc 1 connections + protected Connection(LogWriter logWriter, + int driverManagerLoginTimeout, + String serverName, + int portNumber, + String databaseName, + java.util.Properties properties) throws SqlException { + if (logWriter != null) { + logWriter.traceConnectEntry(serverName, portNumber, databaseName, properties); + } + org.apache.derby.client.am.Configuration.checkForExceptionsFromLoadConfiguration(logWriter); + + databaseName_ = databaseName; + + // Extract common properties. + user_ = ClientDataSource.getUser(properties); + retrieveMessageText_ = ClientDataSource.getRetrieveMessageText(properties); + + loginTimeout_ = driverManagerLoginTimeout; + serverNameIP_ = serverName; + portNumber_ = portNumber; + + agent_ = newAgent_(logWriter, + loginTimeout_, + serverNameIP_, + portNumber_); + } + + // Users are advised to call the method close() on Statement and Connection objects when they are done with them. + // However, some users will forget, and some code may get killed before it can close these objects. + // Therefore, if JDBC drivers have state associated with JDBC objects that need to get + // explicitly cleared up, they should provide finalize methods to take care of them. + // The garbage collector will call these finalize methods when the objects are found to be garbage, + // and this will give the driver a chance to close (or otherwise clean up) the objects. + // Note, however, that there is no guarantee that the garbage collector will ever run. + // If that is the case, the finalizers will not be called. + protected void finalize() throws java.lang.Throwable { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "finalize"); + } + + // finalize() differs from close() in that it will not throw an + // exception if a transaction is in progress. + // finalize() also differs from close() in that it will not drive + // an auto-commit before disconnecting. + // + // If a transaction is in progress, a close() request will throw an SqlException. + // However, if a connection with an incomplete transaction is finalized, + // or is abruptly terminated by application exit, + // the normal rollback semantics imposed by the DERBY server are adopted. + // So we just pull the plug and let the server handle this default semantic. + + if (!open_) { + return; + } + agent_.disconnectEvent(); + super.finalize(); + } + + // ---------------------------jdbc 1------------------------------------------ + + synchronized public java.sql.Statement createStatement() throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "createStatement"); + } + Statement s = createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "createStatement", s); + } + return s; + } + + synchronized public java.sql.PreparedStatement prepareStatement(String sql) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "prepareStatement", sql); + } + PreparedStatement ps = prepareStatementX(sql, + java.sql.ResultSet.TYPE_FORWARD_ONLY, + java.sql.ResultSet.CONCUR_READ_ONLY, + resultSetHoldability_, + java.sql.Statement.NO_GENERATED_KEYS, + null); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "prepareStatement", ps); + } + return ps; + } + + // For internal use only. Use by updatable result set code. + synchronized public PreparedStatement preparePositionedUpdateStatement(String sql, Section querySection) throws SqlException { + checkForClosedConnection(); + // create a net material prepared statement. + PreparedStatement preparedStatement = newPositionedUpdatePreparedStatement_(sql, querySection); + preparedStatement.flowPrepareDescribeInputOutput(); + // The positioned update statement is not added to the list of open statements, + // because this would cause a java.util.ConcurrentModificationException when + // iterating thru the list of open statements to call completeRollback(). + // An updatable result set is marked closed on a call to completeRollback(), + // and would therefore need to close the positioned update statement associated with the result set which would cause + // it to be removed from the open statements list. Resulting in concurrent modification + // on the open statements list. + // Notice that ordinary Statement.closeX() is never called on the positioned update statement, + // rather markClosed() is called to avoid trying to remove the statement from the openStatements_ list. + return preparedStatement; + } + + synchronized public java.sql.CallableStatement prepareCall(String sql) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "prepareCall", sql); + } + CallableStatement cs = prepareCallX(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "prepareCall", cs); + } + return cs; + } + + synchronized PreparedStatement prepareDynamicCatalogQuery(String sql) throws SqlException { + PreparedStatement ps = newPreparedStatement_(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_, java.sql.Statement.NO_GENERATED_KEYS, null); + ps.isCatalogQuery_ = true; + ps.prepare(); + openStatements_.add(ps); + return ps; + } + + public String nativeSQL(String sql) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "nativeSQL", sql); + } + String nativeSql = nativeSQLX(sql); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "nativeSQL", nativeSql); + } + return nativeSql; + } + + synchronized public String nativeSQLX(String sql) throws SqlException { + checkForClosedConnection(); + if (sql == null) { + throw new SqlException(agent_.logWriter_, "Null SQL string passed."); + } + + // Derby can handle the escape syntax directly so only needs escape + // processing for { ? = CALL ....} + String trimSql = sql.trim(); + if (trimSql.startsWith("{")) { + if (trimSql.lastIndexOf("}") >= 0) { + return trimSql.substring(1, trimSql.lastIndexOf("}")); + } + } + + return trimSql; + } + + // Driver-specific determination if local COMMIT/ROLLBACK is allowed; + // primary usage is distinction between local and global trans. envs.; + protected abstract boolean disallowLocalCommitRollback_() throws org.apache.derby.client.am.SqlException; + + synchronized public void setAutoCommit(boolean autoCommit) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "setAutoCommit", autoCommit); + } + checkForClosedConnection(); + + if (disallowLocalCommitRollback_()) { + if (autoCommit) { // can't toggle to autocommit mode when between xars.start() and xars.end() + throw new SqlException(agent_.logWriter_, + "setAutoCommit(true) invalid during global transaction", + SqlState._2D521, // Spec'ed by PROTOCOL + SqlCode.invalidSetAutoCommitUnderXA); + } + } else { + if (autoCommit == autoCommit_) { + return; // don't flow a commit if nothing changed. + } + if (inUnitOfWork_) { + flowCommit(); // we are not between xars.start() and xars.end(), can flow commit + } + } + autoCommit_ = autoCommit; + } + + public boolean getAutoCommit() throws SqlException { + checkForClosedConnection(); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "getAutoCommit", autoCommit_); + } + if (disallowLocalCommitRollback_()) { // autoCommit is always false between xars.start() and xars.end() + return false; + } + return autoCommit_; + } + + synchronized public void commit() throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "commit"); + } + + // the following XA State check must be in commit instead of commitX since + // external application call commit, the SqlException should be thrown + // only if an external application calls commit during a Global Transaction, + // internal code will call commitX which will ignore the commit request + // while in a Global transaction + checkForInvalidXAStateOnCommitOrRollback(); + checkForClosedConnection(); + flowCommit(); + } + + private void checkForInvalidXAStateOnCommitOrRollback() throws SqlException { + if (disallowLocalCommitRollback_()) { + throw new SqlException(agent_.logWriter_, + "COMMIT or ROLLBACK invalid for application execution environment", + SqlState._2D521, // Spec'ed by PROTOCOL + SqlCode.invalidCommitOrRollbackUnderXA); + } + } + + public void flowCommit() throws SqlException { + // Per JDBC specification (see javadoc for Connection.commit()): + // "This method should be used only when auto-commit mode has been disabled." + // However, some applications do this anyway, it is harmless, so + // if they ask to commit, we could go ahead and flow a commit. + // But note that rollback() is less harmless, rollback() shouldn't be used in auto-commit mode. + // This behavior is subject to further review. + + // if (!this.inUnitOfWork) + // return; + // We won't try to be "too smart", if the user requests a commit, we'll flow a commit, + // regardless of whether or not we're in a unit of work or in auto-commit mode. + // + if (isXAConnection_) { + agent_.beginWriteChainOutsideUOW(); + writeCommit(); + agent_.flowOutsideUOW(); + readCommit(); // This will invoke the commitEvent() callback from the material layer. + agent_.endReadChain(); + } else { + agent_.beginWriteChain(null); + writeCommit(); + agent_.flow(null); + readCommit(); // This will invoke the commitEvent() callback from the material layer. + agent_.endReadChain(); + } + + } + + // precondition: autoCommit_ is true + public void flowAutoCommit() throws SqlException { + if (willAutoCommitGenerateFlow()) { + flowCommit(); + } + } + + public boolean willAutoCommitGenerateFlow() throws org.apache.derby.client.am.SqlException { + if (!autoCommit_) { + return false; + } + if (disallowLocalCommitRollback_()) { + return false; + } + return true; + } + + // precondition: autoCommit_ is true + void writeAutoCommit() throws SqlException { + if (willAutoCommitGenerateFlow()) { + writeCommit(); + } + } + + public void writeCommit() throws SqlException { + if (isXAConnection_) { + if ((xaState_ == XA_LOCAL) || + (xaState_ == XA_LOCAL_START_SENT)) { + writeLocalXACommit_(); + } + } else { + writeLocalCommit_(); + } + } + + // precondition: autoCommit_ is true + void readAutoCommit() throws SqlException { + if (willAutoCommitGenerateFlow()) { + readCommit(); + } + } + + public void readCommit() throws SqlException { + if (isXAConnection_) { + if ((xaState_ == XA_LOCAL) || + (xaState_ == XA_LOCAL_START_SENT)) { + readLocalXACommit_(); + setXAState(XA_OPEN_IDLE); + } + } else { + readLocalCommit_(); + } + } + + synchronized public void rollback() throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "rollback"); + } + checkForInvalidXAStateOnCommitOrRollback(); + checkForClosedConnection(); + flowRollback(); + } + + // Even if we're not in a transaction, all open result sets will be closed. + // So we could probably just return if we're not in a transaction + // using the following code: + // if (!this.inUnitOfWork) + // return; + // But we'll just play it safe, and blindly flow the rollback. + // We won't try to be "too smart", if the user requests a rollback, we'll flow a rollback, + // regardless of whether or not we're in a unit of work or in auto-commit mode. + // + // Per JDBC specification (see javadoc for Connection.rollback()): + // "This method should be used only when auto-commit mode has been disabled." + // However, rather than trying to be too smart, we'll just flow the rollback anyway + // before throwing an exception. + // As a side-effect of invoking rollback() in auto-commit mode, + // we'll close all open result sets on this connection in the rollbackEvent(). + // + protected void flowRollback() throws SqlException { + if (isXAConnection_) { + agent_.beginWriteChainOutsideUOW(); + writeRollback(); + agent_.flowOutsideUOW(); + readRollback(); // This method will invoke the rollbackEvent() callback from the material layer. + agent_.endReadChain(); + } else { + agent_.beginWriteChain(null); + writeRollback(); + agent_.flow(null); + readRollback(); // This method will invoke the rollbackEvent() callback from the material layer. + agent_.endReadChain(); + } + } + + public void writeRollback() throws SqlException { + if (isXAConnection_) { + writeLocalXARollback_(); + } else { + writeLocalRollback_(); + } + } + + public void readRollback() throws SqlException { + if (isXAConnection_) { + readLocalXARollback_(); + setXAState(XA_OPEN_IDLE); + } else { + readLocalRollback_(); + } + } + + synchronized public void close() throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "close"); + } + closeX(); + } + + void checkForTransactionInProgress() throws SqlException { + // The following precondition matches CLI semantics, see SQLDisconnect() + if (!autoCommit_ && inUnitOfWork_ && !allowCloseInUOW_()) { + throw new SqlException(agent_.logWriter_, + "java.sql.Connection.close() requested while a transaction is in progress on the connection." + + "The transaction remains active, and the connection cannot be closed."); + } + } + + // This is a no-op if the connection is already closed. + synchronized public void closeX() throws SqlException { + if (!open_) { + return; + } + closeResourcesX(); + } + + // Close physical socket or attachment even if connection is marked close. + // Used by ClientPooledConnection.close(). + synchronized public void closeResources() throws SqlException { + if (open_ || (!open_ && availableForReuse_)) { + availableForReuse_ = false; + closeResourcesX(); + } + } + + private void closeResourcesX() throws SqlException { + checkForTransactionInProgress(); + resetConnectionAtFirstSql_ = false; // unset indicator of deferred reset + SqlException accumulatedExceptions = null; + if (setTransactionIsolationStmt != null) { + try { + setTransactionIsolationStmt.close(); + } catch (SqlException se) { + accumulatedExceptions = se; + } + } + try { + flowClose(); + } catch (SqlException e) { + accumulatedExceptions = + Utils.accumulateSQLException(e, accumulatedExceptions); + } + + markClosed(); + try { + agent_.close(); + } catch (SqlException e) { + throw Utils.accumulateSQLException(e, accumulatedExceptions); + } + } + + protected abstract boolean isGlobalPending_(); + + // Just like closeX except the socket is not pulled. + // Physical resources are not closed. + synchronized public void closeForReuse() throws SqlException { + if (!open_) { + return; + } + checkForTransactionInProgress(); + resetConnectionAtFirstSql_ = false; // unset indicator of deferred reset + SqlException accumulatedExceptions = null; + try { + flowClose(); + } catch (SqlException e) { + accumulatedExceptions = e; + } + if (open_) { + markClosedForReuse(); + } + if (accumulatedExceptions != null) { + throw accumulatedExceptions; + } + } + + private void flowClose() throws SqlException { + agent_.beginWriteChainOutsideUOW(); + if (doCloseStatementsOnClose_()) { + writeCloseStatements(); + } + if (autoCommit_) { + writeAutoCommit(); + } + agent_.flowOutsideUOW(); + if (doCloseStatementsOnClose_()) { + readCloseStatements(); + } + if (autoCommit_) { + readAutoCommit(); + } + agent_.endReadChain(); + } - isolation_ = Configuration.defaultIsolation; - autoCommit_ = true; - inUnitOfWork_ = false; + protected abstract void markClosed_(); - loginTimeout_ = ds.getLoginTimeout(); - dataSource_ = ds; + public void markClosed() // called by LogicalConnection.close() + { + open_ = false; + inUnitOfWork_ = false; + markStatementsClosed(); + CommitAndRollbackListeners_.clear(); + RollbackOnlyListeners_.clear(); + markClosed_(); + } + + + private void markClosedForReuse() { + availableForReuse_ = true; + markClosed(); + } + + private void markStatementsClosed() { + for (java.util.ListIterator i = openStatements_.listIterator(); i.hasNext();) { + Statement stmt = (Statement) i.next(); + stmt.markClosed(); + i.remove(); + } + } + + private void writeCloseStatements() throws SqlException { + for (java.util.ListIterator i = openStatements_.listIterator(); i.hasNext();) { + ((Statement) i.next()).writeClose(false); // false means don't permit auto-commits + } + } + + private void readCloseStatements() throws SqlException { + for (java.util.ListIterator i = openStatements_.listIterator(); i.hasNext();) { + ((Statement) i.next()).readClose(false); // false means don't permit auto-commits + } + } + + + public boolean isClosed() { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "isClosed", !open_); + } + return !open_; + } + + public boolean isClosedX() { + return !open_; + } + + private static String DERBY_TRANSACTION_REPEATABLE_READ = "RS"; + private static String DERBY_TRANSACTION_SERIALIZABLE = "RR"; + private static String DERBY_TRANSACTION_READ_COMMITTED = "CS"; + private static String DERBY_TRANSACTION_READ_UNCOMMITTED = "UR"; + + synchronized public void setTransactionIsolation(int level) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "setTransactionIsolation", level); + } + // Per jdbc spec (see java.sql.Connection.close() javadoc). + checkForClosedConnection(); + + // Javadoc for this method: + // If this method is called during a transaction, the result is implementation-defined. + // + // + // REPEATABLE_READ = JDBC: TRANSACTION_SERIALIZABLE, DERBY: RR, PROTOCOL: repeatable read + // READ_STABILITY = JDBC: TRANSACTION_REPEATABLE_READ, DERBY: RS, PROTOCOL: All + // CURSOR_STABILITY = JDBC: TRANSACTION_READ_COMMITTED, DERBY: CS, PROTOCOL: Cursor stability + // UNCOMMITTED_READ = JDBC: TRANSACTION_READ_UNCOMMITTED, DERBY: UR , PROTOCOL: Change + // NO_COMMIT = JDBC: TRANSACTION_NONE, DERBY: NC, PROTOCOL: No commit + // + String levelString = null; + switch (level) { + case java.sql.Connection.TRANSACTION_REPEATABLE_READ: + levelString = DERBY_TRANSACTION_REPEATABLE_READ; + break; + case java.sql.Connection.TRANSACTION_READ_COMMITTED: + levelString = DERBY_TRANSACTION_READ_COMMITTED; + break; + case java.sql.Connection.TRANSACTION_SERIALIZABLE: + levelString = DERBY_TRANSACTION_SERIALIZABLE; + break; + case java.sql.Connection.TRANSACTION_READ_UNCOMMITTED: + levelString = DERBY_TRANSACTION_READ_UNCOMMITTED; + break; + // Per javadoc: + // Note that Connection.TRANSACTION_NONE cannot be used because it specifies that transactions are not supported. + case java.sql.Connection.TRANSACTION_NONE: + default: + throw new SqlException(agent_.logWriter_, + "Transaction isolation level " + level + " is an invalid argument for java.sql.Connection.setTransactionIsolation()." + + " See Javadoc specification for a list of valid arguments.", "XJ045"); + } + if (setTransactionIsolationStmt == null) { + setTransactionIsolationStmt = + createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY, + java.sql.ResultSet.CONCUR_READ_ONLY, + resultSetHoldability_); + } + setTransactionIsolationStmt.executeUpdate("SET CURRENT ISOLATION = " + levelString); + + isolation_ = level; + + } + + public int getTransactionIsolation() throws SqlException { + checkForClosedConnection(); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "getTransactionIsolation", isolation_); + } + return isolation_; + } + + public java.sql.SQLWarning getWarnings() { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "getWarnings", warnings_); + } + return warnings_; + } + + synchronized public void clearWarnings() throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "clearWarnings"); + } + clearWarningsX(); + } + + // An untraced version of clearWarnings() + public void clearWarningsX() throws SqlException { + warnings_ = null; + accumulated440ForMessageProcFailure_ = false; + accumulated444ForMessageProcFailure_ = false; + accumulatedSetReadOnlyWarning_ = false; + } + + //====================================================================== + // Advanced features: + + public java.sql.DatabaseMetaData getMetaData() throws SqlException { + checkForClosedConnection(); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "getMetaData", databaseMetaData_); + } + return databaseMetaData_; + } + + synchronized public void setReadOnly(boolean readOnly) throws SqlException { + // This is a hint to the driver only, so this request is silently ignored. + // PROTOCOL can only flow a set-read-only before the connection is established. + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "setReadOnly", readOnly); + } + checkForClosedConnection(); + } + + public boolean isReadOnly() throws SqlException { + checkForClosedConnection(); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "isReadOnly", jdbcReadOnly_); + } + return false; + } + + synchronized public void setCatalog(String catalog) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "setCatalog", catalog); + } + checkForClosedConnection(); + // Per jdbc spec: if the driver does not support catalogs, it will silently ignore this request. + } + + public String getCatalog() throws SqlException { + checkForClosedConnection(); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "getCatalog", (String) null); + } + return null; + } + + //--------------------------JDBC 2.0----------------------------- + + synchronized public java.sql.Statement createStatement(int resultSetType, + int resultSetConcurrency) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "createStatement", resultSetType, resultSetConcurrency); + } + Statement s = createStatementX(resultSetType, resultSetConcurrency, resultSetHoldability_); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "createStatement", s); + } + return s; + } + + synchronized public java.sql.PreparedStatement prepareStatement(String sql, + int resultSetType, + int resultSetConcurrency) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "prepareStatement", sql, resultSetType, resultSetConcurrency); + } + PreparedStatement ps = prepareStatementX(sql, + resultSetType, + resultSetConcurrency, + resultSetHoldability_, + java.sql.Statement.NO_GENERATED_KEYS, + null); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "prepareStatement", ps); + } + return ps; + } + + synchronized public java.sql.CallableStatement prepareCall(String sql, + int resultSetType, + int resultSetConcurrency) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "prepareCall", sql, resultSetType, resultSetConcurrency); + } + CallableStatement cs = prepareCallX(sql, resultSetType, resultSetConcurrency, resultSetHoldability_); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "prepareCall", cs); + } + return cs; + } + + synchronized public CallableStatement prepareMessageProc(String sql) throws SqlException { + checkForClosedConnection(); + + CallableStatement cs = prepareCallX(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_); + return cs; + } + + // Per jdbc spec, when a result set type is unsupported, we downgrade and + // issue a warning rather than to throw an exception. + private int downgradeResultSetType(int resultSetType) { + if (resultSetType == java.sql.ResultSet.TYPE_SCROLL_SENSITIVE) { + accumulateWarning(new SqlWarning(agent_.logWriter_, "Scroll sensitive result sets are not supported by server; remapping to forward-only cursor")); + return java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; + } + return resultSetType; + } + + // Per jdbc spec, when a result set concurrency is unsupported, we downgrade and + // issue a warning rather than to throw an exception. + private int downgradeResultSetConcurrency(int resultSetConcurrency, int resultSetType) { + if (resultSetConcurrency == java.sql.ResultSet.CONCUR_UPDATABLE && + resultSetType == java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE) { + accumulateWarning(new SqlWarning(agent_.logWriter_, "Insensitive updatable result sets are not supported by server; remapping to insensitive read-only cursor")); + return java.sql.ResultSet.CONCUR_READ_ONLY; + } + return resultSetConcurrency; + } + + public java.util.Map getTypeMap() throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "getTypeMap"); + } + checkForClosedConnection(); + java.util.Map map = new java.util.HashMap(); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "getTypeMap", map); + } + return map; + } + + synchronized public void setTypeMap(java.util.Map map) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "setTypeMap", map); + } + checkForClosedConnection(); + throw new SqlException(agent_.logWriter_, "Connection.setTypeMap is not supported"); + } + + //--------------------------JDBC 3.0----------------------------- + + synchronized public void setHoldability(int holdability) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "setHoldability", holdability); + } + checkForClosedConnection(); + resultSetHoldability_ = holdability; + } + + public int getHoldability() throws SqlException { + checkForClosedConnection(); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "getHoldability", resultSetHoldability_); + } + return resultSetHoldability_; + } + + public int dncGeneratedSavepointId_; + // generated name used internally for unnamed savepoints + public static final String dncGeneratedSavepointNamePrefix__ = "DNC_GENENERATED_NAME_"; + + synchronized public java.sql.Savepoint setSavepoint() throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "setSavepoint"); + } + checkForClosedConnection(); + if (autoCommit_) // Throw exception if auto-commit is on + { + throw new SqlException(agent_.logWriter_, "Cannot set savepoint when in auto-commit mode."); + } else if (xaState_ == XA_PENDING_START || + xaState_ == XA_ACTIVE) // Throw exception if in distributed transaction + { + throw new SqlException(agent_.logWriter_, "Cannot set savepoint during distributed transaction."); + } + // create an un-named savepoint. + if ((++dncGeneratedSavepointId_) < 0) { + dncGeneratedSavepointId_ = 1; // restart from 1 when overflow. + } + Object s = setSavepointX(new Savepoint(agent_, dncGeneratedSavepointId_)); + return (java.sql.Savepoint) s; + } + + synchronized public java.sql.Savepoint setSavepoint(String name) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "setSavepoint", name); + } + checkForClosedConnection(); + if (name == null) // Throw exception if savepoint name is null + { + throw new SqlException(agent_.logWriter_, "Named savepoint needs a none-null name."); + } else if (autoCommit_) // Throw exception if auto-commit is on + { + throw new SqlException(agent_.logWriter_, "Cannot set savepoint when in auto-commit mode."); + } else if (xaState_ == XA_PENDING_START || + xaState_ == XA_ACTIVE) // Throw exception if in distributed transaction + { + throw new SqlException(agent_.logWriter_, "Cannot set savepoint during distributed transaction."); + } + // create a named savepoint. + Object s = setSavepointX(new Savepoint(agent_, name)); + return (java.sql.Savepoint) s; + } + + private Savepoint setSavepointX(Savepoint savepoint) throws SqlException { + // Construct and flow a savepoint statement to server. + Statement stmt = null; + try { + stmt = (Statement) createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY, + java.sql.ResultSet.CONCUR_READ_ONLY, + resultSetHoldability_); + String savepointName; + try { + savepointName = savepoint.getSavepointName(); + } catch (SqlException e) { + // generate the name for an un-named savepoint. + savepointName = dncGeneratedSavepointNamePrefix__ + + savepoint.getSavepointId(); + } + String sql = "SAVEPOINT \"" + savepointName + "\" ON ROLLBACK RETAIN CURSORS"; + stmt.executeX(sql); + } finally { + if (stmt != null) { + try { + stmt.closeX(); + } catch (SqlException doNothing) { + } + } + } + + return savepoint; + } + + synchronized public void rollback(java.sql.Savepoint savepoint) throws SqlException { + int saveXaState = xaState_; + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "rollback", savepoint); + } + checkForClosedConnection(); + if (savepoint == null) // Throw exception if savepoint is null + { + throw new SqlException(agent_.logWriter_, "Cannot rollback to a null savepoint."); + } else if (autoCommit_) // Throw exception if auto-commit is on + { + throw new SqlException(agent_.logWriter_, "Cannot rollback to a savepoint when in auto-commit mode."); + } else if (xaState_ == XA_PENDING_START || + xaState_ == XA_ACTIVE) // Throw exception if in distributed transaction + { + throw new SqlException(agent_.logWriter_, "Cannot rollback to a savepoint during distributed transaction."); + } + // Only allow to rollback to a savepoint from the connection that create the savepoint. + try { + if (this != ((Savepoint) savepoint).agent_.connection_) { + throw new SqlException(agent_.logWriter_, + "Rollback to a savepoint not created by this connection."); + } + } catch (java.lang.ClassCastException e) { // savepoint is not an instance of am.Savepoint + throw new SqlException(agent_.logWriter_, + "Rollback to a savepoint not created by this connection."); + } + + // Construct and flow a savepoint rollback statement to server. + Statement stmt = null; + try { + stmt = createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY, + java.sql.ResultSet.CONCUR_READ_ONLY, + resultSetHoldability_); + String savepointName; + try { + savepointName = ((Savepoint) savepoint).getSavepointName(); + } catch (SqlException e) { + // generate the name for an un-named savepoint. + savepointName = dncGeneratedSavepointNamePrefix__ + + ((Savepoint) savepoint).getSavepointId(); + } + String sql = "ROLLBACK TO SAVEPOINT \"" + savepointName + "\""; + stmt.executeX(sql); + } finally { + if (stmt != null) { + try { + stmt.closeX(); + } catch (SqlException doNothing) { + } + } + xaState_ = saveXaState; + } + } + + synchronized public void releaseSavepoint(java.sql.Savepoint savepoint) throws SqlException { + int saveXaState = xaState_; + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "releaseSavepoint", savepoint); + } + checkForClosedConnection(); + if (savepoint == null) // Throw exception if savepoint is null + { + throw new SqlException(agent_.logWriter_, "Cannot release a null savepoint."); + } else if (autoCommit_) // Throw exception if auto-commit is on + { + throw new SqlException(agent_.logWriter_, "Cannot release a savepoint when in auto-commit mode."); + } else if (xaState_ == XA_PENDING_START || + xaState_ == XA_ACTIVE) // Throw exception if in distributed transaction + { + throw new SqlException(agent_.logWriter_, "Cannot release a savepoint during distributed transaction."); + } + // Only allow to release a savepoint from the connection that create the savepoint. + try { + if (this != ((Savepoint) savepoint).agent_.connection_) { + throw new SqlException(agent_.logWriter_, + "Cannot release a savepoint that was not created by this connection."); + } + } catch (java.lang.ClassCastException e) { // savepoint is not an instance of am.Savepoint + throw new SqlException(agent_.logWriter_, + "Cannot release a savepoint that was not created by this connection."); + } + + // Construct and flow a savepoint release statement to server. + Statement stmt = null; + try { + stmt = (Statement) createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY, + java.sql.ResultSet.CONCUR_READ_ONLY, + resultSetHoldability_); + String savepointName; + try { + savepointName = ((Savepoint) savepoint).getSavepointName(); + } catch (SqlException e) { + // generate the name for an un-named savepoint. + savepointName = dncGeneratedSavepointNamePrefix__ + + ((Savepoint) savepoint).getSavepointId(); + } + String sql = "RELEASE SAVEPOINT \"" + savepointName + "\""; + stmt.executeX(sql); + } finally { + if (stmt != null) { + try { + stmt.closeX(); + } catch (SqlException doNothing) { + } + } + xaState_ = saveXaState; + } + } + + synchronized public java.sql.Statement createStatement(int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "createStatement", resultSetType, resultSetConcurrency, resultSetHoldability); + } + Statement s = createStatementX(resultSetType, resultSetConcurrency, resultSetHoldability); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "createStatement", s); + } + return s; + } + + private Statement createStatementX(int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SqlException { + checkForClosedConnection(); + resultSetType = downgradeResultSetType(resultSetType); + resultSetConcurrency = downgradeResultSetConcurrency(resultSetConcurrency, resultSetType); + Statement s = newStatement_(resultSetType, resultSetConcurrency, resultSetHoldability); + s.cursorAttributesToSendOnPrepare_ = s.cacheCursorAttributesToSendOnPrepare(); + openStatements_.add(s); + return s; + } + + // not sure if holding on to cursorAttributesToSendOnPrepare and restoring it is the + // right thing to do here... because if property on the dataSource changes, we may have + // to send different attributes, i.e. SENSITIVE DYNAMIC, instead of SENSITIVE STATIC. + protected void resetStatement(Statement s) throws SqlException { + String cursorAttributesToSendOnPrepare = s.cursorAttributesToSendOnPrepare_; + resetStatement_(s, s.resultSetType_, s.resultSetConcurrency_, s.resultSetHoldability_); + s.cursorAttributesToSendOnPrepare_ = cursorAttributesToSendOnPrepare; + } + + synchronized public java.sql.PreparedStatement prepareStatement(String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "prepareStatement", sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + PreparedStatement ps = prepareStatementX(sql, + resultSetType, + resultSetConcurrency, + resultSetHoldability, + java.sql.Statement.NO_GENERATED_KEYS, + null); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "prepareStatement", ps); + } + return ps; + } + + // used by DBMD + PreparedStatement prepareStatementX(String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability, + int autoGeneratedKeys, + String[] columnNames) throws SqlException { + checkForClosedConnection(); + checkAutoGeneratedKeysParameters(autoGeneratedKeys, columnNames); + resultSetType = downgradeResultSetType(resultSetType); + resultSetConcurrency = downgradeResultSetConcurrency(resultSetConcurrency, resultSetType); + PreparedStatement ps = newPreparedStatement_(sql, resultSetType, resultSetConcurrency, resultSetHoldability, autoGeneratedKeys, columnNames); + ps.cursorAttributesToSendOnPrepare_ = ps.cacheCursorAttributesToSendOnPrepare(); + ps.prepare(); + openStatements_.add(ps); + return ps; + } + + // not sure if holding on to cursorAttributesToSendOnPrepare and restoring it is the + // right thing to do here... because if property on the dataSource changes, we may have + // to send different attributes, i.e. SENSITIVE DYNAMIC, instead of SENSITIVE STATIC. + protected void resetPrepareStatement(PreparedStatement ps) throws SqlException { + String cursorAttributesToSendOnPrepare = ps.cursorAttributesToSendOnPrepare_; + resetPreparedStatement_(ps, ps.sql_, ps.resultSetType_, ps.resultSetConcurrency_, ps.resultSetHoldability_, ps.autoGeneratedKeys_, ps.generatedKeysColumnNames_); + ps.cursorAttributesToSendOnPrepare_ = cursorAttributesToSendOnPrepare; + ps.prepare(); + } + + synchronized public java.sql.CallableStatement prepareCall(String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "prepareCall", sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + CallableStatement cs = prepareCallX(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "prepareCall", cs); + } + return cs; + } + + private CallableStatement prepareCallX(String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SqlException { + checkForClosedConnection(); + resultSetType = downgradeResultSetType(resultSetType); + resultSetConcurrency = downgradeResultSetConcurrency(resultSetConcurrency, resultSetType); + CallableStatement cs = newCallableStatement_(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + cs.cursorAttributesToSendOnPrepare_ = cs.cacheCursorAttributesToSendOnPrepare(); + cs.prepare(); + openStatements_.add(cs); + return cs; + } + + protected void resetPrepareCall(CallableStatement cs) throws SqlException { + String cursorAttributesToSendOnPrepare = cs.cursorAttributesToSendOnPrepare_; + resetCallableStatement_(cs, cs.sql_, cs.resultSetType_, cs.resultSetConcurrency_, cs.resultSetHoldability_); + cs.cursorAttributesToSendOnPrepare_ = cursorAttributesToSendOnPrepare; + cs.prepare(); + } + + public java.sql.PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "prepareStatement", sql, autoGeneratedKeys); + } + PreparedStatement ps = prepareStatementX(sql, + java.sql.ResultSet.TYPE_FORWARD_ONLY, + java.sql.ResultSet.CONCUR_READ_ONLY, + resultSetHoldability_, + autoGeneratedKeys, + null); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "prepareStatement", ps); + } + return ps; + } + + public java.sql.PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "prepareStatement", sql, columnIndexes); + } + checkForClosedConnection(); + throw new SqlException(agent_.logWriter_, "Driver not capable"); + } + + public java.sql.PreparedStatement prepareStatement(String sql, String columnNames[]) throws SqlException { + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceEntry(this, "prepareStatement", sql, columnNames); + } + PreparedStatement ps = prepareStatementX(sql, + java.sql.ResultSet.TYPE_FORWARD_ONLY, + java.sql.ResultSet.CONCUR_READ_ONLY, + resultSetHoldability_, + java.sql.Statement.RETURN_GENERATED_KEYS, + columnNames); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "prepareStatement", ps); + } + return ps; + } + + + // --------------------------------------------------------------------------- + + protected abstract boolean allowCloseInUOW_(); + + protected abstract boolean doCloseStatementsOnClose_(); + + public abstract SectionManager newSectionManager(String collection, + Agent agent, + String databaseName); + //--------------------Abstract material factory methods----------------- + + protected abstract Agent newAgent_(LogWriter logWriter, int loginTimeout, String serverName, int portNumber) throws SqlException; + + + protected abstract DatabaseMetaData newDatabaseMetaData_(); + + protected abstract Statement newStatement_(int type, + int concurrency, + int holdability) throws SqlException; + + protected abstract void resetStatement_(Statement statement, + int type, + int concurrency, + int holdability) throws SqlException; + + + protected abstract PreparedStatement newPositionedUpdatePreparedStatement_(String sql, Section section) throws SqlException; + + protected abstract PreparedStatement newPreparedStatement_(String sql, + int type, + int concurrency, + int holdability, + int autoGeneratedKeys, + String[] columnNames) throws SqlException; + + protected abstract void resetPreparedStatement_(PreparedStatement ps, + String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability, + int autoGeneratedKeys, + String[] columnNames) throws SqlException; + + protected abstract CallableStatement newCallableStatement_(String sql, + int type, + int concurrency, + int holdability) throws SqlException; + + protected abstract void resetCallableStatement_(CallableStatement cs, + String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SqlException; + + // ----------------------- abstract box car and callback methods --------------------- + // All callbacks must be client-side only operations. + + + public void completeConnect() throws SqlException { + open_ = true; + databaseMetaData_ = newDatabaseMetaData_(); + + agent_.sectionManager_ = + newSectionManager("NULLID", + agent_, + databaseName_); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceConnectExit(this); + } + } + + public abstract void writeCommitSubstitute_() throws SqlException; + + public abstract void readCommitSubstitute_() throws SqlException; + + public abstract void writeLocalXAStart_() throws SqlException; + + public abstract void readLocalXAStart_() throws SqlException; + + public abstract void writeLocalXACommit_() throws SqlException; + + public abstract void readLocalXACommit_() throws SqlException; + + public abstract void writeLocalCommit_() throws SqlException; + + public abstract void readLocalCommit_() throws SqlException; + + public void completeLocalCommit() { + for (java.util.Iterator i = CommitAndRollbackListeners_.iterator(); i.hasNext();) { + UnitOfWorkListener listener = (UnitOfWorkListener) i.next(); + listener.completeLocalCommit(i); + } + inUnitOfWork_ = false; + } + + public abstract void writeLocalRollback_() throws SqlException; + + public abstract void readLocalRollback_() throws SqlException; + + // A callback for certain non-fatal exceptions that occur when parsing error replies. + // This is a client-side only operation. + // This method will only throw an exception on bug check. + public void completeLocalRollback() { + for (java.util.Iterator i = CommitAndRollbackListeners_.iterator(); i.hasNext();) { + UnitOfWorkListener listener = (UnitOfWorkListener) i.next(); + listener.completeLocalRollback(i); + } + for (java.util.Iterator i = RollbackOnlyListeners_.iterator(); i.hasNext();) { + UnitOfWorkListener listener = (UnitOfWorkListener) i.next(); + listener.completeLocalRollback(i); + } + inUnitOfWork_ = false; + } + + + public abstract void writeLocalXARollback_() throws SqlException; + + public abstract void readLocalXARollback_() throws SqlException; + + public void writeTransactionStart(Statement statement) throws SqlException { + } + + public void readTransactionStart() throws SqlException { + completeTransactionStart(); + } + + void completeTransactionStart() { + inUnitOfWork_ = true; + } + + // Occurs autonomously + public void completeAbnormalUnitOfWork() { + completeLocalRollback(); + } + + // Called by Connection.close(), NetConnection.errorRollbackDisconnect(). + // The Agent's client-side resources associated with database connection are reclaimed (eg. socket). + // And this connection and all associated statements and result sets are marked closed. + // This is a client-side only operation. + // This method will only throw an exception if the agent cannot be closed. + public void completeChainBreakingDisconnect() { + open_ = false; + completeLocalRollback(); + markStatementsClosed(); + } + + public void completeSqlca(Sqlca sqlca) { + if (sqlca == null) { + } else if (sqlca.getSqlCode() > 0) { + accumulateWarning(new SqlWarning(agent_.logWriter_, sqlca)); + } else if (sqlca.getSqlCode() < 0) { + agent_.accumulateReadException(new SqlException(agent_.logWriter_, sqlca)); + } + } + + public abstract void addSpecialRegisters(String s); + + // can this only be called by the PooledConnection + // can this be called on a closed connection + // can this be called in a unit of work + // can this be called from within a stored procedure + // + synchronized public void reset(LogWriter logWriter, String user, String password, ClientDataSource ds, boolean recomputeFromDataSource) throws SqlException { + if (logWriter != null) { + logWriter.traceConnectResetEntry(this, logWriter, user, (ds != null) ? ds : dataSource_); + } + try { + reset_(logWriter, user, password, ds, recomputeFromDataSource); + } catch (SqlException sqle) { + DisconnectException de = new DisconnectException(agent_, "An error occurred during connect reset and the connection has been terminated. See chained exceptions for details."); + de.setNextException(sqle); + throw de; + } } - // property isXAConnection_ - // leave set to current value. this will impact which connect reset flows are used. - - xaState_ = XA_OPEN_IDLE; - if (recomputeFromDataSource) - this.agent_.resetAgent(this, logWriter, loginTimeout_, serverNameIP_, portNumber_); - } + synchronized public void reset(LogWriter logWriter, ClientDataSource ds, boolean recomputeFromDataSource) throws SqlException { + if (logWriter != null) { + logWriter.traceConnectResetEntry(this, logWriter, null, (ds != null) ? ds : dataSource_); + } + try { + reset_(logWriter, ds, recomputeFromDataSource); + } catch (SqlException sqle) { + DisconnectException de = new DisconnectException(agent_, "An error occurred during connect reset and the connection has been terminated. See chained exceptions for details."); + de.setNextException(sqle); + throw de; + } + } - protected void resetConnection (LogWriter logWriter, - String databaseName, - java.util.Properties properties) throws SqlException - { - // clearWarningsX() will re-initialize the following properties - // warnings_, accumulated440ForMessageProcFailure_, - // accumulated444ForMessageProcFailure_, and accumulatedSetReadOnlyWarning_ - clearWarningsX(); + synchronized public void lightReset() throws SqlException { + if (!open_ && !availableForReuse_) { + return; + } + open_ = true; + availableForReuse_ = false; + } - databaseName_ = databaseName; - user_ = ClientDataSource.getUser(properties); + abstract protected void reset_(LogWriter logWriter, String user, String password, ClientDataSource ds, boolean recomputerFromDataSource) throws SqlException; - retrieveMessageText_ = ClientDataSource.getRetrieveMessageText(properties); + abstract protected void reset_(LogWriter logWriter, ClientDataSource ds, boolean recomputerFromDataSource) throws SqlException; + protected void completeReset(boolean isDeferredReset, boolean recomputeFromDataSource) throws SqlException { + open_ = true; - // property encryptionManager_ - // if needed this will later be initialized by NET calls to initializePublicKeyForEncryption() - encryptionManager_ = null; + completeLocalRollback(); // this will close the cursors if the physical connection hadn't been closed for reuse properly - // property: open_ - // this should already be true + // Reopen physical statement resources associated with previous uses of this physical connection. + // Notice that these physical statements may not belong to this logical connection. + // Iterate through the physical statements and re-enable them for reuse. - isolation_ = Configuration.defaultIsolation; - autoCommit_ = true; - inUnitOfWork_ = false; + for (java.util.Iterator i = openStatements_.iterator(); i.hasNext();) { + Object o = i.next(); + ((Statement) o).reset(recomputeFromDataSource); - // property isXAConnection_ - // leave set to current value. this will impact which connect reset flows are used. + } - xaState_ = XA_OPEN_IDLE; + if (!isDeferredReset && agent_.loggingEnabled()) { + agent_.logWriter_.traceConnectResetExit(this); + } + } - this.agent_.resetAgent(this, logWriter, loginTimeout_, serverNameIP_, portNumber_); - } + //-------------------------------helper methods------------------------------- + protected void checkForClosedConnection() throws SqlException { + if (!open_) { + agent_.checkForDeferredExceptions(); + throw new SqlException(agent_.logWriter_, "invalid operation: connection closed"); + } else { + agent_.checkForDeferredExceptions(); + } + } + void checkAutoGeneratedKeysParameters(int autoGeneratedKeys, String[] columnNames) throws SqlException { + if (autoGeneratedKeys != java.sql.Statement.NO_GENERATED_KEYS && + autoGeneratedKeys != java.sql.Statement.RETURN_GENERATED_KEYS) { + throw new SqlException(agent_.logWriter_, "Invalid argument: " + + "Statement auto-generated keys value " + autoGeneratedKeys + + " is invalid."); + } - // For jdbc 1 connections - protected Connection (LogWriter logWriter, - int driverManagerLoginTimeout, - String serverName, - int portNumber, - String databaseName, - java.util.Properties properties) throws SqlException - { - if (logWriter != null) logWriter.traceConnectEntry (serverName, portNumber, databaseName, properties); - org.apache.derby.client.am.Configuration.checkForExceptionsFromLoadConfiguration (logWriter); + if (columnNames != null) { + throw new SqlException(agent_.logWriter_, "Driver not capable"); + } - databaseName_ = databaseName; + } - // Extract common properties. - user_ = ClientDataSource.getUser (properties); - retrieveMessageText_ = ClientDataSource.getRetrieveMessageText (properties); + public boolean isXAConnection() { + return isXAConnection_; + } - loginTimeout_ = driverManagerLoginTimeout; - serverNameIP_ = serverName; - portNumber_ = portNumber; + public int getXAState() { + return xaState_; + } - agent_ = newAgent_ (logWriter, - loginTimeout_, - serverNameIP_, - portNumber_); - } + public void setXAState(int state) { + xaState_ = state; + } - // Users are advised to call the method close() on Statement and Connection objects when they are done with them. - // However, some users will forget, and some code may get killed before it can close these objects. - // Therefore, if JDBC drivers have state associated with JDBC objects that need to get - // explicitly cleared up, they should provide finalize methods to take care of them. - // The garbage collector will call these finalize methods when the objects are found to be garbage, - // and this will give the driver a chance to close (or otherwise clean up) the objects. - // Note, however, that there is no guarantee that the garbage collector will ever run. - // If that is the case, the finalizers will not be called. - protected void finalize () throws java.lang.Throwable - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "finalize"); + public void accumulateWarning(SqlWarning e) { + if (warnings_ == null) { + warnings_ = e; + } else { + warnings_.setNextException(e); + } + } - // finalize() differs from close() in that it will not throw an - // exception if a transaction is in progress. - // finalize() also differs from close() in that it will not drive - // an auto-commit before disconnecting. - // - // If a transaction is in progress, a close() request will throw an SqlException. - // However, if a connection with an incomplete transaction is finalized, - // or is abruptly terminated by application exit, - // the normal rollback semantics imposed by the DERBY server are adopted. - // So we just pull the plug and let the server handle this default semantic. - - if (!open_) return; - agent_.disconnectEvent (); - super.finalize(); - } - - // ---------------------------jdbc 1------------------------------------------ - - synchronized public java.sql.Statement createStatement () throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "createStatement"); - Statement s = createStatementX (java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "createStatement", s); - return s; - } - - synchronized public java.sql.PreparedStatement prepareStatement (String sql) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "prepareStatement", sql); - PreparedStatement ps = prepareStatementX (sql, - java.sql.ResultSet.TYPE_FORWARD_ONLY, - java.sql.ResultSet.CONCUR_READ_ONLY, - resultSetHoldability_, - java.sql.Statement.NO_GENERATED_KEYS, - null); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "prepareStatement", ps); - return ps; - } - - // For internal use only. Use by updatable result set code. - synchronized public PreparedStatement preparePositionedUpdateStatement (String sql, Section querySection) throws SqlException - { - checkForClosedConnection (); - // create a net material prepared statement. - PreparedStatement preparedStatement = newPositionedUpdatePreparedStatement_ (sql, querySection); - preparedStatement.flowPrepareDescribeInputOutput (); - // The positioned update statement is not added to the list of open statements, - // because this would cause a java.util.ConcurrentModificationException when - // iterating thru the list of open statements to call completeRollback(). - // An updatable result set is marked closed on a call to completeRollback(), - // and would therefore need to close the positioned update statement associated with the result set which would cause - // it to be removed from the open statements list. Resulting in concurrent modification - // on the open statements list. - // Notice that ordinary Statement.closeX() is never called on the positioned update statement, - // rather markClosed() is called to avoid trying to remove the statement from the openStatements_ list. - return preparedStatement; - } - - synchronized public java.sql.CallableStatement prepareCall (String sql) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "prepareCall", sql); - CallableStatement cs = prepareCallX (sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "prepareCall", cs); - return cs; - } - - synchronized PreparedStatement prepareDynamicCatalogQuery (String sql) throws SqlException - { - PreparedStatement ps = newPreparedStatement_ (sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_, java.sql.Statement.NO_GENERATED_KEYS, null); - ps.isCatalogQuery_ = true; - ps.prepare (); - openStatements_.add (ps); - return ps; - } - - public String nativeSQL (String sql) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "nativeSQL", sql); - String nativeSql = nativeSQLX (sql); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "nativeSQL", nativeSql); - return nativeSql; - } - - synchronized public String nativeSQLX (String sql) throws SqlException - { - checkForClosedConnection(); - if (sql == null) throw new SqlException (agent_.logWriter_, "Null SQL string passed."); - - // Derby can handle the escape syntax directly so only needs escape - // processing for { ? = CALL ....} - String trimSql = sql.trim(); - if (trimSql.startsWith ("{")) - { - if (trimSql.lastIndexOf("}") >= 0) - return trimSql.substring(1, trimSql.lastIndexOf("}")); + public void accumulate440WarningForMessageProcFailure(SqlWarning e) { + if (!accumulated440ForMessageProcFailure_) { + accumulateWarning(e); + accumulated440ForMessageProcFailure_ = true; + } } - return trimSql; - } + public void accumulate444WarningForMessageProcFailure(SqlWarning e) { + if (!accumulated444ForMessageProcFailure_) { + accumulateWarning(e); + accumulated444ForMessageProcFailure_ = true; + } + } - // Driver-specific determination if local COMMIT/ROLLBACK is allowed; - // primary usage is distinction between local and global trans. envs.; - protected abstract boolean disallowLocalCommitRollback_() throws org.apache.derby.client.am.SqlException; - - synchronized public void setAutoCommit (boolean autoCommit) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setAutoCommit", autoCommit); - checkForClosedConnection(); - - if ( disallowLocalCommitRollback_() ) { - if (autoCommit) { // can't toggle to autocommit mode when between xars.start() and xars.end() - throw new SqlException (agent_.logWriter_, - "setAutoCommit(true) invalid during global transaction", - SqlState._2D521, // Spec'ed by PROTOCOL - SqlCode.invalidSetAutoCommitUnderXA); - } - } - else { - if (autoCommit == autoCommit_) return; // don't flow a commit if nothing changed. - if (inUnitOfWork_) flowCommit(); // we are not between xars.start() and xars.end(), can flow commit - } - autoCommit_ = autoCommit; - } - - public boolean getAutoCommit () throws SqlException - { - checkForClosedConnection(); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getAutoCommit", autoCommit_); - if ( disallowLocalCommitRollback_() ) - { // autoCommit is always false between xars.start() and xars.end() - return false; - } - return autoCommit_; - } - - synchronized public void commit () throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "commit"); - - // the following XA State check must be in commit instead of commitX since - // external application call commit, the SqlException should be thrown - // only if an external application calls commit during a Global Transaction, - // internal code will call commitX which will ignore the commit request - // while in a Global transaction - checkForInvalidXAStateOnCommitOrRollback (); - checkForClosedConnection(); - flowCommit(); - } - - private void checkForInvalidXAStateOnCommitOrRollback () throws SqlException - { - if ( disallowLocalCommitRollback_() ) { - throw new SqlException (agent_.logWriter_, - "COMMIT or ROLLBACK invalid for application execution environment", - SqlState._2D521, // Spec'ed by PROTOCOL - SqlCode.invalidCommitOrRollbackUnderXA); - } - } - - public void flowCommit () throws SqlException - { - // Per JDBC specification (see javadoc for Connection.commit()): - // "This method should be used only when auto-commit mode has been disabled." - // However, some applications do this anyway, it is harmless, so - // if they ask to commit, we could go ahead and flow a commit. - // But note that rollback() is less harmless, rollback() shouldn't be used in auto-commit mode. - // This behavior is subject to further review. - - // if (!this.inUnitOfWork) - // return; - // We won't try to be "too smart", if the user requests a commit, we'll flow a commit, - // regardless of whether or not we're in a unit of work or in auto-commit mode. - // - if (isXAConnection_) { - agent_.beginWriteChainOutsideUOW (); - writeCommit (); - agent_.flowOutsideUOW (); - readCommit (); // This will invoke the commitEvent() callback from the material layer. - agent_.endReadChain(); - } - else { - agent_.beginWriteChain (null) ; - writeCommit (); - agent_.flow (null); - readCommit (); // This will invoke the commitEvent() callback from the material layer. - agent_.endReadChain(); - } - - } - - // precondition: autoCommit_ is true - public void flowAutoCommit () throws SqlException - { - if (willAutoCommitGenerateFlow()) flowCommit(); - } - - public boolean willAutoCommitGenerateFlow() throws org.apache.derby.client.am.SqlException - { - if (!autoCommit_) return false; - if (disallowLocalCommitRollback_()) return false; - return true; - } - - // precondition: autoCommit_ is true - void writeAutoCommit() throws SqlException - { - if (willAutoCommitGenerateFlow()) writeCommit(); - } - - public void writeCommit () throws SqlException - { - if (isXAConnection_) { - if ((xaState_ == XA_LOCAL) || - (xaState_ == XA_LOCAL_START_SENT)) - writeLocalXACommit_(); - } - else - writeLocalCommit_(); - } - - // precondition: autoCommit_ is true - void readAutoCommit() throws SqlException - { - if (willAutoCommitGenerateFlow()) readCommit(); - } - - public void readCommit () throws SqlException - { - if (isXAConnection_) { - if ((xaState_ == XA_LOCAL) || - (xaState_ == XA_LOCAL_START_SENT)) { - readLocalXACommit_(); - setXAState( XA_OPEN_IDLE ); - } - } - else - readLocalCommit_(); - } - - synchronized public void rollback () throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "rollback"); - checkForInvalidXAStateOnCommitOrRollback (); - checkForClosedConnection(); - flowRollback(); - } - - // Even if we're not in a transaction, all open result sets will be closed. - // So we could probably just return if we're not in a transaction - // using the following code: - // if (!this.inUnitOfWork) - // return; - // But we'll just play it safe, and blindly flow the rollback. - // We won't try to be "too smart", if the user requests a rollback, we'll flow a rollback, - // regardless of whether or not we're in a unit of work or in auto-commit mode. - // - // Per JDBC specification (see javadoc for Connection.rollback()): - // "This method should be used only when auto-commit mode has been disabled." - // However, rather than trying to be too smart, we'll just flow the rollback anyway - // before throwing an exception. - // As a side-effect of invoking rollback() in auto-commit mode, - // we'll close all open result sets on this connection in the rollbackEvent(). - // - protected void flowRollback () throws SqlException - { - if(isXAConnection_) { - agent_.beginWriteChainOutsideUOW (); - writeRollback (); - agent_.flowOutsideUOW (); - readRollback (); // This method will invoke the rollbackEvent() callback from the material layer. - agent_.endReadChain(); - } - else { - agent_.beginWriteChain(null); - writeRollback (); - agent_.flow(null); - readRollback (); // This method will invoke the rollbackEvent() callback from the material layer. - agent_.endReadChain(); - } - } - - public void writeRollback () throws SqlException - { - if (isXAConnection_) { - writeLocalXARollback_(); - } - else - writeLocalRollback_(); - } - - public void readRollback() throws SqlException - { - if (isXAConnection_) { - readLocalXARollback_(); - setXAState( XA_OPEN_IDLE ); - } - else - readLocalRollback_(); - } - - synchronized public void close () throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "close"); - closeX(); - } - - void checkForTransactionInProgress () throws SqlException - { - // The following precondition matches CLI semantics, see SQLDisconnect() - if (!autoCommit_ && inUnitOfWork_ && !allowCloseInUOW_()) { - throw new SqlException (agent_.logWriter_, - "java.sql.Connection.close() requested while a transaction is in progress on the connection." + - "The transaction remains active, and the connection cannot be closed."); - } - } - - // This is a no-op if the connection is already closed. - synchronized public void closeX () throws SqlException - { - if (!open_) return; - closeResourcesX(); - } - - // Close physical socket or attachment even if connection is marked close. - // Used by ClientPooledConnection.close(). - synchronized public void closeResources () throws SqlException - { - if (open_ || (!open_ && availableForReuse_)) { - availableForReuse_ = false; - closeResourcesX(); - } - } - - private void closeResourcesX () throws SqlException - { - checkForTransactionInProgress (); - resetConnectionAtFirstSql_ = false; // unset indicator of deferred reset - SqlException accumulatedExceptions = null; - if (setTransactionIsolationStmt != null) - try { - setTransactionIsolationStmt.close(); - } catch (SqlException se) - { - accumulatedExceptions = se; - } - try { flowClose(); } catch (SqlException e) - { accumulatedExceptions = - Utils.accumulateSQLException(e,accumulatedExceptions); - } - - markClosed(); - try { agent_.close(); } - catch (SqlException e) { - throw Utils.accumulateSQLException (e, accumulatedExceptions); - } - } - - protected abstract boolean isGlobalPending_ (); - - // Just like closeX except the socket is not pulled. - // Physical resources are not closed. - synchronized public void closeForReuse() throws SqlException - { - if (!open_) return; - checkForTransactionInProgress (); - resetConnectionAtFirstSql_ = false; // unset indicator of deferred reset - SqlException accumulatedExceptions = null; - try { flowClose(); } catch (SqlException e) { accumulatedExceptions = e; } - if (open_) markClosedForReuse(); - if (accumulatedExceptions != null) throw accumulatedExceptions; - } - - private void flowClose () throws SqlException - { - agent_.beginWriteChainOutsideUOW (); - if (doCloseStatementsOnClose_()) writeCloseStatements(); - if (autoCommit_) writeAutoCommit (); - agent_.flowOutsideUOW (); - if (doCloseStatementsOnClose_()) readCloseStatements(); - if (autoCommit_) readAutoCommit (); - agent_.endReadChain(); - } - - protected abstract void markClosed_(); - public void markClosed() // called by LogicalConnection.close() - { - open_ = false; - inUnitOfWork_ = false; - markStatementsClosed(); - CommitAndRollbackListeners_.clear(); - RollbackOnlyListeners_.clear(); - markClosed_(); - } - - - private void markClosedForReuse() - { - availableForReuse_ = true; - markClosed(); - } - - private void markStatementsClosed () - { - for (java.util.ListIterator i = openStatements_.listIterator(); i.hasNext(); ) { - Statement stmt = (Statement) i.next(); - stmt.markClosed(); - i.remove(); - } - } - - private void writeCloseStatements () throws SqlException - { - for (java.util.ListIterator i = openStatements_.listIterator(); i.hasNext(); ) { - ((Statement) i.next()).writeClose (false); // false means don't permit auto-commits - } - } - - private void readCloseStatements () throws SqlException - { - for (java.util.ListIterator i = openStatements_.listIterator(); i.hasNext(); ) { - ((Statement) i.next()).readClose (false); // false means don't permit auto-commits - } - } - - - public boolean isClosed () - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "isClosed", !open_); - return !open_; - } - - public boolean isClosedX () - { - return !open_; - } - - private static String DERBY_TRANSACTION_REPEATABLE_READ = "RS"; - private static String DERBY_TRANSACTION_SERIALIZABLE = "RR"; - private static String DERBY_TRANSACTION_READ_COMMITTED = "CS"; - private static String DERBY_TRANSACTION_READ_UNCOMMITTED = "UR"; - - synchronized public void setTransactionIsolation (int level) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setTransactionIsolation", level); - // Per jdbc spec (see java.sql.Connection.close() javadoc). - checkForClosedConnection (); + // get the server version + public int getServerVersion() { + return databaseMetaData_.productLevel_.versionLevel_; + } - // Javadoc for this method: - // If this method is called during a transaction, the result is implementation-defined. - // - // - // REPEATABLE_READ = JDBC: TRANSACTION_SERIALIZABLE, DERBY: RR, PROTOCOL: repeatable read - // READ_STABILITY = JDBC: TRANSACTION_REPEATABLE_READ, DERBY: RS, PROTOCOL: All - // CURSOR_STABILITY = JDBC: TRANSACTION_READ_COMMITTED, DERBY: CS, PROTOCOL: Cursor stability - // UNCOMMITTED_READ = JDBC: TRANSACTION_READ_UNCOMMITTED, DERBY: UR , PROTOCOL: Change - // NO_COMMIT = JDBC: TRANSACTION_NONE, DERBY: NC, PROTOCOL: No commit - // - String levelString = null; - switch (level) { - case java.sql.Connection.TRANSACTION_REPEATABLE_READ: - levelString = DERBY_TRANSACTION_REPEATABLE_READ; - break; - case java.sql.Connection.TRANSACTION_READ_COMMITTED: - levelString = DERBY_TRANSACTION_READ_COMMITTED; - break; - case java.sql.Connection.TRANSACTION_SERIALIZABLE: - levelString = DERBY_TRANSACTION_SERIALIZABLE; - break; - case java.sql.Connection.TRANSACTION_READ_UNCOMMITTED: - levelString = DERBY_TRANSACTION_READ_UNCOMMITTED; - break; - // Per javadoc: - // Note that Connection.TRANSACTION_NONE cannot be used because it specifies that transactions are not supported. - case java.sql.Connection.TRANSACTION_NONE: - default: - throw new SqlException (agent_.logWriter_, - "Transaction isolation level " + level + " is an invalid argument for java.sql.Connection.setTransactionIsolation()." + - " See Javadoc specification for a list of valid arguments.","XJ045"); - } - if (setTransactionIsolationStmt == null) - setTransactionIsolationStmt = - createStatementX(java.sql.ResultSet.TYPE_FORWARD_ONLY, - java.sql.ResultSet.CONCUR_READ_ONLY, - resultSetHoldability_); - setTransactionIsolationStmt.executeUpdate("SET CURRENT ISOLATION = " + levelString); - - isolation_ = level; - - } - - public int getTransactionIsolation () throws SqlException - { - checkForClosedConnection(); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getTransactionIsolation", isolation_); - return isolation_; - } - - public java.sql.SQLWarning getWarnings () - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getWarnings", warnings_); - return warnings_; - } - - synchronized public void clearWarnings () throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "clearWarnings"); - clearWarningsX(); - } - - // An untraced version of clearWarnings() - public void clearWarningsX () throws SqlException - { - warnings_ = null; - accumulated440ForMessageProcFailure_ = false; - accumulated444ForMessageProcFailure_ = false; - accumulatedSetReadOnlyWarning_ = false; - } - - //====================================================================== - // Advanced features: - - public java.sql.DatabaseMetaData getMetaData () throws SqlException - { - checkForClosedConnection(); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getMetaData", databaseMetaData_); - return databaseMetaData_; - } - - synchronized public void setReadOnly (boolean readOnly) throws SqlException - { - // This is a hint to the driver only, so this request is silently ignored. - // PROTOCOL can only flow a set-read-only before the connection is established. - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setReadOnly", readOnly); - checkForClosedConnection(); - } - - public boolean isReadOnly () throws SqlException - { - checkForClosedConnection(); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "isReadOnly", jdbcReadOnly_); - return false; - } - - synchronized public void setCatalog (String catalog) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setCatalog", catalog); - checkForClosedConnection(); - // Per jdbc spec: if the driver does not support catalogs, it will silently ignore this request. - } - - public String getCatalog () throws SqlException - { - checkForClosedConnection(); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getCatalog", (String) null); - return null; - } - - //--------------------------JDBC 2.0----------------------------- - - synchronized public java.sql.Statement createStatement (int resultSetType, - int resultSetConcurrency) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "createStatement", resultSetType, resultSetConcurrency); - Statement s = createStatementX (resultSetType, resultSetConcurrency, resultSetHoldability_); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "createStatement", s); - return s; - } - - synchronized public java.sql.PreparedStatement prepareStatement (String sql, - int resultSetType, - int resultSetConcurrency) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "prepareStatement", sql, resultSetType, resultSetConcurrency); - PreparedStatement ps = prepareStatementX (sql, - resultSetType, - resultSetConcurrency, - resultSetHoldability_, - java.sql.Statement.NO_GENERATED_KEYS, - null); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "prepareStatement", ps); - return ps; - } - - synchronized public java.sql.CallableStatement prepareCall (String sql, - int resultSetType, - int resultSetConcurrency) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "prepareCall", sql, resultSetType, resultSetConcurrency); - CallableStatement cs = prepareCallX (sql, resultSetType, resultSetConcurrency, resultSetHoldability_); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "prepareCall", cs); - return cs; - } - - synchronized public CallableStatement prepareMessageProc (String sql) throws SqlException - { - checkForClosedConnection (); - - CallableStatement cs = prepareCallX (sql, java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, resultSetHoldability_); - return cs; - } - - // Per jdbc spec, when a result set type is unsupported, we downgrade and - // issue a warning rather than to throw an exception. - private int downgradeResultSetType (int resultSetType) - { - if (resultSetType == java.sql.ResultSet.TYPE_SCROLL_SENSITIVE) { - accumulateWarning (new SqlWarning ( - agent_.logWriter_, "Scroll sensitive result sets are not supported by server; remapping to forward-only cursor")); - return java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; - } - return resultSetType; - } - - // Per jdbc spec, when a result set concurrency is unsupported, we downgrade and - // issue a warning rather than to throw an exception. - private int downgradeResultSetConcurrency (int resultSetConcurrency, int resultSetType) - { - if (resultSetConcurrency == java.sql.ResultSet.CONCUR_UPDATABLE && - resultSetType == java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE) { - accumulateWarning (new SqlWarning ( - agent_.logWriter_, "Insensitive updatable result sets are not supported by server; remapping to insensitive read-only cursor")); - return java.sql.ResultSet.CONCUR_READ_ONLY; - } - return resultSetConcurrency; - } - - public java.util.Map getTypeMap () throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "getTypeMap"); - checkForClosedConnection(); - java.util.Map map = new java.util.HashMap(); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getTypeMap", map); - return map; - } - - synchronized public void setTypeMap (java.util.Map map) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setTypeMap", map); - checkForClosedConnection(); - throw new SqlException (agent_.logWriter_, "Connection.setTypeMap is not supported"); - } - - //--------------------------JDBC 3.0----------------------------- - - synchronized public void setHoldability (int holdability) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setHoldability", holdability); - checkForClosedConnection(); - resultSetHoldability_ = holdability; - } - - public int getHoldability() throws SqlException - { - checkForClosedConnection(); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getHoldability", resultSetHoldability_); - return resultSetHoldability_; - } - - public int dncGeneratedSavepointId_; - // generated name used internally for unnamed savepoints - public static final String dncGeneratedSavepointNamePrefix__ = "DNC_GENENERATED_NAME_"; - - synchronized public java.sql.Savepoint setSavepoint() throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setSavepoint"); - checkForClosedConnection (); - if (autoCommit_) // Throw exception if auto-commit is on - throw new SqlException (agent_.logWriter_, "Cannot set savepoint when in auto-commit mode."); - else if (xaState_ == XA_PENDING_START || - xaState_ == XA_ACTIVE) // Throw exception if in distributed transaction - throw new SqlException (agent_.logWriter_, "Cannot set savepoint during distributed transaction."); - // create an un-named savepoint. - if ((++dncGeneratedSavepointId_) < 0) dncGeneratedSavepointId_ = 1; // restart from 1 when overflow. - Object s = setSavepointX (new Savepoint (agent_, dncGeneratedSavepointId_)); - return (java.sql.Savepoint) s; - } - - synchronized public java.sql.Savepoint setSavepoint (String name) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setSavepoint", name); - checkForClosedConnection (); - if (name == null) // Throw exception if savepoint name is null - throw new SqlException (agent_.logWriter_, "Named savepoint needs a none-null name."); - else if (autoCommit_) // Throw exception if auto-commit is on - throw new SqlException (agent_.logWriter_, "Cannot set savepoint when in auto-commit mode."); - else if (xaState_ == XA_PENDING_START || - xaState_ == XA_ACTIVE) // Throw exception if in distributed transaction - throw new SqlException (agent_.logWriter_, "Cannot set savepoint during distributed transaction."); - // create a named savepoint. - Object s = setSavepointX (new Savepoint (agent_, name)); - return (java.sql.Savepoint) s; - } - - private Savepoint setSavepointX (Savepoint savepoint) throws SqlException - { - // Construct and flow a savepoint statement to server. - Statement stmt = null; - try { - stmt = (Statement) createStatementX (java.sql.ResultSet.TYPE_FORWARD_ONLY, - java.sql.ResultSet.CONCUR_READ_ONLY, - resultSetHoldability_); - String savepointName; - try { - savepointName = savepoint.getSavepointName(); - } - catch (SqlException e) { - // generate the name for an un-named savepoint. - savepointName = dncGeneratedSavepointNamePrefix__ + - savepoint.getSavepointId(); - } - String sql = "SAVEPOINT \"" + savepointName + "\" ON ROLLBACK RETAIN CURSORS"; - stmt.executeX (sql); - } - finally { - if (stmt != null) - try { stmt.closeX(); } catch (SqlException doNothing) {} - } - - return savepoint; - } - - synchronized public void rollback (java.sql.Savepoint savepoint) throws SqlException - { - int saveXaState = xaState_; - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "rollback", savepoint); - checkForClosedConnection (); - if (savepoint == null) // Throw exception if savepoint is null - throw new SqlException (agent_.logWriter_, "Cannot rollback to a null savepoint."); - else if (autoCommit_) // Throw exception if auto-commit is on - throw new SqlException (agent_.logWriter_, "Cannot rollback to a savepoint when in auto-commit mode."); - else if (xaState_ == XA_PENDING_START || - xaState_ == XA_ACTIVE) // Throw exception if in distributed transaction - throw new SqlException (agent_.logWriter_, "Cannot rollback to a savepoint during distributed transaction."); - // Only allow to rollback to a savepoint from the connection that create the savepoint. - try { - if (this != ((Savepoint) savepoint).agent_.connection_) - throw new SqlException (agent_.logWriter_, - "Rollback to a savepoint not created by this connection."); - } - catch (java.lang.ClassCastException e) { // savepoint is not an instance of am.Savepoint - throw new SqlException (agent_.logWriter_, - "Rollback to a savepoint not created by this connection."); - } - - // Construct and flow a savepoint rollback statement to server. - Statement stmt = null; - try { - stmt = createStatementX (java.sql.ResultSet.TYPE_FORWARD_ONLY, - java.sql.ResultSet.CONCUR_READ_ONLY, - resultSetHoldability_); - String savepointName; - try { - savepointName = ((Savepoint) savepoint).getSavepointName(); - } - catch (SqlException e) { - // generate the name for an un-named savepoint. - savepointName = dncGeneratedSavepointNamePrefix__ + - ((Savepoint) savepoint).getSavepointId(); - } - String sql = "ROLLBACK TO SAVEPOINT \"" + savepointName + "\""; - stmt.executeX (sql); - } - finally { - if (stmt != null) - try { stmt.closeX(); } catch (SqlException doNothing) {} - xaState_ = saveXaState; - } - } - - synchronized public void releaseSavepoint (java.sql.Savepoint savepoint) throws SqlException - { - int saveXaState = xaState_; - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "releaseSavepoint", savepoint); - checkForClosedConnection (); - if (savepoint == null) // Throw exception if savepoint is null - throw new SqlException (agent_.logWriter_, "Cannot release a null savepoint."); - else if (autoCommit_) // Throw exception if auto-commit is on - throw new SqlException (agent_.logWriter_, "Cannot release a savepoint when in auto-commit mode."); - else if (xaState_ == XA_PENDING_START || - xaState_ == XA_ACTIVE) // Throw exception if in distributed transaction - throw new SqlException (agent_.logWriter_, "Cannot release a savepoint during distributed transaction."); - // Only allow to release a savepoint from the connection that create the savepoint. - try { - if (this != ((Savepoint) savepoint).agent_.connection_) - throw new SqlException (agent_.logWriter_, - "Cannot release a savepoint that was not created by this connection."); - } - catch (java.lang.ClassCastException e) { // savepoint is not an instance of am.Savepoint - throw new SqlException (agent_.logWriter_, - "Cannot release a savepoint that was not created by this connection."); - } - - // Construct and flow a savepoint release statement to server. - Statement stmt = null; - try { - stmt = (Statement) createStatementX (java.sql.ResultSet.TYPE_FORWARD_ONLY, - java.sql.ResultSet.CONCUR_READ_ONLY, - resultSetHoldability_); - String savepointName; - try { - savepointName = ((Savepoint) savepoint).getSavepointName(); - } - catch (SqlException e) { - // generate the name for an un-named savepoint. - savepointName = dncGeneratedSavepointNamePrefix__ + - ((Savepoint) savepoint).getSavepointId(); - } - String sql = "RELEASE SAVEPOINT \"" + savepointName + "\""; - stmt.executeX (sql); - } - finally { - if (stmt != null) - try { stmt.closeX(); } catch (SqlException doNothing) {} - xaState_ = saveXaState; - } - } - - synchronized public java.sql.Statement createStatement (int resultSetType, - int resultSetConcurrency, - int resultSetHoldability) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "createStatement", resultSetType, resultSetConcurrency, resultSetHoldability); - Statement s = createStatementX (resultSetType, resultSetConcurrency, resultSetHoldability); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "createStatement", s); - return s; - } - - private Statement createStatementX (int resultSetType, - int resultSetConcurrency, - int resultSetHoldability) throws SqlException - { - checkForClosedConnection (); - resultSetType = downgradeResultSetType (resultSetType); - resultSetConcurrency = downgradeResultSetConcurrency (resultSetConcurrency, resultSetType); - Statement s = newStatement_ (resultSetType, resultSetConcurrency, resultSetHoldability); - s.cursorAttributesToSendOnPrepare_ = s.cacheCursorAttributesToSendOnPrepare(); - openStatements_.add (s); - return s; - } - - // not sure if holding on to cursorAttributesToSendOnPrepare and restoring it is the - // right thing to do here... because if property on the dataSource changes, we may have - // to send different attributes, i.e. SENSITIVE DYNAMIC, instead of SENSITIVE STATIC. - protected void resetStatement (Statement s) throws SqlException - { - String cursorAttributesToSendOnPrepare = s.cursorAttributesToSendOnPrepare_; - resetStatement_ (s, s.resultSetType_, s.resultSetConcurrency_, s.resultSetHoldability_); - s.cursorAttributesToSendOnPrepare_ = cursorAttributesToSendOnPrepare; - } - - synchronized public java.sql.PreparedStatement prepareStatement (String sql, - int resultSetType, - int resultSetConcurrency, - int resultSetHoldability) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "prepareStatement", sql, resultSetType, resultSetConcurrency, resultSetHoldability); - PreparedStatement ps = prepareStatementX (sql, - resultSetType, - resultSetConcurrency, - resultSetHoldability, - java.sql.Statement.NO_GENERATED_KEYS, - null); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "prepareStatement", ps); - return ps; - } - - // used by DBMD - PreparedStatement prepareStatementX (String sql, - int resultSetType, - int resultSetConcurrency, - int resultSetHoldability, - int autoGeneratedKeys, - String[] columnNames) throws SqlException - { - checkForClosedConnection (); - checkAutoGeneratedKeysParameters (autoGeneratedKeys, columnNames); - resultSetType = downgradeResultSetType (resultSetType); - resultSetConcurrency = downgradeResultSetConcurrency (resultSetConcurrency, resultSetType); - PreparedStatement ps = newPreparedStatement_ (sql, resultSetType, resultSetConcurrency, resultSetHoldability, autoGeneratedKeys, columnNames); - ps.cursorAttributesToSendOnPrepare_ = ps.cacheCursorAttributesToSendOnPrepare(); - ps.prepare (); - openStatements_.add (ps); - return ps; - } - - // not sure if holding on to cursorAttributesToSendOnPrepare and restoring it is the - // right thing to do here... because if property on the dataSource changes, we may have - // to send different attributes, i.e. SENSITIVE DYNAMIC, instead of SENSITIVE STATIC. - protected void resetPrepareStatement (PreparedStatement ps) throws SqlException - { - String cursorAttributesToSendOnPrepare = ps.cursorAttributesToSendOnPrepare_; - resetPreparedStatement_ (ps, ps.sql_, ps.resultSetType_, ps.resultSetConcurrency_, ps.resultSetHoldability_, ps.autoGeneratedKeys_, ps.generatedKeysColumnNames_); - ps.cursorAttributesToSendOnPrepare_ = cursorAttributesToSendOnPrepare; - ps.prepare(); - } - - synchronized public java.sql.CallableStatement prepareCall (String sql, - int resultSetType, - int resultSetConcurrency, - int resultSetHoldability) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "prepareCall", sql, resultSetType, resultSetConcurrency, resultSetHoldability); - CallableStatement cs = prepareCallX (sql, resultSetType, resultSetConcurrency, resultSetHoldability); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "prepareCall", cs); - return cs; - } - - private CallableStatement prepareCallX (String sql, - int resultSetType, - int resultSetConcurrency, - int resultSetHoldability) throws SqlException - { - checkForClosedConnection (); - resultSetType = downgradeResultSetType (resultSetType); - resultSetConcurrency = downgradeResultSetConcurrency (resultSetConcurrency, resultSetType); - CallableStatement cs = newCallableStatement_ (sql, resultSetType, resultSetConcurrency, resultSetHoldability); - cs.cursorAttributesToSendOnPrepare_ = cs.cacheCursorAttributesToSendOnPrepare(); - cs.prepare (); - openStatements_.add (cs); - return cs; - } - - protected void resetPrepareCall (CallableStatement cs) throws SqlException - { - String cursorAttributesToSendOnPrepare = cs.cursorAttributesToSendOnPrepare_; - resetCallableStatement_ (cs, cs.sql_, cs.resultSetType_, cs.resultSetConcurrency_, cs.resultSetHoldability_); - cs.cursorAttributesToSendOnPrepare_ = cursorAttributesToSendOnPrepare; - cs.prepare (); - } - - public java.sql.PreparedStatement prepareStatement (String sql, int autoGeneratedKeys) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "prepareStatement", sql, autoGeneratedKeys); - PreparedStatement ps = prepareStatementX (sql, - java.sql.ResultSet.TYPE_FORWARD_ONLY, - java.sql.ResultSet.CONCUR_READ_ONLY, - resultSetHoldability_, - autoGeneratedKeys, - null); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "prepareStatement", ps); - return ps; - } - - public java.sql.PreparedStatement prepareStatement (String sql, int columnIndexes[]) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "prepareStatement", sql, columnIndexes); - checkForClosedConnection(); - throw new SqlException (agent_.logWriter_, "Driver not capable"); - } - - public java.sql.PreparedStatement prepareStatement (String sql, String columnNames[]) throws SqlException - { - if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "prepareStatement", sql, columnNames); - PreparedStatement ps = prepareStatementX (sql, - java.sql.ResultSet.TYPE_FORWARD_ONLY, - java.sql.ResultSet.CONCUR_READ_ONLY, - resultSetHoldability_, - java.sql.Statement.RETURN_GENERATED_KEYS, - columnNames); - if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "prepareStatement", ps); - return ps; - } - - - // --------------------------------------------------------------------------- - - protected abstract boolean allowCloseInUOW_(); - protected abstract boolean doCloseStatementsOnClose_(); - - public abstract SectionManager newSectionManager (String collection, - Agent agent, - String databaseName); - //--------------------Abstract material factory methods----------------- - - protected abstract Agent newAgent_ (LogWriter logWriter, int loginTimeout, String serverName, int portNumber) throws SqlException; - - - protected abstract DatabaseMetaData newDatabaseMetaData_ (); - protected abstract Statement newStatement_ (int type, - int concurrency, - int holdability) throws SqlException; - protected abstract void resetStatement_ (Statement statement, - int type, - int concurrency, - int holdability) throws SqlException; - - - protected abstract PreparedStatement newPositionedUpdatePreparedStatement_ (String sql, Section section) throws SqlException; - protected abstract PreparedStatement newPreparedStatement_ (String sql, - int type, - int concurrency, - int holdability, - int autoGeneratedKeys, - String[] columnNames) throws SqlException; - - protected abstract void resetPreparedStatement_ (PreparedStatement ps, - String sql, - int resultSetType, - int resultSetConcurrency, - int resultSetHoldability, - int autoGeneratedKeys, - String[] columnNames) throws SqlException; - - protected abstract CallableStatement newCallableStatement_ (String sql, - int type, - int concurrency, - int holdability) throws SqlException; - - protected abstract void resetCallableStatement_ (CallableStatement cs, - String sql, - int resultSetType, - int resultSetConcurrency, - int resultSetHoldability) throws SqlException; - - // ----------------------- abstract box car and callback methods --------------------- - // All callbacks must be client-side only operations. - - - public void completeConnect () throws SqlException - { - open_ = true; - databaseMetaData_ = newDatabaseMetaData_(); - - agent_.sectionManager_ = - newSectionManager ("NULLID", - agent_, - databaseName_); - if (agent_.loggingEnabled()) agent_.logWriter_.traceConnectExit (this); - } - - public abstract void writeCommitSubstitute_ () throws SqlException; - public abstract void readCommitSubstitute_ () throws SqlException; - - public abstract void writeLocalXAStart_ () throws SqlException; - public abstract void readLocalXAStart_ () throws SqlException; - - public abstract void writeLocalXACommit_ () throws SqlException; - public abstract void readLocalXACommit_ () throws SqlException; - - public abstract void writeLocalCommit_ () throws SqlException; - public abstract void readLocalCommit_ () throws SqlException; - public void completeLocalCommit () - { - for (java.util.Iterator i = CommitAndRollbackListeners_.iterator(); i.hasNext(); ) { - UnitOfWorkListener listener = (UnitOfWorkListener)i.next(); - listener.completeLocalCommit(i); - } - inUnitOfWork_ = false; - } - - public abstract void writeLocalRollback_ () throws SqlException; - public abstract void readLocalRollback_ () throws SqlException; - // A callback for certain non-fatal exceptions that occur when parsing error replies. - // This is a client-side only operation. - // This method will only throw an exception on bug check. - public void completeLocalRollback () - { - for (java.util.Iterator i = CommitAndRollbackListeners_.iterator(); i.hasNext(); ) { - UnitOfWorkListener listener = (UnitOfWorkListener)i.next(); - listener.completeLocalRollback (i); - } - for (java.util.Iterator i = RollbackOnlyListeners_.iterator(); i.hasNext(); ) { - UnitOfWorkListener listener = (UnitOfWorkListener)i.next(); - listener.completeLocalRollback (i); - } - inUnitOfWork_ = false; - } - - - public abstract void writeLocalXARollback_ () throws SqlException; - public abstract void readLocalXARollback_ () throws SqlException; - - public void writeTransactionStart(Statement statement) throws SqlException {} - public void readTransactionStart() throws SqlException { completeTransactionStart(); } - void completeTransactionStart() { inUnitOfWork_ = true; } - - // Occurs autonomously - public void completeAbnormalUnitOfWork () { completeLocalRollback (); } - - // Called by Connection.close(), NetConnection.errorRollbackDisconnect(). - // The Agent's client-side resources associated with database connection are reclaimed (eg. socket). - // And this connection and all associated statements and result sets are marked closed. - // This is a client-side only operation. - // This method will only throw an exception if the agent cannot be closed. - public void completeChainBreakingDisconnect () - { - open_ = false; - completeLocalRollback(); - markStatementsClosed(); - } - - public void completeSqlca (Sqlca sqlca) - { - if (sqlca == null) {} - else if (sqlca.getSqlCode() > 0) - accumulateWarning (new SqlWarning (agent_.logWriter_, sqlca)); - else if (sqlca.getSqlCode() < 0) - agent_.accumulateReadException (new SqlException (agent_.logWriter_, sqlca)); - } - - public abstract void addSpecialRegisters (String s); - - // can this only be called by the PooledConnection - // can this be called on a closed connection - // can this be called in a unit of work - // can this be called from within a stored procedure - // - synchronized public void reset (LogWriter logWriter, String user, String password, ClientDataSource ds, boolean recomputeFromDataSource) throws SqlException - { - if (logWriter != null) { - logWriter.traceConnectResetEntry (this, logWriter, user, (ds!=null)?ds:dataSource_); - } - try { - reset_ (logWriter, user, password, ds, recomputeFromDataSource); - } - catch (SqlException sqle) { - DisconnectException de = new DisconnectException ( - agent_, "An error occurred during connect reset and the connection has been terminated. See chained exceptions for details."); - de.setNextException (sqle); - throw de; - } - } - - synchronized public void reset (LogWriter logWriter, ClientDataSource ds, boolean recomputeFromDataSource) throws SqlException - { - if (logWriter != null) { - logWriter.traceConnectResetEntry (this, logWriter, null, (ds!=null)?ds:dataSource_); - } - try { - reset_ (logWriter, ds, recomputeFromDataSource); - } - catch (SqlException sqle) { - DisconnectException de = new DisconnectException ( - agent_, "An error occurred during connect reset and the connection has been terminated. See chained exceptions for details."); - de.setNextException (sqle); - throw de; - } - } - - synchronized public void lightReset () throws SqlException - { - if (!open_ && !availableForReuse_) return; - open_ = true; - availableForReuse_ = false; - } - - abstract protected void reset_ (LogWriter logWriter, String user, String password, ClientDataSource ds, boolean recomputerFromDataSource) throws SqlException; - abstract protected void reset_ (LogWriter logWriter, ClientDataSource ds, boolean recomputerFromDataSource) throws SqlException; - protected void completeReset (boolean isDeferredReset, boolean recomputeFromDataSource) throws SqlException - { - open_ = true; - - completeLocalRollback(); // this will close the cursors if the physical connection hadn't been closed for reuse properly - - // Reopen physical statement resources associated with previous uses of this physical connection. - // Notice that these physical statements may not belong to this logical connection. - // Iterate through the physical statements and re-enable them for reuse. - - for (java.util.Iterator i = openStatements_.iterator(); i.hasNext(); ) { - Object o = i.next(); - ((Statement)o).reset (recomputeFromDataSource); - - } - - if (!isDeferredReset && agent_.loggingEnabled()) agent_.logWriter_.traceConnectResetExit (this); - } - - - //-------------------------------helper methods------------------------------- - - protected void checkForClosedConnection () throws SqlException - { - if (!open_) { - agent_.checkForDeferredExceptions(); - throw new SqlException (agent_.logWriter_, "invalid operation: connection closed"); - } - else { - agent_.checkForDeferredExceptions(); - } - } - - void checkAutoGeneratedKeysParameters (int autoGeneratedKeys, String[] columnNames) throws SqlException - { - if (autoGeneratedKeys != java.sql.Statement.NO_GENERATED_KEYS && - autoGeneratedKeys != java.sql.Statement.RETURN_GENERATED_KEYS) - throw new SqlException (agent_.logWriter_, "Invalid argument: " + - "Statement auto-generated keys value " + autoGeneratedKeys + - " is invalid."); - - if (columnNames != null) - throw new SqlException (agent_.logWriter_, "Driver not capable"); - - } - - public boolean isXAConnection() { return isXAConnection_; } - public int getXAState() { return xaState_; } - public void setXAState (int state) { xaState_ = state; } - - public void accumulateWarning (SqlWarning e) - { - if (warnings_ == null) - warnings_ = e; - else - warnings_.setNextException (e); - } - - public void accumulate440WarningForMessageProcFailure (SqlWarning e) - { if (!accumulated440ForMessageProcFailure_) { accumulateWarning (e); accumulated440ForMessageProcFailure_ = true; }} - - public void accumulate444WarningForMessageProcFailure (SqlWarning e) - { if (!accumulated444ForMessageProcFailure_) { accumulateWarning (e); accumulated444ForMessageProcFailure_ = true; }} - - // get the server version - public int getServerVersion() - { - return databaseMetaData_.productLevel_.versionLevel_; - } - - public void setInUnitOfWork (boolean inUnitOfWork) - { - inUnitOfWork_ = inUnitOfWork; - } + public void setInUnitOfWork(boolean inUnitOfWork) { + inUnitOfWork_ = inUnitOfWork; + } }
infrastructure at apache.org | ViewVC Help |
Powered by ViewVC 1.1.26 |