You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by jb...@apache.org on 2005/05/02 08:26:03 UTC
svn commit: r165585 [22/42] - in
/incubator/derby/code/trunk/java/client/org/apache/derby: client/
client/am/ client/net/ client/resources/ jdbc/
Modified: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Statement.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Statement.java?rev=165585&r1=165584&r2=165585&view=diff
==============================================================================
--- incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Statement.java (original)
+++ incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Statement.java Sun May 1 23:25:59 2005
@@ -19,1957 +19,2093 @@
*/
package org.apache.derby.client.am;
-import org.apache.derby.client.am.Section;
-public class Statement implements java.sql.Statement, StatementCallbackInterface, UnitOfWorkListener
-{
- // JDBC 3 constant indicating that the current ResultSet object
- // should be closed when calling getMoreResults.
- // Constant value matches that defined by JDBC 3 java.sql.Statement.CLOSE_CURRENT_RESULT
- public final static int CLOSE_CURRENT_RESULT = 1;
-
- // JDBC 3 constant indicating that the current ResultSet object
- // should not be closed when calling getMoreResults.
- // Constant value matches that defined by JDBC 3 java.sql.Statement.KEEP_CURRENT_RESULT
- public final static int KEEP_CURRENT_RESULT = 2;
-
- // JDBC 3 constant indicating that all ResultSet objects that
- // have previously been kept open should be closed when calling getMoreResults.
- // Constant value matches that defined by JDBC 3 java.sql.Statement.CLOSE_ALL_RESULTS
- public final static int CLOSE_ALL_RESULTS = 3;
-
- //---------------------navigational members-----------------------------------
-
- public MaterialStatement materialStatement_ = null;
-
- public Connection connection_;
- private SqlWarning warnings_ = null;
- public Section section_;
- public Agent agent_;
-
- public ResultSet resultSet_ = null;
-
- // Use -1, if there is no update count returned, ie. when result set is returned. 0 is a valid update count for DDL.
- int updateCount_ = -1;
- int returnValueFromProcedure_;
-
- // Enumeration of the flavors of statement execute call used.
- static final int executeQueryMethod__ = 1;
- static final int executeUpdateMethod__ = 2;
- static final int executeMethod__ = 3;
-
- // sqlMode_ will be moved to PS as soon as we remove the hack reference in completeExecute()
- // Enumerated in Statement: S.sqlIsQuery__, S.sqlIsCall__, S.sqlIsUpdate__
- // Determines whether sql_ starts with SELECT/VALUES, CALL, or other (assumed to be an update).
- protected int sqlMode_ = 0;
- // Enum for sqlMode_:
- static final int isQuery__ = 0x1; // sql starts with SELECT.... or VALUES...
- static final int isCall__ = 0x2; // sql starts with CALL ...
- static final int isUpdate__ = 0x4; // All other sql is categorized as a update DML or DDL.
-
- // sqlUpdateMode_ is only set when the sqlMode_ == isUpdate__
- public int sqlUpdateMode_ = 0;
- // Enum for sqlUpdateMode_:
- public final static int isCommitSql__ = 0x1;
- public final static int isRollbackSql__ = 0x2;
- final static int isPositionedUpdateDeleteSql__ = 0x10;
- final static int isInsertSql__ = 0x20; // used to recognize "insert" for auto-generated keys
- final static int isDeleteSql__ = 0x40; // used to recognize "delete" for parsing cursorname
- final static int isUpdateSql__ = 0x80; // used to recognize "update" for parsing cursorname
-
-
- public ColumnMetaData resultSetMetaData_; // type information for output sqlda
-
- // these two are used during parsing of literals for call statement.
- // please add a comment desribing what why you can't reuse inputs_ and parameterMetaData_
- // members for the literal inputs
-
- // Caching the Cursor object for reuse.
- public Cursor cachedCursor_ = null;
- public Cursor cachedSingletonRowData_ = null;
- public boolean isPreparedStatement_ = false;
- public boolean isCallableStatement_ = false; // we can get rid of this member once we define polymorphic reset() on S/PS/CS
-
- //---------------------navigational cheat-links-------------------------------
- // Cheat-links are for convenience only, and are not part of the conceptual model.
- // Warning:
- // Cheat-links should only be defined for invariant state data.
- // That is, state data that is set by the constructor and never changes.
-
- // Alias for connection_.databaseMetaData
- public DatabaseMetaData databaseMetaData_;
-
- //-----------------------------state------------------------------------------
-
- // Jdbc 1 positioned updates are implemented via
- // sql scan for "...where current of <users-cursor-name>",
- // the addition of mappings from cursor names to query sections,
- // and the subtitution of <users-cursor-name> with <canned-cursor-name> in the pass-thru sql string
- // "...where current of <canned-cursor-name>" when user-defined cursor names are used.
- // Both "canned" cursor names (from our jdbc package set) and user-defined cursor names are mapped.
- // Statement.cursorName_ is initialized to null until the cursor name is requested or set.
- // When set (s.setCursorName()) with a user-defined name, then it is added to the cursor map at that time;
- // When requested (rs.getCursorName()), if the cursor name is still null,
- // then is given the canned cursor name as defined by our jdbc package set and added to the cursor map.
- // Still need to consider how positioned updates should interact with multiple result sets from a stored.
- String cursorName_ = null;
-
- // This means the client-side jdbc statement object is open.
- // This value is set to true when the statement object is constructed, and will not change
- // until statement.close() is called either directly or via connection.close(), finalizer, or other methods.
- boolean openOnClient_ = true;
- // This means a DERBY server-side section for this statement is in the prepared state.
- // A client-side jdbc statement may remain open across commits (openOnClient=true),
- // but the server-side DERBY section moves to an unprepared state (openOnServer=false) across commits,
- // requiring an implicit re-prepare "under the covers" by the driver.
- // Unprepared jdbc query statements still have prepared sections on the server.
- // This openOnServer_ only has implications for preparedstatement
- boolean openOnServer_ = false;
-
-
- //private int indexOfCurrentResultSet_ = -1;
- protected int indexOfCurrentResultSet_ = -1;
- ResultSet [] resultSetList_ = null; // array of ResultSet objects
-
- int timeout_ = 0; // for query timeout in seconds, multiplied by 1000 when passed to java.util.Timer
- int maxRows_ = 0;
- int maxFieldSize_ = 0; // zero means that there is no limit to the size of a column.
- boolean escapedProcedureCallWithResult_ = false;
-
- // When this is false we skip autocommit for this PreparedStatement.
- // This is needed when the PreparedStatement object is used internally by
- // the driver and a commit is not desired, e.g., Blob/Clob API calls
- public boolean isAutoCommittableStatement_ = true;
-
- // The user has no control over the statement that owns a catalog query, and has no ability to close that statement.
- // We need a special member variable on our internal catalog query statements so that
- // when the catalog query is closed, the result set will know to close it's owning statement.
- boolean isCatalogQuery_ = false;
-
-
- // This collection is used for two different purposes:
- // For statement batching it contains the batched SQL strings.
- // For prepared statement batching it contains the batched input rows.
- java.util.ArrayList batch_ = new java.util.ArrayList();
-
-
- // Scrollable cursor attributes
- public int resultSetType_ = java.sql.ResultSet.TYPE_FORWARD_ONLY;
- public int resultSetConcurrency_ = java.sql.ResultSet.CONCUR_READ_ONLY;
- public int resultSetHoldability_;
- // This is ignored by the driver if this is zero.
- // For the net forward-only result set, if fetchSize is unset, we let the server return however many rows will fit in a query block.
- // For the net scrollable result set, then we use a default of 64 rows.
- public int fetchSize_ = 0;
- public int fetchDirection_ = java.sql.ResultSet.FETCH_FORWARD;
-
- // Conceptually this doesn't belong in Statement, but belongs in PreparedStatement,
- // since Statement doesn't know about params, so we're just putting it here perhaps temporarily,
- // Used for callable statement OUT paramters.
- public Cursor singletonRowData_ = null;
-
- // number of invisible result sets returned from a stored procedure.
- public int numInvisibleRS_ = 0;
-
- // This is a cache of the attributes to be sent on prepare.
- // Think about caching the entire prepare DDM string for the re-prepares
- public String cursorAttributesToSendOnPrepare_ = null;
-
- // The following members are for the exclusive use of prepared statements that require auto-generated keys to be returned
- public PreparedStatement preparedStatementForAutoGeneratedKeys_;
- public ResultSet generatedKeysResultSet_;
- public String[] generatedKeysColumnNames_;
- public int autoGeneratedKeys_ = java.sql.Statement.NO_GENERATED_KEYS;
-
- // This flag makes sure that only one copy of this statement
- // will be in connection_.commitListeners_.
-
-
- //---------------------constructors/finalizer---------------------------------
-
- private Statement() throws SqlException
- {
- initStatement();
- }
-
- private void resetStatement() throws SqlException
- {
- initStatement();
- }
-
- private void initStatement() throws SqlException
- {
- materialStatement_ = null;
- connection_ = null;
- agent_ = null;
- databaseMetaData_ = null;
- resultSetType_ = java.sql.ResultSet.TYPE_FORWARD_ONLY;
- resultSetConcurrency_ = java.sql.ResultSet.CONCUR_READ_ONLY;
- resultSetHoldability_ = 0;
- cursorAttributesToSendOnPrepare_ = null;
-
- initResetStatement();
- }
-
- private void initResetStatement() throws SqlException
- {
- initResetPreparedStatement();
-
- //section_ = null; // don't set section to null because write piggyback command require a section
- if (section_ != null)
- section_.free();
- sqlMode_ = 0;
- sqlUpdateMode_ = 0;
- resultSetMetaData_ = null;
- }
-
- protected void initResetPreparedStatement ()
- {
- warnings_ = null;
- //section_ = null;
- resultSet_ = null;
- updateCount_ = -1;
- returnValueFromProcedure_ = 0;
- cursorName_ = null;
- openOnClient_ = true;
- openOnServer_ = false;
- indexOfCurrentResultSet_ = -1;
- resultSetList_ = null;
- timeout_ = 0;
- maxRows_ = 0;
- maxFieldSize_ = 0;
- escapedProcedureCallWithResult_ = false;
- isCatalogQuery_ = false;
- isAutoCommittableStatement_ = true;
-
- if (batch_ == null)
- batch_ = new java.util.ArrayList();
- else
- batch_.clear();
- fetchSize_ = 0;
- fetchDirection_ = java.sql.ResultSet.FETCH_FORWARD;
- singletonRowData_ = null;
- numInvisibleRS_ = 0;
- preparedStatementForAutoGeneratedKeys_ = null;
- generatedKeysResultSet_ = null;
- generatedKeysColumnNames_ = null;
- autoGeneratedKeys_ = java.sql.Statement.NO_GENERATED_KEYS;
-
- // these members were not initialized
- isPreparedStatement_ = false;
- }
-
- // If a dataSource is passed into resetClientConnection(), then we will assume
- // properties on the dataSource may have changed, and we will need to go through
- // the open-statement list on the connection and do a full reset on all statements,
- // including preparedStatement's and callableStatement's. This is because property
- // change may influence the section we allocate for the preparedStatement, and
- // also the cursor attributes, i.e. setCursorSensitivity().
- // If no dataSource is passed into resetClientConnection(), then we will do the
- // minimum reset required for preparedStatement's and callableStatement's.
- public void reset (boolean fullReset) throws SqlException
- {
- if (fullReset)
- connection_.resetStatement (this);
- else {
- initResetStatement();
- materialStatement_.reset_();
- }
- }
-
- public Statement (Agent agent, Connection connection) throws SqlException
- {
- this();
- initStatement (agent, connection);
- }
-
- public void resetStatement (Agent agent, Connection connection) throws SqlException
- {
- resetStatement();
- initStatement (agent, connection);
- }
-
- private void initStatement (Agent agent, Connection connection)
- {
- agent_ = agent;
- connection_ = connection;
- databaseMetaData_ = connection.databaseMetaData_;
- }
-
- // For jdbc 2 statements with scroll attributes
- public Statement (Agent agent, Connection connection, int type, int concurrency, int holdability,
- int autoGeneratedKeys, String[] columnNames) throws SqlException
- {
- this (agent, connection);
- initStatement (type, concurrency, holdability, autoGeneratedKeys, columnNames);
- }
-
- public void resetStatement (Agent agent, Connection connection, int type, int concurrency, int holdability,
- int autoGeneratedKeys, String[] columnNames) throws SqlException
- {
- resetStatement (agent, connection);
- initStatement (type, concurrency, holdability, autoGeneratedKeys, columnNames);
- }
-
- private void initStatement (int type, int concurrency, int holdability,
- int autoGeneratedKeys, String[] columnNames) throws SqlException
- {
- switch (type) {
- case java.sql.ResultSet.TYPE_FORWARD_ONLY:
- case java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE:
- case java.sql.ResultSet.TYPE_SCROLL_SENSITIVE:
- resultSetType_ = type;
- break;
- default:
- throw new SqlException (agent_.logWriter_, "Invalid argument: " +
- "ResultSet Type " + type + " is invalid.");
- }
-
- switch (concurrency) {
- case java.sql.ResultSet.CONCUR_READ_ONLY:
- case java.sql.ResultSet.CONCUR_UPDATABLE:
- resultSetConcurrency_ = concurrency;
- break;
- default:
- throw new SqlException (agent_.logWriter_, "Invalid argument: " +
- "ResultSet Concurrency " + concurrency + " is invalid.");
- }
-
- switch (holdability) {
- case org.apache.derby.jdbc.ClientDataSource.CLOSE_CURSORS_AT_COMMIT:
- case org.apache.derby.jdbc.ClientDataSource.HOLD_CURSORS_OVER_COMMIT:
- resultSetHoldability_ = holdability;
- break;
- default:
- throw new SqlException (agent_.logWriter_, "Invalid argument: " +
- "ResultSet holdability " + holdability + " is invalid.");
- }
-
- switch (autoGeneratedKeys) {
- case java.sql.Statement.NO_GENERATED_KEYS:
- case java.sql.Statement.RETURN_GENERATED_KEYS:
- autoGeneratedKeys_ = autoGeneratedKeys;
- break;
- default:
- throw new SqlException (agent_.logWriter_, "Invalid argument: " +
- "Statement auto-generated keys value " + autoGeneratedKeys +
- " is invalid.");
- }
-
- generatedKeysColumnNames_ = columnNames;
- }
-
- protected void finalize () throws java.lang.Throwable
- {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "finalize");
- if (openOnClient_) {
- synchronized (connection_) {
- closeX();
- }
- }
- super.finalize();
- }
-
- // ---------------------------jdbc 1------------------------------------------
-
- public java.sql.ResultSet executeQuery (String sql) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "executeQuery", sql);
- ResultSet resultSet = executeQueryX (sql);
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "executeQuery", resultSet);
- return resultSet;
- }
- }
-
- private ResultSet executeQueryX (String sql) throws SqlException
- {
- flowExecute (executeQueryMethod__, sql);
-
- checkExecuteQueryPostConditions ("java.sql.Statement");
- return resultSet_;
- }
-
- void checkExecuteQueryPostConditions (String jdbcStatementInterfaceName) throws SqlException
- {
- // We'll just rely on finalizers to close the dangling result sets.
- if (resultSetList_ != null && resultSetList_.length != 1)
- throw new SqlException (agent_.logWriter_, jdbcStatementInterfaceName + ".executeQuery() cannot be called " +
- "because multiple result sets were returned." +
- " Use " + jdbcStatementInterfaceName + ".execute() to obtain multiple results.");
-
- if (resultSet_ == null)
- throw new SqlException (agent_.logWriter_, jdbcStatementInterfaceName + ".executeQuery() was called " +
- "but no result set was returned."+
- " Use " + jdbcStatementInterfaceName + ".executeUpdate() for non-queries.");
- }
-
- public int executeUpdate (String sql) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "executeUpdate", sql);
- int updateValue = executeUpdateX (sql);
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "executeUpdate", updateValue);
- return updateValue;
- }
- }
- private int executeUpdateX (String sql) throws SqlException
- {
- flowExecute (executeUpdateMethod__, sql);
-
- checkExecuteUpdatePostConditions ("java.sql.Statement");
- return updateCount_;
- }
-
- void checkExecuteUpdatePostConditions (String jdbcStatementInterfaceName) throws SqlException
- {
- // We'll just rely on finalizers to close the dangling result sets.
- if (resultSetList_ != null)
- throw new SqlException (agent_.logWriter_, jdbcStatementInterfaceName + ".executeUpdate() cannot be called " +
- "because multiple result sets returned." +
- " Use " + jdbcStatementInterfaceName + ".execute() to obtain multiple results.");
-
- // We'll just rely on the finalizer to close the dangling result set.
- if (resultSet_ != null)
- throw new SqlException (agent_.logWriter_, jdbcStatementInterfaceName + ".executeUpdate() was called " +
- "but a result set was returned." +
- " Use " + jdbcStatementInterfaceName + ".executeQuery() to obtain a result set.");
- }
-
- // The server holds statement resources until transaction end.
- public void close () throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "close");
- closeX();
- }
- }
-
- // An untraced version of close()
- public void closeX () throws SqlException
- {
- if (!openOnClient_) return;
- // Regardless of whether or not this statement is in the prepared state,
- // we need to close any open cursors for this statement on the server.
- int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : resultSetList_.length;
- boolean willTickleServer = willTickleServer (numberOfResultSetsToClose, true);
- try {
- if (willTickleServer)
- flowClose ();
- else
- flowCloseOutsideUOW ();
- }
- finally {
- markClosed();
- connection_.openStatements_.remove (this);
- }
- // push the mark close of rsmd into Statement.markClosed() method
- if (resultSetMetaData_ != null) {
- resultSetMetaData_.markClosed();
- resultSetMetaData_ = null;
- }
- }
-
- public int getMaxFieldSize () throws SqlException
- {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "getMaxFieldSize");
- checkForClosedStatement ();
- return maxFieldSize_;
- }
-
- public void setMaxFieldSize (int max) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setMaxFieldSize", max);
- checkForClosedStatement ();
- if (max < 0) throw new SqlException (agent_.logWriter_, "Invalid maxFieldSize value: " + max);
- maxFieldSize_ = max;
- }
- }
-
- public int getMaxRows () throws SqlException
- {
- checkForClosedStatement ();
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getMaxRows", maxRows_);
- return maxRows_;
- }
-
- public void setMaxRows (int maxRows) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setMaxRows", maxRows);
- checkForClosedStatement (); // Per jdbc spec (see java.sql.Statement.close() javadoc)
- if (maxRows < 0) throw new SqlException (agent_.logWriter_, "Invalid maxRows value: " + maxRows);
- maxRows_ = maxRows;
- }
- }
-
- public void setEscapeProcessing (boolean enable) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setEscapeProcessing", enable);
- checkForClosedStatement (); // Per jdbc spec (see java.sql.Statement.close() javadoc)
- }
- }
-
- public int getQueryTimeout () throws SqlException
- {
- checkForClosedStatement ();
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getQueryTimeout", timeout_);
- return timeout_;
- }
-
- public void setQueryTimeout (int seconds) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setQueryTimeout", seconds);
- checkForClosedStatement (); // Per jdbc spec (see java.sql.Statement.close() javadoc)
- if (seconds < 0) throw new SqlException (agent_.logWriter_, "Attempt to set a negative query timeout");
- timeout_ = seconds; // java.util.Timer takes milliseconds
- }
- }
-
- public void cancel () throws SqlException
- {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "cancel");
- checkForClosedStatement (); // Per jdbc spec (see java.sql.Statement.close() javadoc)
- throw new SqlException (agent_.logWriter_, "cancel() not supported by server");
- }
-
- public java.sql.SQLWarning getWarnings () throws SqlException
- {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getWarnings", warnings_);
- return warnings_;
- }
-
- public void clearWarnings () throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "clearWarnings");
- clearWarningsX();
- }
- }
-
- // An untraced version of clearWarnings()
- public void clearWarningsX ()
- {
- warnings_ = null;
- }
-
- // Dnc statements are already associated with a unique cursor name as defined
- // by our canned dnc package set.
- // ResultSet.getCursorName() should be used to
- // obtain the for update cursor name to use when executing a positioned update statement.
- // See Jdbc 3 spec section 14.2.4.4.
- public void setCursorName (String name) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setCursorName", name);
- checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
- if (name == null || name.equals ("")) throw new SqlException (agent_.logWriter_, "Invalid cursor name.");
-
- // Invalid to set the cursor name if there are ResultSet's open on the Statement.
- if (resultSet_ != null && resultSet_.openOnClient_)
- throw new SqlException (agent_.logWriter_, "Invalid operation: setCursorName() " +
- "called when there are open ResultSet's on the Statement.");
-
- // Duplicate cursor names not allowed.
- if (connection_.clientCursorNameCache_.containsKey (name))
- throw new SqlException (agent_.logWriter_, "Duplicate cursor names are not allowed.");
- connection_.clientCursorNameCache_.put (name, name);
-
- // section_ is null for Statement objects. We will defer the mapping of cursorName
- // to section until when the query is executed.
- if (section_ != null) {
- agent_.sectionManager_.mapCursorNameToQuerySection (name, (Section) section_);
-
- // This means we must subtitute the <users-cursor-name> with the <canned-cursor-name>
- // in the pass-thru sql string "...where current of <canned-cursor-name>".
- section_.setClientCursorName (name);
- }
- cursorName_ = name;
- }
- }
-
- //----------------------- Multiple Results --------------------------
-
-
- public boolean execute (String sql) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "execute", sql);
- boolean b = executeX (sql);
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "execute", b);
- return b;
- }
- }
-
- boolean executeX (String sql) throws SqlException
- {
- flowExecute (executeMethod__, sql);
- return resultSet_ != null;
- }
-
- public java.sql.ResultSet getResultSet () throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "getResultSet");
- checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getResultSet", resultSet_);
- return resultSet_;
- }
- }
-
- public int getUpdateCount () throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "getUpdateCount");
- checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getUpdateCount", updateCount_);
- return updateCount_;
- }
- }
-
- public boolean getMoreResults () throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "getMoreResults");
- boolean resultIsResultSet = getMoreResultsX (CLOSE_ALL_RESULTS);
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getMoreResults", resultIsResultSet);
- return resultIsResultSet;
- }
- }
-
- //--------------------------JDBC 2.0-----------------------------
-
- public void setFetchDirection (int direction) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setFetchDirection", direction);
- checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
- switch (direction) {
- case java.sql.ResultSet.FETCH_FORWARD:
- case java.sql.ResultSet.FETCH_REVERSE:
- case java.sql.ResultSet.FETCH_UNKNOWN:
- fetchDirection_ = direction;
- break;
- default:
- throw new SqlException (agent_.logWriter_, "Invalid fetch direction " + direction);
- }
- }
- }
-
- public int getFetchDirection () throws SqlException
- {
- checkForClosedStatement ();
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getFetchDirection", fetchDirection_);
- return fetchDirection_;
- }
-
- public void setFetchSize (int rows) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "setFetchSize", rows);
- checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
-
- if (rows < 0 || (maxRows_ != 0 && rows > maxRows_))
- throw new SqlException (agent_.logWriter_, "Invalid fetch size " + rows);
- fetchSize_ = rows;
- }
- }
-
- public int getFetchSize () throws SqlException
- {
- checkForClosedStatement ();
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getFetchSize", fetchSize_);
- return fetchSize_;
- }
-
- public int getResultSetConcurrency () throws SqlException
- {
- checkForClosedStatement ();
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getResultSetConcurrency", resultSetConcurrency_);
- return resultSetConcurrency_;
- }
-
- public int getResultSetType () throws SqlException
- {
- checkForClosedStatement ();
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getResultSetType", resultSetType_);
- return resultSetType_;
- }
-
- public void addBatch (String sql) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "addBatch", sql);
- checkForClosedStatement ();
- sql = connection_.nativeSQLX (sql);
- batch_.add (sql);
- }
- }
-
- public void clearBatch () throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "clearBatch");
- checkForClosedStatement ();
- batch_.clear ();
- }
- }
-
- public int[] executeBatch () throws SqlException, BatchUpdateException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "executeBatch");
- int [] updateCounts = executeBatchX();
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "executeBatch", updateCounts);
- return updateCounts;
- }
- }
-
- private int[] executeBatchX () throws SqlException, BatchUpdateException
- {
- checkForClosedStatement (); // Per jdbc spec (see java.sql.Statement.close() javadoc)
- clearWarningsX (); // Per jdbc spec 0.7, and getWarnings() javadoc
- resultSetList_ = null;
-
- // Initialize all the updateCounts to indicate failure
- // This is done to account for "chain-breaking" errors where we cannot
- // read any more replies
- int[] updateCounts = new int[batch_.size()];
- for (int i = 0; i < batch_.size(); i++){
- updateCounts[i] = -3;
- }
- flowExecuteBatch (updateCounts);
-
- return updateCounts;
- }
-
- public java.sql.Connection getConnection () throws SqlException
- {
- checkForClosedStatement ();
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getConnection", connection_);
- return connection_;
- }
-
- //--------------------------JDBC 3.0-----------------------------
-
- public boolean getMoreResults (int current) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "getMoreResults", current);
- boolean resultIsResultSet = getMoreResultsX (current);
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getMoreResults", resultIsResultSet);
- return resultIsResultSet;
- }
- }
-
- private boolean getMoreResultsX (int current) throws SqlException
- {
- checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
- boolean resultIsResultSet;
- updateCount_ = -1;
- if (resultSetList_ == null) {
- if (resultSet_ != null) {
- if (current != KEEP_CURRENT_RESULT) resultSet_.closeX();
+public class Statement implements java.sql.Statement, StatementCallbackInterface, UnitOfWorkListener {
+
+ // JDBC 3 constant indicating that the current ResultSet object
+ // should be closed when calling getMoreResults.
+ // Constant value matches that defined by JDBC 3 java.sql.Statement.CLOSE_CURRENT_RESULT
+ public final static int CLOSE_CURRENT_RESULT = 1;
+
+ // JDBC 3 constant indicating that the current ResultSet object
+ // should not be closed when calling getMoreResults.
+ // Constant value matches that defined by JDBC 3 java.sql.Statement.KEEP_CURRENT_RESULT
+ public final static int KEEP_CURRENT_RESULT = 2;
+
+ // JDBC 3 constant indicating that all ResultSet objects that
+ // have previously been kept open should be closed when calling getMoreResults.
+ // Constant value matches that defined by JDBC 3 java.sql.Statement.CLOSE_ALL_RESULTS
+ public final static int CLOSE_ALL_RESULTS = 3;
+
+ //---------------------navigational members-----------------------------------
+
+ public MaterialStatement materialStatement_ = null;
+
+ public Connection connection_;
+ private SqlWarning warnings_ = null;
+ public Section section_;
+ public Agent agent_;
+
+ public ResultSet resultSet_ = null;
+
+ // Use -1, if there is no update count returned, ie. when result set is returned. 0 is a valid update count for DDL.
+ int updateCount_ = -1;
+ int returnValueFromProcedure_;
+
+ // Enumeration of the flavors of statement execute call used.
+ static final int executeQueryMethod__ = 1;
+ static final int executeUpdateMethod__ = 2;
+ static final int executeMethod__ = 3;
+
+ // sqlMode_ will be moved to PS as soon as we remove the hack reference in completeExecute()
+ // Enumerated in Statement: S.sqlIsQuery__, S.sqlIsCall__, S.sqlIsUpdate__
+ // Determines whether sql_ starts with SELECT/VALUES, CALL, or other (assumed to be an update).
+ protected int sqlMode_ = 0;
+ // Enum for sqlMode_:
+ static final int isQuery__ = 0x1; // sql starts with SELECT.... or VALUES...
+ static final int isCall__ = 0x2; // sql starts with CALL ...
+ static final int isUpdate__ = 0x4; // All other sql is categorized as a update DML or DDL.
+
+ // sqlUpdateMode_ is only set when the sqlMode_ == isUpdate__
+ public int sqlUpdateMode_ = 0;
+ // Enum for sqlUpdateMode_:
+ public final static int isCommitSql__ = 0x1;
+ public final static int isRollbackSql__ = 0x2;
+ final static int isPositionedUpdateDeleteSql__ = 0x10;
+ final static int isInsertSql__ = 0x20; // used to recognize "insert" for auto-generated keys
+ final static int isDeleteSql__ = 0x40; // used to recognize "delete" for parsing cursorname
+ final static int isUpdateSql__ = 0x80; // used to recognize "update" for parsing cursorname
+
+
+ public ColumnMetaData resultSetMetaData_; // type information for output sqlda
+
+ // these two are used during parsing of literals for call statement.
+ // please add a comment desribing what why you can't reuse inputs_ and parameterMetaData_
+ // members for the literal inputs
+
+ // Caching the Cursor object for reuse.
+ public Cursor cachedCursor_ = null;
+ public Cursor cachedSingletonRowData_ = null;
+ public boolean isPreparedStatement_ = false;
+ public boolean isCallableStatement_ = false; // we can get rid of this member once we define polymorphic reset() on S/PS/CS
+
+ //---------------------navigational cheat-links-------------------------------
+ // Cheat-links are for convenience only, and are not part of the conceptual model.
+ // Warning:
+ // Cheat-links should only be defined for invariant state data.
+ // That is, state data that is set by the constructor and never changes.
+
+ // Alias for connection_.databaseMetaData
+ public DatabaseMetaData databaseMetaData_;
+
+ //-----------------------------state------------------------------------------
+
+ // Jdbc 1 positioned updates are implemented via
+ // sql scan for "...where current of <users-cursor-name>",
+ // the addition of mappings from cursor names to query sections,
+ // and the subtitution of <users-cursor-name> with <canned-cursor-name> in the pass-thru sql string
+ // "...where current of <canned-cursor-name>" when user-defined cursor names are used.
+ // Both "canned" cursor names (from our jdbc package set) and user-defined cursor names are mapped.
+ // Statement.cursorName_ is initialized to null until the cursor name is requested or set.
+ // When set (s.setCursorName()) with a user-defined name, then it is added to the cursor map at that time;
+ // When requested (rs.getCursorName()), if the cursor name is still null,
+ // then is given the canned cursor name as defined by our jdbc package set and added to the cursor map.
+ // Still need to consider how positioned updates should interact with multiple result sets from a stored.
+ String cursorName_ = null;
+
+ // This means the client-side jdbc statement object is open.
+ // This value is set to true when the statement object is constructed, and will not change
+ // until statement.close() is called either directly or via connection.close(), finalizer, or other methods.
+ boolean openOnClient_ = true;
+ // This means a DERBY server-side section for this statement is in the prepared state.
+ // A client-side jdbc statement may remain open across commits (openOnClient=true),
+ // but the server-side DERBY section moves to an unprepared state (openOnServer=false) across commits,
+ // requiring an implicit re-prepare "under the covers" by the driver.
+ // Unprepared jdbc query statements still have prepared sections on the server.
+ // This openOnServer_ only has implications for preparedstatement
+ boolean openOnServer_ = false;
+
+
+ //private int indexOfCurrentResultSet_ = -1;
+ protected int indexOfCurrentResultSet_ = -1;
+ ResultSet[] resultSetList_ = null; // array of ResultSet objects
+
+ int timeout_ = 0; // for query timeout in seconds, multiplied by 1000 when passed to java.util.Timer
+ int maxRows_ = 0;
+ int maxFieldSize_ = 0; // zero means that there is no limit to the size of a column.
+ boolean escapedProcedureCallWithResult_ = false;
+
+ // When this is false we skip autocommit for this PreparedStatement.
+ // This is needed when the PreparedStatement object is used internally by
+ // the driver and a commit is not desired, e.g., Blob/Clob API calls
+ public boolean isAutoCommittableStatement_ = true;
+
+ // The user has no control over the statement that owns a catalog query, and has no ability to close that statement.
+ // We need a special member variable on our internal catalog query statements so that
+ // when the catalog query is closed, the result set will know to close it's owning statement.
+ boolean isCatalogQuery_ = false;
+
+
+ // This collection is used for two different purposes:
+ // For statement batching it contains the batched SQL strings.
+ // For prepared statement batching it contains the batched input rows.
+ java.util.ArrayList batch_ = new java.util.ArrayList();
+
+
+ // Scrollable cursor attributes
+ public int resultSetType_ = java.sql.ResultSet.TYPE_FORWARD_ONLY;
+ public int resultSetConcurrency_ = java.sql.ResultSet.CONCUR_READ_ONLY;
+ public int resultSetHoldability_;
+ // This is ignored by the driver if this is zero.
+ // For the net forward-only result set, if fetchSize is unset, we let the server return however many rows will fit in a query block.
+ // For the net scrollable result set, then we use a default of 64 rows.
+ public int fetchSize_ = 0;
+ public int fetchDirection_ = java.sql.ResultSet.FETCH_FORWARD;
+
+ // Conceptually this doesn't belong in Statement, but belongs in PreparedStatement,
+ // since Statement doesn't know about params, so we're just putting it here perhaps temporarily,
+ // Used for callable statement OUT paramters.
+ public Cursor singletonRowData_ = null;
+
+ // number of invisible result sets returned from a stored procedure.
+ public int numInvisibleRS_ = 0;
+
+ // This is a cache of the attributes to be sent on prepare.
+ // Think about caching the entire prepare DDM string for the re-prepares
+ public String cursorAttributesToSendOnPrepare_ = null;
+
+ // The following members are for the exclusive use of prepared statements that require auto-generated keys to be returned
+ public PreparedStatement preparedStatementForAutoGeneratedKeys_;
+ public ResultSet generatedKeysResultSet_;
+ public String[] generatedKeysColumnNames_;
+ public int autoGeneratedKeys_ = java.sql.Statement.NO_GENERATED_KEYS;
+
+ // This flag makes sure that only one copy of this statement
+ // will be in connection_.commitListeners_.
+
+
+ //---------------------constructors/finalizer---------------------------------
+
+ private Statement() throws SqlException {
+ initStatement();
+ }
+
+ private void resetStatement() throws SqlException {
+ initStatement();
+ }
+
+ private void initStatement() throws SqlException {
+ materialStatement_ = null;
+ connection_ = null;
+ agent_ = null;
+ databaseMetaData_ = null;
+ resultSetType_ = java.sql.ResultSet.TYPE_FORWARD_ONLY;
+ resultSetConcurrency_ = java.sql.ResultSet.CONCUR_READ_ONLY;
+ resultSetHoldability_ = 0;
+ cursorAttributesToSendOnPrepare_ = null;
+
+ initResetStatement();
+ }
+
+ private void initResetStatement() throws SqlException {
+ initResetPreparedStatement();
+
+ //section_ = null; // don't set section to null because write piggyback command require a section
+ if (section_ != null) {
+ section_.free();
+ }
+ sqlMode_ = 0;
+ sqlUpdateMode_ = 0;
+ resultSetMetaData_ = null;
+ }
+
+ protected void initResetPreparedStatement() {
+ warnings_ = null;
+ //section_ = null;
resultSet_ = null;
- }
- resultIsResultSet = false;
+ updateCount_ = -1;
+ returnValueFromProcedure_ = 0;
+ cursorName_ = null;
+ openOnClient_ = true;
+ openOnServer_ = false;
+ indexOfCurrentResultSet_ = -1;
+ resultSetList_ = null;
+ timeout_ = 0;
+ maxRows_ = 0;
+ maxFieldSize_ = 0;
+ escapedProcedureCallWithResult_ = false;
+ isCatalogQuery_ = false;
+ isAutoCommittableStatement_ = true;
+
+ if (batch_ == null) {
+ batch_ = new java.util.ArrayList();
+ } else {
+ batch_.clear();
+ }
+ fetchSize_ = 0;
+ fetchDirection_ = java.sql.ResultSet.FETCH_FORWARD;
+ singletonRowData_ = null;
+ numInvisibleRS_ = 0;
+ preparedStatementForAutoGeneratedKeys_ = null;
+ generatedKeysResultSet_ = null;
+ generatedKeysColumnNames_ = null;
+ autoGeneratedKeys_ = java.sql.Statement.NO_GENERATED_KEYS;
+
+ // these members were not initialized
+ isPreparedStatement_ = false;
+ }
+
+ // If a dataSource is passed into resetClientConnection(), then we will assume
+ // properties on the dataSource may have changed, and we will need to go through
+ // the open-statement list on the connection and do a full reset on all statements,
+ // including preparedStatement's and callableStatement's. This is because property
+ // change may influence the section we allocate for the preparedStatement, and
+ // also the cursor attributes, i.e. setCursorSensitivity().
+ // If no dataSource is passed into resetClientConnection(), then we will do the
+ // minimum reset required for preparedStatement's and callableStatement's.
+ public void reset(boolean fullReset) throws SqlException {
+ if (fullReset) {
+ connection_.resetStatement(this);
+ } else {
+ initResetStatement();
+ materialStatement_.reset_();
+ }
}
- else {
- if (numInvisibleRS_ == 0 &&
- current == CLOSE_CURRENT_RESULT &&
- resultSetList_[indexOfCurrentResultSet_] != null) {
- resultSetList_[indexOfCurrentResultSet_].closeX();
- }
- resultIsResultSet = indexOfCurrentResultSet_ + 1 < resultSetList_.length;
- }
- if ((current == CLOSE_ALL_RESULTS) && (numInvisibleRS_ == 0)) {
- int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : indexOfCurrentResultSet_+1;
- boolean willTickleServer = willTickleServer (numberOfResultSetsToClose, false);
- if (willTickleServer)
- flowCloseRetrievedResultSets();
- else
- flowCloseRetrievedResultSetsOutsideUOW();
- }
- if (resultIsResultSet)
- resultSet_ = resultSetList_[++indexOfCurrentResultSet_];
- else
- resultSet_ = null;
- return resultIsResultSet;
- }
+ public Statement(Agent agent, Connection connection) throws SqlException {
+ this();
+ initStatement(agent, connection);
+ }
+
+ public void resetStatement(Agent agent, Connection connection) throws SqlException {
+ resetStatement();
+ initStatement(agent, connection);
+ }
+
+ private void initStatement(Agent agent, Connection connection) {
+ agent_ = agent;
+ connection_ = connection;
+ databaseMetaData_ = connection.databaseMetaData_;
+ }
+
+ // For jdbc 2 statements with scroll attributes
+ public Statement(Agent agent, Connection connection, int type, int concurrency, int holdability,
+ int autoGeneratedKeys, String[] columnNames) throws SqlException {
+ this(agent, connection);
+ initStatement(type, concurrency, holdability, autoGeneratedKeys, columnNames);
+ }
+
+ public void resetStatement(Agent agent, Connection connection, int type, int concurrency, int holdability,
+ int autoGeneratedKeys, String[] columnNames) throws SqlException {
+ resetStatement(agent, connection);
+ initStatement(type, concurrency, holdability, autoGeneratedKeys, columnNames);
+ }
+
+ private void initStatement(int type, int concurrency, int holdability,
+ int autoGeneratedKeys, String[] columnNames) throws SqlException {
+ switch (type) {
+ case java.sql.ResultSet.TYPE_FORWARD_ONLY:
+ case java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE:
+ case java.sql.ResultSet.TYPE_SCROLL_SENSITIVE:
+ resultSetType_ = type;
+ break;
+ default:
+ throw new SqlException(agent_.logWriter_, "Invalid argument: " +
+ "ResultSet Type " + type + " is invalid.");
+ }
- public java.sql.ResultSet getGeneratedKeys () throws SqlException
- {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "getGeneratedKeys");
- checkForClosedStatement ();
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "getGeneratedKeys", generatedKeysResultSet_);
- return generatedKeysResultSet_;
+ switch (concurrency) {
+ case java.sql.ResultSet.CONCUR_READ_ONLY:
+ case java.sql.ResultSet.CONCUR_UPDATABLE:
+ resultSetConcurrency_ = concurrency;
+ break;
+ default:
+ throw new SqlException(agent_.logWriter_, "Invalid argument: " +
+ "ResultSet Concurrency " + concurrency + " is invalid.");
+ }
+
+ switch (holdability) {
+ case org.apache.derby.jdbc.ClientDataSource.CLOSE_CURSORS_AT_COMMIT:
+ case org.apache.derby.jdbc.ClientDataSource.HOLD_CURSORS_OVER_COMMIT:
+ resultSetHoldability_ = holdability;
+ break;
+ default:
+ throw new SqlException(agent_.logWriter_, "Invalid argument: " +
+ "ResultSet holdability " + holdability + " is invalid.");
+ }
+
+ switch (autoGeneratedKeys) {
+ case java.sql.Statement.NO_GENERATED_KEYS:
+ case java.sql.Statement.RETURN_GENERATED_KEYS:
+ autoGeneratedKeys_ = autoGeneratedKeys;
+ break;
+ default:
+ throw new SqlException(agent_.logWriter_, "Invalid argument: " +
+ "Statement auto-generated keys value " + autoGeneratedKeys +
+ " is invalid.");
+ }
+
+ generatedKeysColumnNames_ = columnNames;
}
- public int executeUpdate (String sql, int autoGeneratedKeys) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "executeUpdate", sql, autoGeneratedKeys);
- autoGeneratedKeys_ = autoGeneratedKeys;
- int updateValue = executeUpdateX (sql);
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "executeUpdate", updateValue);
- return updateValue;
- }
+ protected void finalize() throws java.lang.Throwable {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "finalize");
+ }
+ if (openOnClient_) {
+ synchronized (connection_) {
+ closeX();
+ }
+ }
+ super.finalize();
}
- public int executeUpdate (String sql, int columnIndexes[]) throws SqlException
- {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "executeUpdate", sql, columnIndexes);
- checkForClosedStatement ();
- throw new SqlException (agent_.logWriter_, "Driver not capable");
+ // ---------------------------jdbc 1------------------------------------------
+
+ public java.sql.ResultSet executeQuery(String sql) throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "executeQuery", sql);
+ }
+ ResultSet resultSet = executeQueryX(sql);
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceExit(this, "executeQuery", resultSet);
+ }
+ return resultSet;
+ }
}
- public int executeUpdate (String sql, String columnNames[]) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "executeUpdate", sql, columnNames);
- generatedKeysColumnNames_ = columnNames;
- int updateValue = executeUpdateX (sql);
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "executeUpdate", updateValue);
- return updateValue;
- }
+ private ResultSet executeQueryX(String sql) throws SqlException {
+ flowExecute(executeQueryMethod__, sql);
+
+ checkExecuteQueryPostConditions("java.sql.Statement");
+ return resultSet_;
}
- public boolean execute (String sql, int autoGeneratedKeys) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "execute", sql, autoGeneratedKeys);
- autoGeneratedKeys_ = autoGeneratedKeys;
- boolean b = executeX (sql);
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "execute", b);
- return b;
- }
+ void checkExecuteQueryPostConditions(String jdbcStatementInterfaceName) throws SqlException {
+ // We'll just rely on finalizers to close the dangling result sets.
+ if (resultSetList_ != null && resultSetList_.length != 1) {
+ throw new SqlException(agent_.logWriter_, jdbcStatementInterfaceName + ".executeQuery() cannot be called " +
+ "because multiple result sets were returned." +
+ " Use " + jdbcStatementInterfaceName + ".execute() to obtain multiple results.");
+ }
+
+ if (resultSet_ == null) {
+ throw new SqlException(agent_.logWriter_, jdbcStatementInterfaceName + ".executeQuery() was called " +
+ "but no result set was returned." +
+ " Use " + jdbcStatementInterfaceName + ".executeUpdate() for non-queries.");
+ }
}
- public boolean execute (String sql, int columnIndexes[]) throws SqlException
- {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "execute", sql, columnIndexes);
- checkForClosedStatement ();
- throw new SqlException (agent_.logWriter_, "Driver not capable");
+ public int executeUpdate(String sql) throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "executeUpdate", sql);
+ }
+ int updateValue = executeUpdateX(sql);
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceExit(this, "executeUpdate", updateValue);
+ }
+ return updateValue;
+ }
}
- public boolean execute (String sql, String columnNames[]) throws SqlException
- {
- synchronized (connection_) {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "execute", sql, columnNames);
- generatedKeysColumnNames_ = columnNames;
- boolean b = executeX (sql);
- if (agent_.loggingEnabled()) agent_.logWriter_.traceExit (this, "execute", b);
- return b;
- }
+ private int executeUpdateX(String sql) throws SqlException {
+ flowExecute(executeUpdateMethod__, sql);
+
+ checkExecuteUpdatePostConditions("java.sql.Statement");
+ return updateCount_;
}
- public int getResultSetHoldability () throws SqlException
- {
- if (agent_.loggingEnabled()) agent_.logWriter_.traceEntry (this, "getResultSetHoldability");
- checkForClosedStatement ();
- return resultSetHoldability_;
- }
-
- // ----------------------- box car and callback methods ---------------------
- // All callbacks must be client-side only operations.
- // Use of MaterialStatement interface is necessary to avoid multiple inheritance problem in Java.
- public void writeSetSpecialRegister (java.util.ArrayList sqlsttList) throws SqlException
- { materialStatement_.writeSetSpecialRegister_ (sqlsttList); }
-
- public void readSetSpecialRegister () throws SqlException
- { materialStatement_.readSetSpecialRegister_(); }
-
- public void writeExecuteImmediate (String sql,
- Section section) throws SqlException
- { materialStatement_.writeExecuteImmediate_ (sql, section); }
- public void readExecuteImmediate () throws SqlException
- { materialStatement_.readExecuteImmediate_(); }
- public void completeExecuteImmediate (Sqlca sqlca)
- {
- int sqlcode = completeSqlca (sqlca);
- if (sqlcode < 0) return;
- if (sqlca != null)
- updateCount_ = sqlca.getUpdateCount();
- }
- public void readExecuteImmediateForBatch (String sql) throws SqlException
- { materialStatement_.readExecuteImmediateForBatch_ (sql); }
-
- public void writePrepareDescribeOutput (String sql,
- Section section) throws SqlException
- { materialStatement_.writePrepareDescribeOutput_ (sql, section); }
- public void readPrepareDescribeOutput () throws SqlException
- { materialStatement_.readPrepareDescribeOutput_(); }
-
- public void completePrepareDescribeOutput (ColumnMetaData resultSetMetaData,
- Sqlca sqlca)
- {
- completePrepare (sqlca);
- resultSetMetaData_ = resultSetMetaData;
- if (agent_.loggingEnabled()) agent_.logWriter_.traceResultSetMetaData (this, resultSetMetaData_);
- }
-
- // Used for re-prepares across commit only
- public void writePrepare (String sql, Section section) throws SqlException
- { materialStatement_.writePrepare_ (sql, section); }
- public void readPrepare () throws SqlException
- { materialStatement_.readPrepare_(); }
- public void completePrepare (Sqlca sqlca)
- {
- int sqlcode = completeSqlca (sqlca);
- if (sqlcode < 0) return;
- markPrepared();
- }
-
- public void writeOpenQuery (Section section,
- int fetchSize,
- int resultSetType
- ) throws SqlException
- {
- materialStatement_.writeOpenQuery_ (section,
- fetchSize,
- resultSetType);
- }
- public void readOpenQuery () throws SqlException
- { materialStatement_.readOpenQuery_(); }
-
- public void completeOpenQuery (Sqlca sqlca, ResultSet resultSet)
- {
- completeSqlca (sqlca);
- resultSet_ = resultSet;
- // For NET, resultSet_ == null when open query fails and receives OPNQFLRM.
- // Then, in NetStatementReply.parseOpenQueryFailure(), completeOpenQuery() is
- // invoked with resultSet explicitly set to null.
- if (resultSet == null) return;
- resultSet.resultSetMetaData_ = resultSetMetaData_;
- resultSet.resultSetMetaData_.resultSetConcurrency_ = resultSet.resultSetConcurrency_;
-
- // only cache the Cursor object for a PreparedStatement and if a Cursor object is
- // not already cached.
- if (cachedCursor_ == null && isPreparedStatement_)
- cachedCursor_ = resultSet_.cursor_;
-
- // The following two assignments should have already happened via prepareEvent(),
- // but are included here for safety for the time being.
- if (sqlca != null && sqlca.getSqlCode() < 0) return;
- openOnServer_ = true;
- resultSet.cursor_.rowsRead_ = 0;
-
- // Set fetchSize_ to the default(64) if not set by the user if the resultset is scrollable.
- // This fetchSize_ is used to check for a complete rowset when rowsets are parsed.
- // For scrollable cursors when the fetchSize_ is not set, (fetchSize_ == 0), a default
- // fetchSize of 64 is sent on behalf of the application, so we need to update the fetchSize_
- // here to 64.
- if (resultSet_.fetchSize_ == 0 &&
- (resultSet_.resultSetType_ == java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE ||
- resultSet_.resultSetType_ == java.sql.ResultSet.TYPE_SCROLL_SENSITIVE))
- resultSet_.fetchSize_ = org.apache.derby.client.am.Configuration.defaultFetchSize;
- }
-
- public void completeExecuteCallOpenQuery (Sqlca sqlca, ResultSet resultSet, ColumnMetaData resultSetMetaData, Section generatedSection)
- {
- resultSet.completeSqlca (sqlca);
- // For CallableStatements we can't just clobber the resultSet_ here, must use setResultSetEvent() separately
- resultSet.resultSetMetaData_ = resultSetMetaData;
-
- // The following two assignments should have already happened via prepareEvent(),
- // but are included here for safety for the time being.
- if (sqlca != null && sqlca.getSqlCode() < 0) return;
- openOnServer_ = true;
- resultSet.cursor_.rowsRead_ = 0;
-
- resultSet.generatedSection_ = generatedSection;
-
- // We are always sending the default fetchSize of 64 if not set for stored procedure calls.
- // This is different from the "normal" cursor case for forward_only cursors, where if
- // fetchSize_ is not set, we do not send any default value. Here since we always send
- // the fetchSize_, we need to set it to what we sent.
- if (resultSet.fetchSize_ == 0)
- resultSet.fetchSize_ = org.apache.derby.client.am.Configuration.defaultFetchSize;
- }
-
- public void writeExecuteCall (boolean outputExpected,
- String procedureName,
- Section section,
- int fetchSize,
- boolean suppressResultSets, // for batch updates == true
- int resultSetType,
- ColumnMetaData parameterMetaData,
- Object[] inputs) throws SqlException
- {
- materialStatement_.writeExecuteCall_ (outputExpected,
- procedureName,
- section,
- fetchSize,
- suppressResultSets,
- resultSetType,
- parameterMetaData,
- inputs);
- }
- public void readExecuteCall () throws SqlException
- { materialStatement_.readExecuteCall_(); }
- public void completeExecuteCall (Sqlca sqlca, Cursor singletonParams, ResultSet[] resultSets)
- {
- completeExecuteCall (sqlca, singletonParams);
- resultSetList_ = resultSets;
- if (resultSets != null)
- resultSet_ = resultSets[0];
- indexOfCurrentResultSet_ = 0;
- }
- public void completeExecuteCall (Sqlca sqlca, Cursor singletonParams) // no result sets returned
- {
- completeExecute (sqlca);
- //if ((sqlca != null) && ((sqlca.getSqlCode() < 0) || (sqlca.getSqlCode() == 100)))
- if (sqlca != null && sqlca.getSqlCode() < 0)
- singletonRowData_ = null;
- else {
- singletonRowData_ = singletonParams;
- if (cachedSingletonRowData_ == null && isPreparedStatement_)
- cachedSingletonRowData_ = singletonRowData_;
- }
- }
- // Callback for CALLS, and PreparedStatement updates.
- public void completeExecute (Sqlca sqlca)
- {
- if (sqlca == null) return;
-
- int sqlcode = sqlca.getSqlCode();
- if (sqlcode < 0) {
- agent_.accumulateReadException (new SqlException (agent_.logWriter_, sqlca));
- returnValueFromProcedure_ = sqlcode;
- }
- else {
- updateCount_ = sqlca.getUpdateCount();
- // sometime for call statement, protocol will return updateCount_, we will always set that to 0
- // sqlMode_ is not set for statements, only for prepared statements
- if (sqlMode_ == isCall__) {
- updateCount_ = -1;
- returnValueFromProcedure_ = sqlca.getSqlErrd()[0]; ////what is this for??
+ void checkExecuteUpdatePostConditions(String jdbcStatementInterfaceName) throws SqlException {
+ // We'll just rely on finalizers to close the dangling result sets.
+ if (resultSetList_ != null) {
+ throw new SqlException(agent_.logWriter_, jdbcStatementInterfaceName + ".executeUpdate() cannot be called " +
+ "because multiple result sets returned." +
+ " Use " + jdbcStatementInterfaceName + ".execute() to obtain multiple results.");
}
- // Sqlcode 466 indicates a call statement has issued and result sets returned.
- // This is a good place to set some state variable to indicate result sets are open
- // for call, so that when autocommit is true, commit will not be issued until the
- // result sets are closed.
- // Currently, commit is not issued even there is no result set.
- // do not externalize sqlcode +100
- if (sqlcode > 0 && sqlcode != 466 && sqlcode != 100)
- accumulateWarning (new SqlWarning (agent_.logWriter_, sqlca));
- }
- }
-
-
- public void setUpdateCount (int updateCount) { updateCount_ = updateCount; }
-
-
- private boolean willTickleServer (int number, boolean allowAutoCommits) throws SqlException
- {
- boolean requiresAutocommit = false;
- if (resultSetList_ != null) {
- for (int i = 0; i < number; i++) {
- if (resultSetList_[i] != null) {
- if (resultSetList_[i].openOnServer_)
- return true; // for the writeClose flow
- if (!resultSetList_[i].autoCommitted_ && allowAutoCommits)
- requiresAutocommit = true; // for the commit flow
- }
- }
- }
- else if (generatedKeysResultSet_ != null && generatedKeysResultSet_.openOnServer_) {
- generatedKeysResultSet_.writeClose ();
- }
- else if (resultSet_ != null) {
- if (resultSet_.openOnServer_)
- return true; // for the writeClose flow
- if (!resultSet_.autoCommitted_ && allowAutoCommits)
- requiresAutocommit = true;
- }
- if (connection_.autoCommit_ && requiresAutocommit) { // for the auto-commit;
- if (connection_.isXAConnection_)
- return (connection_.xaState_ == Connection.XA_LOCAL) || (connection_.xaState_ == Connection.XA_LOCAL_START_SENT);
- else
- return true;
- }
- return false;
- }
-
- private void flowClose () throws SqlException
- {
- agent_.beginWriteChain (this);
- writeClose (true); // true means permit auto-commits
- agent_.flow (this);
- readClose (true); // true means permit auto-commits
- agent_.endReadChain();
- }
-
- private void flowCloseOutsideUOW () throws SqlException
- {
- agent_.beginWriteChainOutsideUOW ();
- writeClose (true); // true means permit auto-commits
- agent_.flowOutsideUOW ();
- readClose (true); // true means permit auto-commits
- agent_.endReadChain();
- }
-
- final void writeClose (boolean allowAutoCommits) throws SqlException
- {
- writeCloseResultSets (allowAutoCommits);
- }
-
- final void readClose (boolean allowAutoCommits) throws SqlException
- {
- readCloseResultSets (allowAutoCommits);
- }
-
- boolean writeCloseResultSets (boolean allowAutoCommits) throws SqlException
- {
- int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : resultSetList_.length;
- return writeCloseResultSets (numberOfResultSetsToClose, allowAutoCommits);
- }
-
- // The connection close processing passes allowAutoCommits=false because if we drove an
- // autocommits after each statement close, then when we issue close requests on non-held cursors
- // the server would complain that the non-held cursor was already closed from the previous statement's auto-commit.
- // So the solution is to never autocommit statements during connection close processing.
- //
- // Here's the operative explanation:
- // Given a sequence of open statements S1, S2, .... a logic problem is occuring after S1 close-query
- // drives an auto-commit, and S2 close-query is driven against a non-held cursor.
- // The first auto-commit driven by S1 triggers a callback that closes S2's non-held cursor,
- // and so the subsequent S2 close-query request generates an error from the server saying
- // that the cursor is already closed.
- //
- // This is fixed by passing a flag to our statement close processing that prevents
- // driving additional auto-commits after each statement close.
- // Connectino close drives its own final auto-commit.
- //
- boolean writeCloseResultSets (int number, boolean allowAutoCommits) throws SqlException
- {
- boolean requiresAutocommit = false;
- if (resultSetList_ != null) {
- for (int i = 0; i < number; i++) {
- if (resultSetList_[i] != null) {
- if (resultSetList_[i].openOnServer_)
- resultSetList_[i].writeClose ();
- if (!resultSetList_[i].autoCommitted_ && allowAutoCommits)
- requiresAutocommit = true;
- }
- }
- }
- else if (generatedKeysResultSet_ != null && generatedKeysResultSet_.openOnServer_) {
- generatedKeysResultSet_.writeClose ();
- }
- else if (resultSet_ != null) {
- if (resultSet_.openOnServer_)
- resultSet_.writeClose ();
- if (!resultSet_.autoCommitted_ && allowAutoCommits)
- requiresAutocommit = true;
- }
- if (connection_.autoCommit_ && requiresAutocommit && isAutoCommittableStatement_) {
- connection_.writeAutoCommit ();
- if (connection_.isXAConnection_)
- return (connection_.xaState_ == Connection.XA_LOCAL) || (connection_.xaState_ == Connection.XA_LOCAL_START_SENT);
- else
- return true;
- }
- return false;
- }
-
- // Helper method for S.flowCloseResultSets() and PS.flowExecute()
- void readCloseResultSets (boolean allowAutoCommits) throws SqlException
- {
- int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : resultSetList_.length;
- readCloseResultSets (numberOfResultSetsToClose, allowAutoCommits);
- }
-
- void readCloseResultSets (int number, boolean allowAutoCommits) throws SqlException
- {
- boolean requiredAutocommit = false;
- if (resultSetList_ != null) {
- for (int i = 0; i < number; i++) {
- if (resultSetList_[i] != null) {
- if (resultSetList_[i].openOnServer_)
- resultSetList_[i].readClose ();
- else
- resultSetList_[i].markClosed();
- if (!resultSetList_[i].autoCommitted_ && allowAutoCommits)
- requiredAutocommit = true;
- }
- }
- }
- else if (generatedKeysResultSet_ != null) {
- if (generatedKeysResultSet_.openOnServer_)
- generatedKeysResultSet_.readClose ();
- else
- generatedKeysResultSet_.markClosed ();
- }
- else if (resultSet_ != null) {
- if (resultSet_.openOnServer_)
- resultSet_.readClose ();
- else
- resultSet_.markClosed();
- if (!resultSet_.autoCommitted_ && allowAutoCommits)
- requiredAutocommit = true;
- }
- // we only commit when auto commit is turned on and at least one result set needed closing on server.
- if (connection_.autoCommit_ && requiredAutocommit && isAutoCommittableStatement_) {
- connection_.readAutoCommit ();
- }
- }
-
- private void flowCloseRetrievedResultSets () throws SqlException
- {
- int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : indexOfCurrentResultSet_+1;
- agent_.beginWriteChain (this);
- // Need to refactor the ResultSet.readClose() path to check if we are the
- // last result set closed in a set of multiple result sets of the owning statement,
- // if so, we need to flow the auto-commit (but only then).
- // currently, the code to do this is only in the closeX() path, which isn't called here
- writeCloseResultSets (numberOfResultSetsToClose, false);
- agent_.flow (this);
- readCloseResultSets (numberOfResultSetsToClose, false); // true means permit auto-commits
- agent_.endReadChain();
- }
-
- private void flowCloseRetrievedResultSetsOutsideUOW () throws SqlException
- {
- int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : indexOfCurrentResultSet_+1;
- agent_.beginWriteChainOutsideUOW ();
- // Need to refactor the ResultSet.readClose() path to check if we are the
- // last result set closed in a set of multiple result sets of the owning statement,
- // if so, we need to flow the auto-commit (but only then).
- // currently, the code to do this is only in the closeX() path, which isn't called here
- writeCloseResultSets (numberOfResultSetsToClose, false);
- agent_.flowOutsideUOW ();
- readCloseResultSets (numberOfResultSetsToClose, false); // true means permit auto-commits
- agent_.endReadChain();
- }
-
- public int completeSqlca (Sqlca sqlca)
- {
- if (sqlca == null) return 0;
- int sqlcode = sqlca.getSqlCode();
- if (sqlcode < 0)
- connection_.agent_.accumulateReadException (new SqlException (agent_.logWriter_, sqlca));
- else if (sqlcode > 0)
- accumulateWarning (new SqlWarning (agent_.logWriter_, sqlca));
- return sqlcode;
- }
-
- public void completeExecuteSetStatement (Sqlca sqlca)
- {
- }
-
- void markClosedOnServer ()
- {
- if (section_ != null) {
- section_.free();
- section_ = null;
- }
- openOnServer_ = false;
- // if an error occurs during the middle of the reset, before the statement
- // has a chance to reset its materialStatement_, and Agent.disconnectEvent() is called,
- // then the materialStatement_ here can be null.
- if (materialStatement_ != null)
- materialStatement_.markClosedOnServer_();
- }
-
- void markClosed ()
- {
- openOnClient_ = false;
- markResultSetsClosed();
- // in case a cursorName was set on the Statement but the Statement was
- // never used to execute a query, the cursorName will not be removed
- // when the resultSets are mark closed, so we need to remove the
- // cursorName form the cache.
- removeClientCursorNameFromCache ();
- markPreparedStatementForAutoGeneratedKeysClosed ();
- markClosedOnServer();
- }
-
- void markPreparedStatementForAutoGeneratedKeysClosed ()
- {
- if (preparedStatementForAutoGeneratedKeys_ != null)
- preparedStatementForAutoGeneratedKeys_.markClosed();
- }
-
- void markResultSetsClosed()
- {
- if (resultSetList_ != null) {
- for (int i = 0; i < resultSetList_.length; i++) {
- if (resultSetList_[i] != null) resultSetList_[i].markClosed();
- resultSetList_[i] = null;
- }
- }
- if (generatedKeysResultSet_ != null) generatedKeysResultSet_.markClosed();
- if (resultSet_ != null) resultSet_.markClosed();
- resultSet_ = null;
- resultSetList_ = null;
- generatedKeysResultSet_ = null;
- }
-
- private void flowExecute (int executeType, String sql) throws SqlException
- {
- checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
- checkAutoGeneratedKeysParameters();
- clearWarningsX(); // Per jdbc spec 0.7, and getWarnings() javadoc
-
- sql = escape (sql);
- parseSqlAndSetSqlModes (sql);
- if (sqlMode_ == isUpdate__) updateCount_ = 0;
- else updateCount_ = -1;
-
- checkForAppropriateSqlMode (executeType, sqlMode_);
-
- java.util.Timer queryTimer = null;
- QueryTimerTask queryTimerTask = null;
- if (timeout_ != 0) {
- queryTimer = new java.util.Timer (); // A thread that ticks the seconds
- queryTimerTask = new QueryTimerTask (this, queryTimer);
- queryTimer.schedule (queryTimerTask, 1000*timeout_);
- }
-
- // enclose the processing in a try finally block in order to make sure
- // the query timeout is cancelled at the end of this method.
- try {
- agent_.beginWriteChain (this);
- boolean piggybackedAutoCommit = writeCloseResultSets (true); // true means permit auto-commits
-
- ResultSet scrollableRS = null;
- Section newSection = null;
- boolean repositionedCursor = false;
-
- switch (sqlMode_) {
- case isQuery__:
- newSection = agent_.sectionManager_.getDynamicSection (
- resultSetHoldability_);
- // if client's cursor name is set, map it to the query section in the hashtable
- // after we obtain the section.
- if (cursorName_ != null) {
- agent_.sectionManager_.mapCursorNameToQuerySection (cursorName_, newSection);
+ // We'll just rely on the finalizer to close the dangling result set.
+ if (resultSet_ != null) {
+ throw new SqlException(agent_.logWriter_, jdbcStatementInterfaceName + ".executeUpdate() was called " +
+ "but a result set was returned." +
+ " Use " + jdbcStatementInterfaceName + ".executeQuery() to obtain a result set.");
+ }
+ }
+
+ // The server holds statement resources until transaction end.
+ public void close() throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "close");
+ }
+ closeX();
+ }
+ }
- // This means we must subtitute the <users-cursor-name> with the <canned-cursor-name>
- // in the pass-thru sql string "...where current of <canned-cursor-name>".
- newSection.setClientCursorName (cursorName_);
+ // An untraced version of close()
+ public void closeX() throws SqlException {
+ if (!openOnClient_) {
+ return;
+ }
+ // Regardless of whether or not this statement is in the prepared state,
+ // we need to close any open cursors for this statement on the server.
+ int numberOfResultSetsToClose = (resultSetList_ == null) ? 0 : resultSetList_.length;
+ boolean willTickleServer = willTickleServer(numberOfResultSetsToClose, true);
+ try {
+ if (willTickleServer) {
+ flowClose();
+ } else {
+ flowCloseOutsideUOW();
+ }
+ } finally {
+ markClosed();
+ connection_.openStatements_.remove(this);
+ }
+ // push the mark close of rsmd into Statement.markClosed() method
+ if (resultSetMetaData_ != null) {
+ resultSetMetaData_.markClosed();
+ resultSetMetaData_ = null;
}
+ }
- writePrepareDescribeOutput (sql, newSection);
- writeOpenQuery (newSection,
- fetchSize_,
- resultSetType_);
- break;
- case isUpdate__:
- String cursorName = null;
- if(sqlUpdateMode_ == isDeleteSql__ || sqlUpdateMode_ == isUpdateSql__) {
- String[] sqlAndCursorName = extractCursorNameFromWhereCurrentOf (sql);
- if(sqlAndCursorName != null) {
- cursorName = sqlAndCursorName[0];
- sql = sqlAndCursorName[1];
- }
- }
- if (cursorName != null) {
- newSection = agent_.sectionManager_.getPositionedUpdateSection (cursorName, true); // true means get an execute immediate section
- if (newSection == null)
- throw new SqlException (agent_.logWriter_, "Invalid cursor name \"" + cursorName +
- "\" in the Update/Delete statement.");
- scrollableRS = agent_.sectionManager_.getPositionedUpdateResultSet (cursorName);
- // do not need to reposition for rowset cursors
- if (scrollableRS != null && !scrollableRS.isRowsetCursor_) {
- repositionedCursor =
- scrollableRS.repositionScrollableResultSetBeforeJDBC1PositionedUpdateDelete();
- if (!repositionedCursor) scrollableRS = null;
- }
-
- // if client's cursor name is set, and the cursor name in the positioned update
- // string is the same as the client's cursor name, replace client's cursor name
- // with the server's cursor name.
- if (newSection.getClientCursorName() != null &&
- cursorName.compareTo (newSection.getClientCursorName()) == 0) {
- // substitute cusor name in pass thru sql string
- sql = substituteClientCursorNameWithServerCursorName (sql, newSection);
- }
- writeExecuteImmediate (sql, newSection);
- }
- // if sql is an insert and columnNames is not null, and
- // then transform the insert statement into an
- // select from insert statement.
- // else chain an "select from identity_val_local()" to the insert statement
- else if (sqlUpdateMode_ == isInsertSql__ && generatedKeysColumnNames_ != null) {
- newSection = agent_.sectionManager_.getDynamicSection (
- resultSetHoldability_);
- writePrepareDescribeOutput (constructSelectFromInsertSQL(sql), newSection);
- writeOpenQuery (newSection,
- fetchSize_,
- resultSetType_);
- }
- else {
- newSection = agent_.sectionManager_.getDynamicSection(resultSetHoldability_);
-
- writeExecuteImmediate (sql, newSection);
- if (sqlUpdateMode_ == isInsertSql__ && autoGeneratedKeys_ == RETURN_GENERATED_KEYS) {
- prepareAutoGeneratedKeysStatement ();
- writeOpenQuery (preparedStatementForAutoGeneratedKeys_.section_,
- preparedStatementForAutoGeneratedKeys_.fetchSize_,
- preparedStatementForAutoGeneratedKeys_.resultSetType_);
- }
- }
-
- // maybe duplicate a commit here if the sql is a "commit"
- if (connection_.autoCommit_) connection_.writeAutoCommit ();
- break;
- case isCall__:
- newSection = writeExecuteCall (sql, false);
-
- break;
- }
-
- agent_.flow (this);
-
- readCloseResultSets (true); // true means permit auto-commits
-
- // turn inUnitOfWork_ flag back on and add statement
- // back on commitListeners_ list if they were off
- // by an autocommit chained to a close cursor.
- if (piggybackedAutoCommit) {
- connection_.completeTransactionStart();
- }
-
- markResultSetsClosed();
- markClosedOnServer();
- section_ = newSection;
-
- switch (sqlMode_) {
- case isQuery__:
- // parse out the reply to a chained prepare and open request
- readPrepareDescribeOutput ();
- // This establishes statement.resultSet
- readOpenQuery ();
-
- // resultSet_ is null if open query failed.
- // check for null resultSet_ before using it.
- // the first rowset comes back on OPEN for static non-rowset cursors.
- // no row is returned on open for rowset cursors.
- if (resultSet_ != null) {
- resultSet_.parseScrollableRowset ();
- // If client's cursor name is set, map the client's cursor name to the ResultSet
- // Else map the server's cursor name to the ResultSet
- mapCursorNameToResultSet();
+ public int getMaxFieldSize() throws SqlException {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "getMaxFieldSize");
+ }
+ checkForClosedStatement();
+ return maxFieldSize_;
+ }
+
+ public void setMaxFieldSize(int max) throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "setMaxFieldSize", max);
+ }
+ checkForClosedStatement();
+ if (max < 0) {
+ throw new SqlException(agent_.logWriter_, "Invalid maxFieldSize value: " + max);
+ }
+ maxFieldSize_ = max;
}
+ }
+
+ public int getMaxRows() throws SqlException {
+ checkForClosedStatement();
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceExit(this, "getMaxRows", maxRows_);
+ }
+ return maxRows_;
+ }
+
+ public void setMaxRows(int maxRows) throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "setMaxRows", maxRows);
+ }
+ checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
+ if (maxRows < 0) {
+ throw new SqlException(agent_.logWriter_, "Invalid maxRows value: " + maxRows);
+ }
+ maxRows_ = maxRows;
+ }
+ }
+
+ public void setEscapeProcessing(boolean enable) throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "setEscapeProcessing", enable);
+ }
+ checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
+ }
+ }
+
+ public int getQueryTimeout() throws SqlException {
+ checkForClosedStatement();
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceExit(this, "getQueryTimeout", timeout_);
+ }
+ return timeout_;
+ }
+
+ public void setQueryTimeout(int seconds) throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "setQueryTimeout", seconds);
+ }
+ checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
+ if (seconds < 0) {
+ throw new SqlException(agent_.logWriter_, "Attempt to set a negative query timeout");
+ }
+ timeout_ = seconds; // java.util.Timer takes milliseconds
+ }
+ }
+
+ public void cancel() throws SqlException {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "cancel");
+ }
+ checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
+ throw new SqlException(agent_.logWriter_, "cancel() not supported by server");
+ }
+
+ public java.sql.SQLWarning getWarnings() throws SqlException {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceExit(this, "getWarnings", warnings_);
+ }
+ return warnings_;
+ }
+
+ public void clearWarnings() throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "clearWarnings");
+ }
+ clearWarningsX();
+ }
+ }
+
+ // An untraced version of clearWarnings()
+ public void clearWarningsX() {
+ warnings_ = null;
+ }
+
+ // Dnc statements are already associated with a unique cursor name as defined
+ // by our canned dnc package set.
+ // ResultSet.getCursorName() should be used to
+ // obtain the for update cursor name to use when executing a positioned update statement.
+ // See Jdbc 3 spec section 14.2.4.4.
+ public void setCursorName(String name) throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "setCursorName", name);
+ }
+ checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
+ if (name == null || name.equals("")) {
+ throw new SqlException(agent_.logWriter_, "Invalid cursor name.");
+ }
+
+ // Invalid to set the cursor name if there are ResultSet's open on the Statement.
+ if (resultSet_ != null && resultSet_.openOnClient_) {
+ throw new SqlException(agent_.logWriter_, "Invalid operation: setCursorName() " +
+ "called when there are open ResultSet's on the Statement.");
+ }
+
+ // Duplicate cursor names not allowed.
+ if (connection_.clientCursorNameCache_.containsKey(name)) {
+ throw new SqlException(agent_.logWriter_, "Duplicate cursor names are not allowed.");
+ }
+ connection_.clientCursorNameCache_.put(name, name);
+
+ // section_ is null for Statement objects. We will defer the mapping of cursorName
+ // to section until when the query is executed.
+ if (section_ != null) {
+ agent_.sectionManager_.mapCursorNameToQuerySection(name, (Section) section_);
+
+ // This means we must subtitute the <users-cursor-name> with the <canned-cursor-name>
+ // in the pass-thru sql string "...where current of <canned-cursor-name>".
+ section_.setClientCursorName(name);
+ }
+ cursorName_ = name;
+ }
+ }
+
+ //----------------------- Multiple Results --------------------------
- break;
- case isUpdate__:
+ public boolean execute(String sql) throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "execute", sql);
+ }
+ boolean b = executeX(sql);
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceExit(this, "execute", b);
+ }
+ return b;
+ }
+ }
- // do not need to reposition for rowset cursors.
- if (scrollableRS != null && !scrollableRS.isRowsetCursor_)
- scrollableRS.readPositioningFetch_();
+ boolean executeX(String sql) throws SqlException {
+ flowExecute(executeMethod__, sql);
+ return resultSet_ != null;
+ }
+
+ public java.sql.ResultSet getResultSet() throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "getResultSet");
+ }
+ checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceExit(this, "getResultSet", resultSet_);
+ }
+ return resultSet_;
+ }
+ }
+
+ public int getUpdateCount() throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "getUpdateCount");
+ }
+ checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceExit(this, "getUpdateCount", updateCount_);
+ }
+ return updateCount_;
+ }
+ }
- if (sqlUpdateMode_ == isInsertSql__ && generatedKeysColumnNames_ != null) {
- readPrepareDescribeOutput ();
- readOpenQuery ();
- if (resultSet_ != null) {
- generatedKeysResultSet_ = resultSet_;
+ public boolean getMoreResults() throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "getMoreResults");
+ }
+ boolean resultIsResultSet = getMoreResultsX(CLOSE_ALL_RESULTS);
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceExit(this, "getMoreResults", resultIsResultSet);
+ }
+ return resultIsResultSet;
+ }
+ }
+
+ //--------------------------JDBC 2.0-----------------------------
+
+ public void setFetchDirection(int direction) throws SqlException {
+ synchronized (connection_) {
+ if (agent_.loggingEnabled()) {
+ agent_.logWriter_.traceEntry(this, "setFetchDirection", direction);
+ }
+ checkForClosedStatement(); // Per jdbc spec (see java.sql.Statement.close() javadoc)
+ switch (direction) {
+ case java.sql.ResultSet.FETCH_FORWARD:
+ case java.sql.ResultSet.FETCH_REVERSE:
+ case java.sql.ResultSet.FETCH_UNKNOWN:
+ fetchDirection_ = direction;
+ break;
+ default:
+ throw new SqlException(agent_.logWriter_, "Invalid fetch direction " + direction);
+ }
+ }
+ }
+
[... 1906 lines stripped ...]