db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jboy...@apache.org
Subject svn commit: r165585 [22/42] - in /incubator/derby/code/trunk/java/client/org/apache/derby: client/ client/am/ client/net/ client/resources/ jdbc/
Date Mon, 02 May 2005 06:26:03 GMT
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 ...]


Mime
View raw message