Code Search for Developers
 
 
  

ResultSet.java from CSDerby at Krugle


Show ResultSet.java syntax highlighted

/*

   Derby - Class org.apache.derby.client.am.ResultSet

   Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

package org.apache.derby.client.am;



public abstract class ResultSet implements java.sql.ResultSet,
        ResultSetCallbackInterface,
        UnitOfWorkListener {
    //---------------------navigational members-----------------------------------

    public Statement statement_;
    public ColumnMetaData resultSetMetaData_; // As obtained from the SQLDA
    private SqlWarning warnings_;
    public Cursor cursor_;
    protected Agent agent_;

    public Section generatedSection_ = null;

    //---------------------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, the state data is set by the constructor and never changes.

    // Alias for statement_.connection
    public final Connection connection_;

    //----------------------------- constants ------------------------------------

    public final static int scrollOrientation_relative__ = 1;
    public final static int scrollOrientation_absolute__ = 2;
    public final static int scrollOrientation_after__ = 3;
    public final static int scrollOrientation_before__ = 4;
    public final static int scrollOrientation_prior__ = 5;
    public final static int scrollOrientation_first__ = 6;
    public final static int scrollOrientation_last__ = 7;
    public final static int scrollOrientation_current__ = 8;
    public final static int scrollOrientation_next__ = 0;

    public final static int updatability_unknown__ = 0;
    public final static int updatability_readOnly__ = 1;
    public final static int updatability_delete__ = 2;
    public final static int updatability_update__ = 4;

    public final static int sensitivity_unknown__ = 0;
    public final static int sensitivity_insensitive__ = 1;
    public final static int sensitivity_sensitive_static__ = 2;
    public final static int sensitivity_sensitive_dynamic__ = 3;

    static final private int WAS_NULL = 1;
    static final private int WAS_NOT_NULL = 2;
    static final private int WAS_NULL_UNSET = 0;

    static final public int NEXT_ROWSET = 1;
    static final public int PREVIOUS_ROWSET = 2;
    static final public int ABSOLUTE_ROWSET = 3;
    static final public int FIRST_ROWSET = 4;
    static final public int LAST_ROWSET = 5;
    static final public int RELATIVE_ROWSET = 6;
    static final public int REFRESH_ROWSET = 7;
    //  determines if a cursor is a:
    //    Return to Client - not to be read by the stored procedure only by client
    //    Return to Caller
    public static final byte DDM_RETURN_CALLER = 0x01;
    public static final byte DDM_RETURN_CLIENT = 0x02;

    //-----------------------------state------------------------------------------

    // Note:
    //   Result set meta data as described by the SQLDA is described in ColumnMetaData.

    private int wasNull_ = WAS_NULL_UNSET;

    // ResultSet returnability for Stored Procedure cursors
    //  determines if a cursor is a:
    //    Return to Client - not to be read by the stored procedure only by client
    //    Return to Caller - only calling JSP can read it, not the client
    protected byte rsReturnability_ = DDM_RETURN_CLIENT;

    // This means the client-side jdbc result set object is open.
    boolean openOnClient_ = true;
    // This means a server-side DERBY query section (cursor) for this result set is in the open state.
    // A jdbc result set may remain open even after the server has closed its cursor
    // (openOnClient=true, openOnServer=false); this is known as the "close-only" state.
    public boolean openOnServer_ = true;

    // there is a query terminating sqlca returned from the server when the server closes
    // it's cursor and the client moves to the close-only state.
    public Sqlca queryTerminatingSqlca_;

    // Only true for forward cursors after next() returns false (+100).
    // Used to prevent multiple commits for subsequent next() calls.
    boolean autoCommitted_ = false;

    // Before the first call to next() or any cursor positioning method, the cursor position is invalid
    // and getter methods cannot be called.
    // Also, if a cursor is exhausted (+100), the cursor position is invalid.
    public boolean isValidCursorPosition_ = false;

    public boolean cursorHold_;

    // query instance identifier returned on open by uplevel servers.
    // this value plus the package information uniquely identifies a query.
    // it is 64 bits long and it's value is unarchitected.
    public long queryInstanceIdentifier_ = 0;

    public int resultSetType_;
    public int resultSetConcurrency_;
    public int resultSetHoldability_;
    public boolean scrollable_ = false;
    public int sensitivity_;
    public boolean isRowsetCursor_ = false;
    public boolean isBeforeFirst_ = true;
    public boolean isAfterLast_ = false;
    public boolean isFirst_ = false;
    public boolean isLast_ = false;
    public boolean rowsetContainsLastRow_ = false;
    public Sqlca[] rowsetSqlca_;
    public int fetchSize_;
    public int fetchDirection_;

    public long rowCount_ = -1;

    protected long absolutePosition_ = 0;       // absolute position of the current row
    protected long firstRowInRowset_ = 0;       // absolute position of the first row in the current rowset
    protected long lastRowInRowset_ = 0;        // absolute position of the last row in the current rowset
    protected long currentRowInRowset_ = -1;     // relative position to the first row in the current rowsetwel

    protected long absoluteRowNumberForTheIntendedRow_;

    // This variable helps keep track of whether cancelRowUpdates() should have any effect.
    protected boolean updateRowCalled_ = false;
    private boolean isOnInsertRow_ = false;  // reserved for later
    protected boolean isOnCurrentRow_ = true;
    public int rowsReceivedInCurrentRowset_ = 0;  // keep track of the number of rows received in the
    // current rowset so far

    // maybe be able to consolidate with rowsReceivedInCurrentRowset_
    // Could use the rowsReceivedInCurrentRowset_ flag. But since we are going to set it to the
    // fetchSize and decrement it each time we successfully receiveds a row, the name will be confusing.
    // Fetch size can be changed in the middle of a rowset, and since we don't pre-parse all the rows \
    // for forward-only cursors like we do for scrollable cursors, we will lose the original fetchSize
    // when it's reset.  By decrementing rowsYetToBeReceivedInRowset_, when we come across a fetch
    // request, if rowsYetToBeReceivedInRowset_ is 0, then we can fetch using the "new" fetchSize,
    // otherwise, we will use rowsYetToBeReceivedInRowset_ to complete the rowset.
    public int rowsYetToBeReceivedForRowset_ = 0; // keep track of the number of rows still need to
    // be received to complete the rowset

    private Object updatedColumns_[];

    // Keeps track of whether a column has been updated.  If a column is updated to null,
    // the object array updatedColumns_ entry is null, and we will use this array to distinguish
    // between column not updated and column updated to null.
    private boolean columnUpdated_[];

    public PreparedStatement preparedStatementForUpdate_;
    public PreparedStatement preparedStatementForDelete_;

    // Nesting level of the result set in a stored procedure
    public int nestingLevel_ = -1;

    // Whenever a commit occurs, it unpositions the cursor on the server.  We need to
    // reposition the cursor before updating/deleting again.  This flag will be set to true
    // whenever a commit happens, and reset to false again after we repositoin the cursor.
    public boolean cursorUnpositionedOnServer_ = false;

    //---------------------constructors/finalizer---------------------------------

    protected ResultSet(Agent agent,
                        Statement statement,
                        Cursor cursor,
                        int resultSetType,
                        int resultSetConcurrency,
                        int resultSetHoldability) {
        agent_ = agent;
        statement_ = statement;
        connection_ = statement_.connection_;
        cursor_ = cursor;
        if (cursor_ != null) {
            cursor_.maxFieldSize_ = statement_.maxFieldSize_;
        }
        resultSetType_ = resultSetType;
        resultSetConcurrency_ = resultSetConcurrency;
        resultSetHoldability_ = resultSetHoldability;
        fetchDirection_ = statement_.fetchDirection_;
        fetchSize_ = statement_.fetchSize_;

        // Only set the warning if actual resultSetType returned by the server is less
        // than the application requested resultSetType.
        // TYPE_FORWARD_ONLY = 1003
        // TYPE_SCROLL_INSENSITIVE = 1004
        // TYPE_SCROLL_SENSITIVE = 1005
        if (resultSetType_ < statement_.resultSetType_) {
            statement_.accumulateWarning
                    (new SqlWarning(agent_.logWriter_, "Unable to open resultSet type " +
                    statement_.resultSetType_ + "." +
                    " ResultSet type " + resultSetType_ + " opened."));
        }

        // Only set the warning if actual resultSetConcurrency returned by the server is
        // less than the application requested resultSetConcurrency.
        // CONCUR_READ_ONLY = 1007
        // CONCUR_UPDATABLE = 1008
        if (resultSetConcurrency_ < statement_.resultSetConcurrency_) {
            statement_.accumulateWarning
                    (new SqlWarning(agent_.logWriter_, "Unable to open ResultSet with concurrency  " +
                    statement_.resultSetConcurrency_ + "." +
                    " ResultSet concurrency " + resultSetConcurrency_ + " is used."));
        }

        listenToUnitOfWork();
    }

    // ---------------------------jdbc 1------------------------------------------

    public final boolean next() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "next");
            }
            boolean isValidCursorPosition = nextX();
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceExit(this, "next", isValidCursorPosition);
            }
            return isValidCursorPosition;
        }
    }

    // used by DBMD
    boolean nextX() throws SqlException {
        checkForClosedResultSet();
        clearWarningsX();

        wasNull_ = ResultSet.WAS_NULL_UNSET;

        // discard all previous updates when moving the cursor
        resetUpdatedColumns();

        // for TYPE_FORWARD_ONLY ResultSet, just call cursor.next()
        if (resultSetType_ == java.sql.ResultSet.TYPE_FORWARD_ONLY) {
            // cursor is null for singleton selects that do not return data.
            isValidCursorPosition_ = (cursor_ == null) ? false : cursor_.next();

            // for forward-only cursors, if qryrowset was specificed on OPNQRY or EXCSQLSTT,
            // then we must count the rows returned in the rowset to make sure we received a
            // complete rowset.  if not, we need to complete the rowset on the next fetch.
            if (fetchSize_ != 0) {
                if (rowsYetToBeReceivedForRowset_ == 0) {
                    rowsYetToBeReceivedForRowset_ = fetchSize_;
                }
                if (isValidCursorPosition_) {
                    rowsYetToBeReceivedForRowset_--;
                }
            }

            // Auto-commit semantics for exhausted cursors follows.
            // From Connection.setAutoCommit() javadoc:
            //   The commit occurs when the statement completes or the next execute occurs, whichever comes first.
            //   In the case of statements returning a ResultSet object, the statement completes when the
            //   last row of the ResultSet object has been retrieved or the ResultSet object has been closed.
            //   In advanced cases, a single statement may return multiple results as well as output parameter values.
            //   In these cases, the commit occurs when all results and output parameter values have been retrieved.
            // we will check to see if the forward only result set has gone past the end,
            // we will close the result set, the autocommit logic is in the closeX() method
//    if (!isValidCursorPosition_ && // We've gone past the end (+100)
//        cursor_ != null) {
            if ((!isValidCursorPosition_ && cursor_ != null) ||
                    (statement_.maxRows_ > 0 && cursor_.rowsRead_ > statement_.maxRows_)) {
                isValidCursorPosition_ = false;

                // if not on a valid row and the query is closed at the server.
                // check for an error which may have caused the cursor to terminate.
                // if there were no more rows because of an error, then this method
                // should throw an SqlException rather than just returning false.
                // note: closeX is still called and this will cause the
                // result set to be closed on the client. any additional calls to
                // next() will fail checkForClosedResultSet(), the query terminating exception is
                // only thrown once.
                // depending on how this works with scrollable cursors, there may be
                // a better way/more common place for this logic.
                SqlException sqlException = null;
                if (!openOnServer_) {
                    int sqlcode = Utils.getSqlcodeFromSqlca(queryTerminatingSqlca_);
                    if (sqlcode > 0 && sqlcode != 100) {
                        accumulateWarning(new SqlWarning(agent_.logWriter_, queryTerminatingSqlca_));
                    } else if (sqlcode < 0) {
                        sqlException = new SqlException(agent_.logWriter_, queryTerminatingSqlca_);
                    }
                }
                try {
                    closeX(); // the auto commit logic is in closeX()
                } catch (SqlException sqle) {
                    sqlException = Utils.accumulateSQLException(sqle, sqlException);
                }
                if (sqlException != null) {
                    throw sqlException;
                }
            }
        }

        // for scrollable ResultSet's,
        // if the "next" request is still fetching within the current rowset,
        //   update column info from cache and increment the current row index
        // else
        //   fetch the next rowset from the server
        else {

            // These flags will only be used for dynamic cursors where we don't know the row count
            // and can't keep track of the absolute position of the cursor.
            isAfterLast_ = false;
            isLast_ = false;

            // if the next row is still within the current rowset
            if (rowIsInCurrentRowset(firstRowInRowset_ + currentRowInRowset_ + 1, scrollOrientation_next__)) {
                isValidCursorPosition_ = true;
                currentRowInRowset_++;
            } else {
                checkAndThrowReceivedQueryTerminatingException();
                isValidCursorPosition_ = getNextRowset();
            }

            if (isValidCursorPosition_) {
                updateColumnInfoFromCache();
                // check if there is a non-null SQLCA for the current row for rowset cursors
                checkRowsetSqlca();
                if (isBeforeFirst_) {
                    isFirst_ = true;
                }
                isBeforeFirst_ = false;
            } else {
                isFirst_ = false;
                return isValidCursorPosition_;
            }
        }

        // for forward-only cursors, check if rowsRead_ > maxRows_.
        // for scrollable cursors, check if absolute row number > maxRows_.
        // maxRows_ will be ignored by sensitive dynamic cursors since we don't know the rowCount
        if (!openOnClient_) {
            isValidCursorPosition_ = false;
        } else if (sensitivity_ != sensitivity_sensitive_dynamic__ && statement_.maxRows_ > 0 &&
                (firstRowInRowset_ + currentRowInRowset_ > statement_.maxRows_)) {
            isValidCursorPosition_ = false;
        }
        return isValidCursorPosition_;
    }


    public void close() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "close");
            }
            closeX();
        }
    }

    // TO DO: when parseEndqryrm() notifies common w/ endQueryCloseOnlyEvent() we need to mark something
    // that we later check to drive a commit.
    // An untraced version of close()
    public final void closeX() throws SqlException {
        if (!openOnClient_) {
            return;
        }
        try {
            if (openOnServer_) {
                flowCloseAndAutoCommitIfNotAutoCommitted();
            } else {
                flowAutoCommitIfNotAutoCommitted(); // in case of early close
            }
        } finally {
            markClosed();
            connection_.CommitAndRollbackListeners_.remove(this);
        }

        flowAutoCommitIfLastOpenMultipleResultSetWasJustClosed();
        if (statement_.openOnClient_ && statement_.isCatalogQuery_) {
            statement_.closeX();
        }

        nullDataForGC();
    }

    public void nullDataForGC() {
        // This method is called by closeX().  We cannot call this if cursor is cached,
        // otherwise it will cause NullPointerException's when cursor is reused.
        // Cursor is only cached for PreparedStatement's.
        if (cursor_ != null && !statement_.isPreparedStatement_) {
            cursor_.nullDataForGC();
        }
        cursor_ = null;
        resultSetMetaData_ = null;
    }

    void flowCloseAndAutoCommitIfNotAutoCommitted() throws SqlException {
        agent_.beginWriteChain(statement_);
        writeCloseAndAutoCommitIfNotAutoCommitted();
        agent_.flow(statement_);
        readCloseAndAutoCommitIfNotAutoCommitted();
        agent_.endReadChain();
    }

    private void writeCloseAndAutoCommitIfNotAutoCommitted() throws SqlException {
        // set autoCommitted_ to false so commit will flow following
        // close cursor if autoCommit is true.
        autoCommitted_ = false;
        if (generatedSection_ == null) { // none call statement result set case
            writeCursorClose_(statement_.section_);
            writeAutoCommitIfNotAutoCommitted();
        } else { // call statement result set(s) case
            writeCursorClose_(generatedSection_);
        }
    }

    private void readCloseAndAutoCommitIfNotAutoCommitted() throws SqlException {
        if (generatedSection_ == null) { // none call statement result set case
            readCursorClose_();
            readAutoCommitIfNotAutoCommitted();
        } else { // call statement result set(s) case
            readCursorClose_();
        }
    }

    void writeClose() throws SqlException {
        // set autoCommitted_ to false so commit will flow following
        // close cursor if autoCommit is true.
        autoCommitted_ = false;
        if (generatedSection_ == null) { // none call statement result set case
            writeCursorClose_(statement_.section_);
        } else { // call statement result set(s) case
            writeCursorClose_(generatedSection_);
        }
    }

    void readClose() throws SqlException {
        try {
            if (generatedSection_ == null) { // none call statement result set case
                readCursorClose_();
            } else { // call statement result set(s) case
                readCursorClose_();
            }
        } finally {
            markClosed();
        }
    }

    void flowAutoCommitIfNotAutoCommitted() throws SqlException {
        if (generatedSection_ == null && connection_.autoCommit_ && !autoCommitted_) {
            connection_.flowAutoCommit();
            markAutoCommitted();
        }
    }

    // precondition: transaction state allows for auto commit to generate flow
    private void writeAutoCommitIfNotAutoCommitted() throws SqlException {
        if (connection_.autoCommit_ && !autoCommitted_) {
            connection_.writeAutoCommit();
        }
    }

    private void readAutoCommitIfNotAutoCommitted() throws SqlException {
        if (connection_.autoCommit_ && !autoCommitted_) {
            connection_.readAutoCommit();
            markAutoCommitted();
        }
    }

    private void flowAutoCommitIfLastOpenMultipleResultSetWasJustClosed() throws SqlException {
        // After this call, the generatedSection_ is reset to null to avoid repeating the commit.
        if (generatedSection_ != null && statement_ != null && statement_.resultSetList_ != null) {
            int count = 0;
            for (int i = 0; i < statement_.resultSetList_.length; i++) {
                if (statement_.resultSetList_[i] == null) {
                    count++;
                }
            }
            if (count == statement_.resultSetList_.length) {
                if (connection_.autoCommit_ && !autoCommitted_) {
                    connection_.flowAutoCommit();
                    markAutoCommitted();
                }
            }
        }
        generatedSection_ = null; // this is prevent a subsequent close() call from doing another autocommit.
    }

    public boolean wasNull() throws SqlException {

        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "wasNull");
        }
        checkForClosedResultSet();

        if (wasNull_ == ResultSet.WAS_NULL_UNSET) {
            throw new SqlException(agent_.logWriter_, "Invalid operation: wasNull() called with no data retrieved");
        }

        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "wasNull", wasNull_ == ResultSet.WAS_NULL);
        }
        return wasNull_ == ResultSet.WAS_NULL;
    }

    //------------------- getters on column index --------------------------------

    // Live life on the edge and run unsynchronized
    public boolean getBoolean(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getBoolean", column);
        }
        checkGetterPreconditions(column);
        boolean result = false;
        if (wasNonNullSensitiveUpdate(column)) {
            result = agent_.crossConverters_.setBooleanFromObject(updatedColumns_[column - 1],
                    resultSetMetaData_.types_[column - 1]);
        } else {
            result = isNull(column) ? false : cursor_.getBoolean(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getBoolean", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public byte getByte(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getByte", column);
        }
        checkGetterPreconditions(column);
        byte result = 0;
        if (wasNonNullSensitiveUpdate(column)) {
            result = agent_.crossConverters_.setByteFromObject(updatedColumns_[column - 1],
                    resultSetMetaData_.types_[column - 1]);
        } else {
            result = isNull(column) ? 0 : cursor_.getByte(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getByte", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public short getShort(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getShort", column);
        }
        checkGetterPreconditions(column);
        short result = 0;
        if (wasNonNullSensitiveUpdate(column)) {
            result = ((Short) agent_.crossConverters_.setObject(java.sql.Types.SMALLINT,
                    updatedColumns_[column - 1])).shortValue();
        } else {
            result = isNull(column) ? 0 : cursor_.getShort(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getShort", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public int getInt(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getInt", column);
        }
        checkGetterPreconditions(column);
        int result = 0;
        if (wasNonNullSensitiveUpdate(column)) {
            result = ((Integer) agent_.crossConverters_.setObject(java.sql.Types.INTEGER,
                    updatedColumns_[column - 1])).intValue();
        } else {
            result = isNull(column) ? 0 : cursor_.getInt(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getInt", result);
        }
        setWasNull(column); // this is placed here close to the return to minimize risk of race condition.
        return result;
    }

    // Live life on the edge and run unsynchronized
    public long getLong(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getLong", column);
        }
        checkGetterPreconditions(column);
        long result = 0;
        if (wasNonNullSensitiveUpdate(column)) {
            result = ((Long) agent_.crossConverters_.setObject(java.sql.Types.BIGINT,
                    updatedColumns_[column - 1])).longValue();
        } else {
            result = isNull(column) ? 0 : cursor_.getLong(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getLong", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public float getFloat(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getFloat", column);
        }
        checkGetterPreconditions(column);
        float result = 0;
        if (wasNonNullSensitiveUpdate(column)) {
            result = ((Float) agent_.crossConverters_.setObject(java.sql.Types.REAL,
                    updatedColumns_[column - 1])).floatValue();
        } else {
            result = isNull(column) ? 0 : cursor_.getFloat(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getFloat", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public double getDouble(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getDouble", column);
        }
        checkGetterPreconditions(column);
        double result = 0;
        if (wasNonNullSensitiveUpdate(column)) {
            result = ((Double) agent_.crossConverters_.setObject(java.sql.Types.DOUBLE,
                    updatedColumns_[column - 1])).doubleValue();
        } else {
            result = isNull(column) ? 0 : cursor_.getDouble(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getDouble", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.math.BigDecimal getBigDecimal(int column, int scale) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceDeprecatedEntry(this, "getBigDecimal", column, scale);
        }
        checkGetterPreconditions(column);
        java.math.BigDecimal result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result =
                    ((java.math.BigDecimal) agent_.crossConverters_.setObject(java.sql.Types.DECIMAL,
                            updatedColumns_[column - 1])).setScale(scale, java.math.BigDecimal.ROUND_DOWN);
        } else {
            result =
                    isNull(column) ? null : cursor_.getBigDecimal(column).setScale(scale, java.math.BigDecimal.ROUND_DOWN);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceDeprecatedExit(this, "getBigDecimal", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.math.BigDecimal getBigDecimal(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getBigDecimal", column);
        }
        checkGetterPreconditions(column);
        java.math.BigDecimal result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result =
                    (java.math.BigDecimal) agent_.crossConverters_.setObject(java.sql.Types.DECIMAL,
                            updatedColumns_[column - 1]);
        } else {
            result = isNull(column) ? null : cursor_.getBigDecimal(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getBigDecimal", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.sql.Date getDate(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getDate", column);
        }
        checkGetterPreconditions(column);
        java.sql.Date result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result = (java.sql.Date) agent_.crossConverters_.setObject(java.sql.Types.DATE, updatedColumns_[column - 1]);
        } else {
            result = isNull(column) ? null : cursor_.getDate(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getDate", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.sql.Date getDate(int column, java.util.Calendar calendar) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getDate", column, calendar);
        }
        if (calendar == null) {
            throw new SqlException(agent_.logWriter_, "Invalid parameter: calendar is null");
        }
        java.sql.Date date = getDate(column);
        if (date != null) {
            java.util.Calendar targetCalendar = java.util.Calendar.getInstance(calendar.getTimeZone());
            targetCalendar.clear();
            targetCalendar.setTime(date);
            java.util.Calendar defaultCalendar = java.util.Calendar.getInstance();
            defaultCalendar.clear();
            defaultCalendar.setTime(date);
            long timeZoneOffset =
                    targetCalendar.get(java.util.Calendar.ZONE_OFFSET) - defaultCalendar.get(java.util.Calendar.ZONE_OFFSET) +
                    targetCalendar.get(java.util.Calendar.DST_OFFSET) - defaultCalendar.get(java.util.Calendar.DST_OFFSET);
            date.setTime(date.getTime() - timeZoneOffset);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getDate", date);
        }
        return date;
    }

    // Live life on the edge and run unsynchronized
    public java.sql.Time getTime(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getTime", column);
        }
        checkGetterPreconditions(column);
        java.sql.Time result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result = (java.sql.Time) agent_.crossConverters_.setObject(java.sql.Types.TIME, updatedColumns_[column - 1]);
        } else {
            result = isNull(column) ? null : cursor_.getTime(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getTime", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.sql.Time getTime(int column, java.util.Calendar calendar) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getTime", column, calendar);
        }
        if (calendar == null) {
            throw new SqlException(agent_.logWriter_, "Invalid parameter: calendar is null");
        }
        java.sql.Time time = getTime(column);
        if (time != null) {
            java.util.Calendar targetCalendar = java.util.Calendar.getInstance(calendar.getTimeZone());
            targetCalendar.clear();
            targetCalendar.setTime(time);
            java.util.Calendar defaultCalendar = java.util.Calendar.getInstance();
            defaultCalendar.clear();
            defaultCalendar.setTime(time);
            long timeZoneOffset =
                    targetCalendar.get(java.util.Calendar.ZONE_OFFSET) - defaultCalendar.get(java.util.Calendar.ZONE_OFFSET) +
                    targetCalendar.get(java.util.Calendar.DST_OFFSET) - defaultCalendar.get(java.util.Calendar.DST_OFFSET);
            time.setTime(time.getTime() - timeZoneOffset);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getTime", time);
        }
        return time;
    }

    // Live life on the edge and run unsynchronized
    public java.sql.Timestamp getTimestamp(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getTimestamp", column);
        }
        checkGetterPreconditions(column);
        java.sql.Timestamp result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result = (java.sql.Timestamp) agent_.crossConverters_.setObject(java.sql.Types.TIMESTAMP, updatedColumns_[column - 1]);
        } else {
            result = isNull(column) ? null : cursor_.getTimestamp(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getTimestamp", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.sql.Timestamp getTimestamp(int column, java.util.Calendar calendar) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getTimestamp", column, calendar);
        }
        if (calendar == null) {
            throw new SqlException(agent_.logWriter_, "Invalid parameter: calendar is null");
        }
        java.sql.Timestamp timestamp = getTimestamp(column);
        if (timestamp != null) {
            int nano = timestamp.getNanos();
            java.util.Calendar targetCalendar = java.util.Calendar.getInstance(calendar.getTimeZone());
            targetCalendar.clear();
            targetCalendar.setTime(timestamp);
            java.util.Calendar defaultCalendar = java.util.Calendar.getInstance();
            defaultCalendar.clear();
            defaultCalendar.setTime(timestamp);
            long timeZoneOffset =
                    targetCalendar.get(java.util.Calendar.ZONE_OFFSET) - defaultCalendar.get(java.util.Calendar.ZONE_OFFSET) +
                    targetCalendar.get(java.util.Calendar.DST_OFFSET) - defaultCalendar.get(java.util.Calendar.DST_OFFSET);
            timestamp.setTime(timestamp.getTime() - timeZoneOffset);
            timestamp.setNanos(nano);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getTimestamp", timestamp);
        }
        return timestamp;
    }

    // Live life on the edge and run unsynchronized
    public String getString(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getString", column);
        }
        checkGetterPreconditions(column);
        String result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result = (String) agent_.crossConverters_.setObject(java.sql.Types.CHAR, updatedColumns_[column - 1]);
        } else {
            result = isNull(column) ? null : cursor_.getString(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getString", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public byte[] getBytes(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getBytes", column);
        }
        checkGetterPreconditions(column);
        byte[] result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result = (byte[]) agent_.crossConverters_.setObject(java.sql.Types.BINARY, updatedColumns_[column - 1]);
        } else {
            result = isNull(column) ? null : cursor_.getBytes(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getBytes", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.io.InputStream getBinaryStream(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getBinaryStream", column);
        }
        checkGetterPreconditions(column);
        java.io.InputStream result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result = new java.io.ByteArrayInputStream((byte[]) agent_.crossConverters_.setObject(java.sql.Types.BINARY, updatedColumns_[column - 1]));
        } else {
            result = isNull(column) ? null : cursor_.getBinaryStream(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getBinaryStream", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.io.InputStream getAsciiStream(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getAsciiStream", column);
        }
        checkGetterPreconditions(column);
        java.io.InputStream result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            try {
                result = new java.io.ByteArrayInputStream
                        (((String) agent_.crossConverters_.setObject(java.sql.Types.CHAR,
                                updatedColumns_[column - 1])).getBytes("US-ASCII"));
            } catch (java.io.UnsupportedEncodingException e) {
                throw new SqlException(agent_.logWriter_, e, e.getMessage());
            }
        } else {
            result = isNull(column) ? null : cursor_.getAsciiStream(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getAsciiStream", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.io.InputStream getUnicodeStream(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceDeprecatedEntry(this, "getUnicodeStream", column);
        }
        checkGetterPreconditions(column);
        java.io.InputStream result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            try {
                result = new java.io.ByteArrayInputStream
                        (((String) agent_.crossConverters_.setObject(java.sql.Types.CHAR,
                                updatedColumns_[column - 1])).getBytes("UTF-8"));
            } catch (java.io.UnsupportedEncodingException e) {
                throw new SqlException(agent_.logWriter_, e, e.getMessage());
            }
        } else {
            result = isNull(column) ? null : cursor_.getUnicodeStream(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceDeprecatedExit(this, "getUnicodeStream", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.io.Reader getCharacterStream(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getCharacterStream", column);
        }
        checkGetterPreconditions(column);
        java.io.Reader result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result = new java.io.StringReader
                    ((String) agent_.crossConverters_.setObject(java.sql.Types.CHAR, updatedColumns_[column - 1]));
        } else {
            result = isNull(column) ? null : cursor_.getCharacterStream(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getCharacterStream", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.sql.Blob getBlob(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getBlob", column);
        }
        checkGetterPreconditions(column);
        java.sql.Blob result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result = (java.sql.Blob) agent_.crossConverters_.setObject(java.sql.Types.BLOB,
                    updatedColumns_[column - 1]);
        } else {
            result = isNull(column) ? null : cursor_.getBlob(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getBlob", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.sql.Clob getClob(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getClob", column);
        }
        checkGetterPreconditions(column);
        java.sql.Clob result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result = (java.sql.Clob) agent_.crossConverters_.setObject(java.sql.Types.CLOB,
                    updatedColumns_[column - 1]);
        } else {
            result = isNull(column) ? null : cursor_.getClob(column);
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getClob", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.sql.Ref getRef(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getRef", column);
        }
        checkGetterPreconditions(column);
        java.sql.Ref result = isNull(column) ? null : cursor_.getRef(column);
        if (true) {
            throw new SqlException(agent_.logWriter_, "jdbc 2 method not yet implemented");
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getRef", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public java.sql.Array getArray(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getArray", column);
        }
        checkGetterPreconditions(column);
        java.sql.Array result = isNull(column) ? null : cursor_.getArray(column);
        if (true) {
            throw new SqlException(agent_.logWriter_, "jdbc 2 method not yet implemented");
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getArray", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public Object getObject(int column) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getObject", column);
        }
        Object result = getObjectX(column);
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getObject", result);
        }
        return result;
    }

    // used by DBMD
    Object getObjectX(int column) throws SqlException {
        checkGetterPreconditions(column);
        Object result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result = updatedColumns_[column - 1];
        } else {
            result = isNull(column) ? null : cursor_.getObject(column);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    // Live life on the edge and run unsynchronized
    public Object getObject(int column, java.util.Map map) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getObject", column, map);
        }
        checkGetterPreconditions(column);
        Object result = null;
        if (wasNonNullSensitiveUpdate(column)) {
            result = updatedColumns_[column - 1];
        } else {
            result = isNull(column) ? null : cursor_.getObject(column);
        }
        if (true) {
            throw new SqlException(agent_.logWriter_, "jdbc 2 method not yet implemented");
        }
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getObject", result);
        }
        setWasNull(column);  // Placed close to the return to minimize risk of thread interference
        return result;
    }

    //----------------------------------------------------------------------------

    // This method only returns true if there is a new non-null updated value.
    // If the resultset is updatable, sensitive, and updated, return the new non-null updated value.
    // Otherwise this method will return false.
    // If the column is updated to null, or if the column has not been update but is null,
    // a null will be returned by isNull(), which first calls wasNullSensitiveUpdate() to check for a column
    // that is updated to null, and columnUpdated_ is checked there.
    private boolean wasNonNullSensitiveUpdate(int column) {
        return
                updatedColumns_ != null &&
                updatedColumns_[column - 1] != null;
    }

    // if updatedColumns_ entry is null, but columnUpdated_ entry
    // indicates column has been updated, then column is updated to null.
    private boolean wasNullSensitiveUpdate(int column) {
        return
                resultSetType_ == java.sql.ResultSet.TYPE_SCROLL_SENSITIVE &&
                updatedColumns_ != null &&
                updatedColumns_[column - 1] == null &&
                columnUpdated_[column - 1];
    }

    private void setWasNull(int column) {
        if (wasNullSensitiveUpdate(column)) {
            wasNull_ = WAS_NULL;
        } else {
            wasNull_ = (cursor_.isNull_ == null || cursor_.isNull_[column - 1]) ? WAS_NULL : WAS_NOT_NULL;
        }
    }

    private boolean isNull(int column) {
        if (wasNullSensitiveUpdate(column)) {
            return true;
        } else {
            return (cursor_.isUpdateDeleteHole_ == true || cursor_.isNull_[column - 1]);
        }
    }

    // ------------- Methods for accessing results by column name ----------------

    public final boolean getBoolean(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getBoolean", columnName);
        }
        return getBoolean(findColumnX(columnName));
    }

    public final byte getByte(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getByte", columnName);
        }
        return getByte(findColumnX(columnName));
    }

    public final short getShort(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getShort", columnName);
        }
        return getShort(findColumnX(columnName));
    }

    public final int getInt(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getInt", columnName);
        }
        return getInt(findColumnX(columnName));
    }

    public final long getLong(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getLong", columnName);
        }
        return getLong(findColumnX(columnName));
    }

    public final float getFloat(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getFloat", columnName);
        }
        return getFloat(findColumnX(columnName));
    }

    public final double getDouble(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getDouble", columnName);
        }
        return getDouble(findColumnX(columnName));
    }

    public final java.math.BigDecimal getBigDecimal(String columnName, int scale) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceDeprecatedEntry(this, "getBigDecimal", columnName, scale);
        }
        return getBigDecimal(findColumnX(columnName), scale);
    }

    public final java.math.BigDecimal getBigDecimal(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getBigDecimal", columnName);
        }
        return getBigDecimal(findColumnX(columnName));
    }

    public final java.sql.Date getDate(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getDate", columnName);
        }
        return getDate(findColumnX(columnName));
    }

    public final java.sql.Date getDate(String columnName, java.util.Calendar cal) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getDate", columnName, cal);
        }
        return getDate(findColumnX(columnName), cal);
    }

    public final java.sql.Time getTime(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getTime", columnName);
        }
        return getTime(findColumnX(columnName));
    }

    public final java.sql.Time getTime(String columnName, java.util.Calendar cal) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getTime", columnName, cal);
        }
        return getTime(findColumnX(columnName), cal);
    }

    public final java.sql.Timestamp getTimestamp(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getTimestamp", columnName);
        }
        return getTimestamp(findColumnX(columnName));
    }

    public final java.sql.Timestamp getTimestamp(String columnName, java.util.Calendar cal) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getTimestamp", columnName, cal);
        }
        return getTimestamp(findColumnX(columnName), cal);
    }

    public final String getString(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getString", columnName);
        }
        return getString(findColumnX(columnName));
    }

    public final byte[] getBytes(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getBytes", columnName);
        }
        return getBytes(findColumnX(columnName));
    }

    public final java.io.InputStream getBinaryStream(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getBinaryStream", columnName);
        }
        return getBinaryStream(findColumnX(columnName));
    }

    public final java.io.InputStream getAsciiStream(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getAsciiStream", columnName);
        }
        return getAsciiStream(findColumnX(columnName));
    }

    public final java.io.InputStream getUnicodeStream(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceDeprecatedEntry(this, "getUnicodeStream", columnName);
        }
        return getUnicodeStream(findColumnX(columnName));
    }

    public final java.io.Reader getCharacterStream(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getCharacterStream", columnName);
        }
        return getCharacterStream(findColumnX(columnName));
    }

    public final java.sql.Blob getBlob(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getBlob", columnName);
        }
        return getBlob(findColumnX(columnName));
    }

    public final java.sql.Clob getClob(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getClob", columnName);
        }
        return getClob(findColumnX(columnName));
    }

    public final java.sql.Array getArray(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getArray", columnName);
        }
        return getArray(findColumnX(columnName));
    }

    public final java.sql.Ref getRef(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getRef", columnName);
        }
        return getRef(findColumnX(columnName));
    }

    public final Object getObject(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getObject", columnName);
        }
        return getObject(findColumnX(columnName));
    }

    public final Object getObject(String columnName, java.util.Map map) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getObject", columnName, map);
        }
        return getObject(findColumnX(columnName), map);
    }

    // ----------------Advanced features -----------------------------------------

    public final java.sql.SQLWarning getWarnings() {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getWarnings", warnings_);
        }
        return warnings_;
    }

    public final void clearWarnings() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "clearWarnings");
            }
            warnings_ = null;
        }
    }

    // An untraced version of clearWarnings()
    public final void clearWarningsX() {
        warnings_ = null;
    }

    public String getCursorName() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "getCursorName");
            }
            checkForClosedResultSet();
            if (generatedSection_ != null) {
                return "stored procedure generated cursor:" + generatedSection_.getServerCursorName();
            }
            if (statement_.cursorName_ == null) {// cursor name is not in the maps yet.
                statement_.cursorName_ = statement_.section_.getServerCursorName();
                if (statement_.section_ instanceof Section) {
                    agent_.sectionManager_.mapCursorNameToQuerySection(statement_.cursorName_,
                            (Section) statement_.section_);
                }
            }
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceExit(this, "getCursorName", statement_.cursorName_);
            }
            return statement_.cursorName_;
        }
    }

    public java.sql.ResultSetMetaData getMetaData() throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "getMetaData");
        }
        java.sql.ResultSetMetaData resultSetMetaData = getMetaDataX();
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getMetaData", resultSetMetaData);
        }
        return resultSetMetaData;
    }

    // used by DBMD
    ColumnMetaData getMetaDataX() throws SqlException {
        checkForClosedResultSet();
        return resultSetMetaData_;
    }


    public final int findColumn(String columnName) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "findColumn", columnName);
            }
            int column = findColumnX(columnName);
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceExit(this, "findColumn", column);
            }
            return column;
        }
    }

    // An untraced version of findColumn()
    private final int findColumnX(String columnName) throws SqlException {
        checkForClosedResultSet();
        return resultSetMetaData_.findColumnX(columnName);
    }

    //-------------------------- Traversal/Positioning ---------------------------

    public boolean isBeforeFirst() throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "isBeforeFirst");
        }
        checkForClosedResultSet();
        checkThatResultSetTypeIsScrollable();
        // Returns false if the ResultSet contains no rows.
        boolean isBeforeFirst = isBeforeFirstX();
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "isBeforeFirst", isBeforeFirst);
        }
        return isBeforeFirst;
    }

    private boolean isBeforeFirstX() throws SqlException {
        if (sensitivity_ == sensitivity_sensitive_dynamic__) {
            return isBeforeFirst_;
        } else
        //return ((resultSetContainsNoRows()) ? false : (currentRowInRowset_ == -1));
        {
            return ((currentRowInRowset_ == -1) && !resultSetContainsNoRows());
        }
    }

    public boolean isAfterLast() throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "isAfterLast");
        }
        checkForClosedResultSet();
        checkThatResultSetTypeIsScrollable();
        // Returns false if the ResultSet contains no rows.
        boolean isAfterLast = isAfterLastX();
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "isAfterLast", isAfterLast);
        }
        return isAfterLast;
    }

    private boolean isAfterLastX() throws SqlException {
        if (sensitivity_ == sensitivity_sensitive_dynamic__) {
            return isAfterLast_;
        } else {
            return (resultSetContainsNoRows() ? false :
                    (firstRowInRowset_ == currentRowInRowset_ &&
                    currentRowInRowset_ == lastRowInRowset_ &&
                    lastRowInRowset_ == 0 &&
                    absolutePosition_ == rowCount_ + 1));
        }
    }

    public boolean isFirst() throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "isFirst");
        }
        checkForClosedResultSet();
        checkThatResultSetTypeIsScrollable();
        // Not necessary to get the rowCount_ since currentRowInRowset_ is initialized to -1,
        // and it will not be changed if there is no rows in the ResultSet.
        boolean isFirst = isFirstX();
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "isFirst", isFirst);
        }
        return isFirst;
    }

    private boolean isFirstX() {
        if (sensitivity_ == sensitivity_sensitive_dynamic__) {
            return isFirst_;
        }
        return (firstRowInRowset_ == 1 && currentRowInRowset_ == 0);
    }

    public boolean isLast() throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "isLast");
        }
        checkForClosedResultSet();
        checkThatResultSetTypeIsScrollable();
        // Returns false if the ResultSet contains no rows.
        boolean isLast = isLastX();
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "isLast", isLast);
        }
        return isLast;
    }

    private boolean isLastX() throws SqlException {
        if (sensitivity_ == sensitivity_sensitive_dynamic__) {
            return isLast_;
        } else {
            return (resultSetContainsNoRows() ? false :
                    (firstRowInRowset_ + currentRowInRowset_) == rowCount_);
        }
    }

    public void beforeFirst() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "beforeFirst");
            }
            checkForClosedResultSet();
            checkThatResultSetTypeIsScrollable();
            clearWarningsX();
            beforeFirstX();
        }
    }

    private void beforeFirstX() throws SqlException {
        resetRowsetFlags();

        // this method has no effect if the result set has no rows.
        // only send cntqry to position the cursor before first if
        // resultset contains rows and it is not already before first, or
        // if the cursor is a dynamic cursor.
        if (sensitivity_ == sensitivity_sensitive_dynamic__ ||
                (!resultSetContainsNoRows() && !isServersCursorPositionBeforeFirst())) {
            moveToBeforeFirst();
        }
        isBeforeFirst_ = true;
        setRowsetBeforeFirstEvent();
        cursor_.resetDataBuffer();
        resetRowsetSqlca();
        isValidCursorPosition_ = false;
    }

    public void afterLast() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "afterLast");
            }
            checkForClosedResultSet();
            checkThatResultSetTypeIsScrollable();
            clearWarningsX();
            afterLastX();
        }
    }

    private void afterLastX() throws SqlException {
        resetRowsetFlags();

        // this method has no effect if the result set has no rows.
        // only send cntqry to position the cursor after last if
        // resultset contains rows and it is not already after last, or
        // if the cursor is a dynamic cursor.
        if (sensitivity_ == sensitivity_sensitive_dynamic__ ||
                (!resultSetContainsNoRows() && !isServerCursorPositionAfterLast())) {
            moveToAfterLast();
        }
        isAfterLast_ = true;
        setRowsetAfterLastEvent();
        cursor_.resetDataBuffer();
        resetRowsetSqlca();
        isValidCursorPosition_ = false;
    }

    public boolean first() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "first");
            }
            boolean isValidCursorPosition = firstX();
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceExit(this, "first", isValidCursorPosition);
            }
            return isValidCursorPosition;
        }
    }

    private boolean firstX() throws SqlException {
        checkForClosedResultSet();
        checkThatResultSetTypeIsScrollable();
        clearWarningsX();

        wasNull_ = ResultSet.WAS_NULL_UNSET;

        // discard all previous updates when moving the cursor
        resetUpdatedColumns();

        resetRowsetFlags();

        // if first row is not in the current rowset, fetch the first rowset from the server.
        // rowIsInCurrentRowset with orientation first will always return false for dynamic cursors.
        if (rowIsInCurrentRowset(1, scrollOrientation_first__)) {
            isValidCursorPosition_ = true;
            currentRowInRowset_ = 0;
        } else {
            checkAndThrowReceivedQueryTerminatingException();
            isValidCursorPosition_ = getFirstRowset();
        }

        if (isValidCursorPosition_) {
            updateColumnInfoFromCache();
            isFirst_ = true;
            // check if there is a non-null SQLCA for the row for rowset cursors
            checkRowsetSqlca();
        }

        return isValidCursorPosition_;
    }

    public boolean last() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "last");
            }
            boolean isValidCursorPosition = lastX();
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceExit(this, "last", isValidCursorPosition);
            }
            return isValidCursorPosition;
        }
    }

    private boolean lastX() throws SqlException {
        checkForClosedResultSet();
        checkThatResultSetTypeIsScrollable();
        clearWarningsX();

        wasNull_ = ResultSet.WAS_NULL_UNSET;

        // discard all previous updates when moving the cursor
        resetUpdatedColumns();

        resetRowsetFlags();

        // only get the rowCount for static cursors.
        if (rowCountIsUnknown()) {
            getRowCount();
        }
        long row = rowCount_;
        if (sensitivity_ != sensitivity_sensitive_dynamic__ && statement_.maxRows_ > 0) {
            if (rowCount_ > statement_.maxRows_) {
                row = statement_.maxRows_;
            }
        }

        // rowIsInCurrentRowset with orientation last will always return false for dynamic cursors.
        if (rowIsInCurrentRowset(row, scrollOrientation_last__)) {
            isValidCursorPosition_ = true;
            currentRowInRowset_ = row - firstRowInRowset_;
        } else {
            checkAndThrowReceivedQueryTerminatingException();
            isValidCursorPosition_ = getLastRowset(row);
        }

        if (isValidCursorPosition_) {
            updateColumnInfoFromCache();
            isLast_ = true;
            // check if there is a non-null SQLCA for the current row for rowset cursors
            checkRowsetSqlca();
        }

        return isValidCursorPosition_;
    }

    public int getRow() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "getRow");
            }
            int row = getRowX();
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceExit(this, "getRow", row);
            }
            return row;
        }
    }

    private int getRowX() throws SqlException {
        checkForClosedResultSet();
        long row;
        checkThatResultSetIsNotDynamic();
        if (resultSetType_ == java.sql.ResultSet.TYPE_FORWARD_ONLY)
        // for forward-only cursors, getRow() should return 0 if cursor is not on a valid row,
        // i.e. afterlast.
        {
            row = (cursor_.allRowsReceivedFromServer_ &&
                    cursor_.currentRowPositionIsEqualToNextRowPosition()) ? 0 : cursor_.rowsRead_;
        } else {
            if (rowCountIsUnknown()) {
                // commented out here because the following method is called the first thing
                // inside getRowCount();
                //checkAndThrowReceivedQueryTerminatingException();
                getRowCount();
            }
            if (rowCount_ == 0 || currentRowInRowset_ < 0) // || currentRowInRowset_ > rowCount_)
            {
                row = 0;
            } else {
                row = firstRowInRowset_ + currentRowInRowset_;
            }
        }
        if (row > Integer.MAX_VALUE) {
            this.accumulateWarning(new SqlWarning(agent_.logWriter_, "Value too large to fit in an int."));
        }
        return (int) row;
    }

    public boolean absolute(int row) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "absolute", row);
            }
            boolean isValidCursorPosition = absoluteX(row);
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceExit(this, "absolute", isValidCursorPosition);
            }
            return isValidCursorPosition;
        }
    }

    public boolean absoluteX(int row) throws SqlException {
        checkForClosedResultSet();
        checkThatResultSetTypeIsScrollable();
        clearWarningsX();

        wasNull_ = ResultSet.WAS_NULL_UNSET;

        // discard all previous updates when moving the cursor.
        resetUpdatedColumns();

        resetRowsetFlags();

        if (statement_.maxRows_ > 0) {
            // if "row" is positive and > maxRows, fetch afterLast
            // else if "row" is negative, and abs(row) > maxRows, fetch beforeFirst
            if (row > 0 && row > statement_.maxRows_) {
                afterLastX();
                isValidCursorPosition_ = false;
                return isValidCursorPosition_;
            } else if (row <= 0 && java.lang.Math.abs(row) > statement_.maxRows_) {
                beforeFirstX();
                isValidCursorPosition_ = false;
                return isValidCursorPosition_;
            }
        }

        int fetchAbsoluteRow = 0;
        if (rowCountIsUnknown()) {
            getRowCount();
        }
        if (sensitivity_ == sensitivity_sensitive_dynamic__) {
            fetchAbsoluteRow = row;
        } else
        // calculate the positive absolute row number based on rowCount for static or insensitive cursors.
        {
            fetchAbsoluteRow = (row >= 0) ? row : (int) (rowCount_ + row + 1);
        }

        // rowIsInCurrentRowset with orientation absolute will always return false for dynamic cursors.
        if (rowIsInCurrentRowset(fetchAbsoluteRow, scrollOrientation_absolute__)) {
            isValidCursorPosition_ = true;
            currentRowInRowset_ = fetchAbsoluteRow - firstRowInRowset_;
        } else {
            checkAndThrowReceivedQueryTerminatingException();
            isValidCursorPosition_ = getAbsoluteRowset(fetchAbsoluteRow);
        }

        if (isValidCursorPosition_) {
            updateColumnInfoFromCache();
            if (row == 1) {
                isFirst_ = true;
            }
            if (row == -1) {
                isLast_ = true;
            }
            // check if there is a non-null SQLCA for the row for rowset cursors
            checkRowsetSqlca();
        }

        return isValidCursorPosition_;
    }

    public boolean relative(int rows) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "relative", rows);
            }
            boolean isValidCursorPosition = relativeX(rows);
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceExit(this, "relative", isValidCursorPosition);
            }
            return isValidCursorPosition;
        }
    }

    private boolean relativeX(int rows) throws SqlException {
        checkForClosedResultSet();
        checkThatResultSetTypeIsScrollable();
        clearWarningsX();
        wasNull_ = ResultSet.WAS_NULL_UNSET;

        // discard all previous updates when moving the cursor.
        resetUpdatedColumns();

        // this method may not be called when the cursor on the insert row
        if (isOnInsertRow_) {
            throw new SqlException(agent_.logWriter_, "Cursor is Not on a Valid Row");
        }

        // If the resultset is empty, relative(n) is a null operation
        if (resultSetContainsNoRows()) {
            isValidCursorPosition_ = false;
            return isValidCursorPosition_;
        }
        
        // relative(0) is a null-operation, but the retruned result is
        // dependent on wether the cursorposition is on a row or not.
        if (rows == 0) {
            if (isBeforeFirstX() || isAfterLastX()) {
                isValidCursorPosition_ = false;
            } else {
                isValidCursorPosition_ = true;
            }
            return isValidCursorPosition_;
        }

        // Handle special cases when the cursor is before first or
        // after last, since the following code assumes we ar on a
        // valid cursor
        if (isBeforeFirstX()) {
            if (rows > 0) {
                nextX();
                return relativeX(rows-1);
            } else {
                isValidCursorPosition_ = false;
                return isValidCursorPosition_;
            }
        }
        if (isAfterLastX()) {
            if (rows < 0) {
                previousX();
                return relativeX(rows+1);
            } else {
                isValidCursorPosition_ = false;
                return isValidCursorPosition_;
            }
        }
        // Ok, now we are on a row and ready to do some real positioning.....

        resetRowsetFlags();

        // currentAbsoluteRowNumber is used for static cursors only.
        long currentAbsoluteRowNumber = firstRowInRowset_ + currentRowInRowset_;

        // if "rows" is positive, and currentRow+rows > maxRows, fetch afterLast.
        // if "rows" is negative, and if the absolute value of "rows" is greater than
        // the currentrow number, will fetch beforeFirst anyways.  do not need to check
        // for maxRows.
        if (sensitivity_ != sensitivity_sensitive_dynamic__ &&
                statement_.maxRows_ > 0 && rows > 0 && currentAbsoluteRowNumber + rows > statement_.maxRows_) {
            afterLastX();
            isValidCursorPosition_ = false;
            return isValidCursorPosition_;
        }

        if (rowIsInCurrentRowset(currentAbsoluteRowNumber + rows, scrollOrientation_relative__)) {
            currentRowInRowset_ += rows;
            isValidCursorPosition_ = true;
        } else {
            checkAndThrowReceivedQueryTerminatingException();
            long rowNumber =
                    (sensitivity_ == sensitivity_sensitive_dynamic__) ? currentRowInRowset_ + rows :
                    currentAbsoluteRowNumber + rows - absolutePosition_;
            isValidCursorPosition_ = getRelativeRowset(rowNumber);
        }

        if (isValidCursorPosition_) {
            updateColumnInfoFromCache();
            // check if there is a non-null SQLCA for the row for rowset cursors
            checkRowsetSqlca();
        }

        return isValidCursorPosition_;
    }

    public boolean previous() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "previous");
            }
            boolean isValidCursorPosition = previousX();
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceExit(this, "previous", isValidCursorPosition);
            }
            return isValidCursorPosition;
        }
    }

    private boolean previousX() throws SqlException {
        checkForClosedResultSet();
        checkThatResultSetTypeIsScrollable();
        clearWarningsX();

        wasNull_ = ResultSet.WAS_NULL_UNSET;

        // discard all previous updates when moving the cursor.
        resetUpdatedColumns();

        isBeforeFirst_ = false;
        isFirst_ = false;

        if (rowIsInCurrentRowset(firstRowInRowset_ + currentRowInRowset_ - 1, scrollOrientation_prior__)) {
            isValidCursorPosition_ = true;
            currentRowInRowset_--;
        } else {
            checkAndThrowReceivedQueryTerminatingException();
            isValidCursorPosition_ = getPreviousRowset();
        }

        if (isValidCursorPosition_) {
            updateColumnInfoFromCache();
            // check if there is a non-null SQLCA for the row for rowset cursors
            checkRowsetSqlca();
            if (isAfterLast_) {
                isLast_ = true;
            }
            isAfterLast_ = false;
        } else {
            return isValidCursorPosition_;
        }

        if (sensitivity_ != sensitivity_sensitive_dynamic__ && statement_.maxRows_ > 0 &&
                (firstRowInRowset_ + currentRowInRowset_ > statement_.maxRows_)) {
            isValidCursorPosition_ = false;
        }
        // auto-close result set if this is the last row from server and return false
        return isValidCursorPosition_;
    }

    public void setFetchDirection(int direction) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "setFetchDirection", direction);
            }
            checkForClosedResultSet();
            checkThatResultSetTypeIsScrollable();

            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 {
        checkForClosedResultSet();
        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);
            }
            checkForClosedResultSet();
            if (rows < 0 || (statement_.maxRows_ != 0 && rows > statement_.maxRows_)) {
                throw new SqlException(agent_.logWriter_, "Invalid fetch size " + rows);
            }
            setFetchSize_(rows);
        }
    }

    public int getFetchSize() throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getFetchSize", fetchSize_);
        }
        checkForClosedResultSet();
        return fetchSize_;
    }

    public int getType() throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getType", resultSetType_);
        }
        checkForClosedResultSet();
        return resultSetType_;
    }

    public int getConcurrency() throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getConcurrency", resultSetConcurrency_);
        }
        checkForClosedResultSet();
        return resultSetConcurrency_;
    }

    //----------------------------- Updates --------------------------------------

    public boolean rowUpdated() throws SqlException {
        // we cannot tell whether the ResultSet has been updated, so always return false here.
        boolean rowUpdated = false;
        checkForClosedResultSet();
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "rowUpdated", rowUpdated);
        }
        return rowUpdated;
    }

    public boolean rowInserted() throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "rowInserted");
        }
        checkForClosedResultSet();
        if (true) {
            throw new SqlException(agent_.logWriter_, "under construction");
        }
        boolean rowInserted = false;
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "rowInserted", rowInserted);
        }
        return rowInserted;
    }

    public boolean rowDeleted() throws SqlException {
        // rowDeleted is visible through a delete hole, (sqlcode +222).
        // Always return false and do not check the return code for now.
        boolean rowDeleted = false;
        checkForClosedResultSet();
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "rowDeleted", rowDeleted);
        }
        return rowDeleted;
    }

    // --------------------------- update column methods -------------------------

    public void updateNull(int column) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateNull", column);
            }
            checkUpdatePreconditions(column);
            if (!resultSetMetaData_.nullable_[column - 1]) {
                throw new SqlException(agent_.logWriter_, "Invalid operation to update a non-nullable column to null.");
            }
            updateColumn(column, null);
        }
    }

    public void updateBoolean(int column, boolean x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateBoolean", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateByte(int column, byte x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateByte", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateShort(int column, short x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateShort", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateInt(int column, int x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateInt", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateLong(int column, long x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateLong", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateFloat(int column, float x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateFloat", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateDouble(int column, double x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateDouble", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateBigDecimal(int column, java.math.BigDecimal x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateBigDecimal", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateDate(int column, java.sql.Date x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateDate", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateTime(int column, java.sql.Time x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateTime", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateTimestamp(int column, java.sql.Timestamp x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateTimestamp", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateString(int column, String x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateString", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateBytes(int column, byte x[]) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateBytes", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateBinaryStream(int column,
                                   java.io.InputStream x,
                                   int length) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateBinaryStream", column, x, length);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObjectFromBinaryStream(resultSetMetaData_.types_[column - 1], x, length));
        }
    }

    public void updateAsciiStream(int column,
                                  java.io.InputStream x,
                                  int length) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateAsciiStream", column, x, length);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObjectFromCharacterStream(resultSetMetaData_.types_[column - 1], x, "US-ASCII", length));
        }
    }

    public void updateCharacterStream(int column,
                                      java.io.Reader x,
                                      int length) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateCharacterStream", column, x, length);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x, length));
        }
    }

    public void updateObject(int column, Object x, int scale) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateObject", column, x, scale);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    public void updateObject(int column, Object x) throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateObject", column, x);
            }
            checkUpdatePreconditions(column);
            updateColumn(column, agent_.crossConverters_.setObject(resultSetMetaData_.types_[column - 1], x));
        }
    }

    // ---------------------- update on column name methods ----------------------

    public void updateNull(String columnName) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateNull", columnName);
        }
        updateNull(findColumnX(columnName));
    }

    public void updateBoolean(String columnName, boolean x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateBoolean", columnName, x);
        }
        updateBoolean(findColumnX(columnName), x);
    }

    public void updateByte(String columnName, byte x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateByte", columnName, x);
        }
        updateByte(findColumnX(columnName), x);
    }

    public void updateShort(String columnName, short x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateShort", columnName, x);
        }
        updateShort(findColumnX(columnName), x);
    }

    public void updateInt(String columnName, int x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateInt", columnName, x);
        }
        updateInt(findColumnX(columnName), x);
    }

    public void updateLong(String columnName, long x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateLong", columnName, x);
        }
        updateLong(findColumnX(columnName), x);
    }

    public void updateFloat(String columnName, float x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateFloat", columnName, x);
        }
        updateFloat(findColumnX(columnName), x);
    }

    public void updateDouble(String columnName, double x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateDouble", columnName, x);
        }
        updateDouble(findColumnX(columnName), x);
    }

    public void updateBigDecimal(String columnName, java.math.BigDecimal x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateBigDecimal", columnName, x);
        }
        updateBigDecimal(findColumnX(columnName), x);
    }

    public void updateDate(String columnName, java.sql.Date x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateDate", columnName, x);
        }
        updateDate(findColumnX(columnName), x);
    }

    public void updateTime(String columnName, java.sql.Time x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateTime", columnName, x);
        }
        updateTime(findColumnX(columnName), x);
    }

    public void updateTimestamp(String columnName, java.sql.Timestamp x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateTimestamp", columnName, x);
        }
        updateTimestamp(findColumnX(columnName), x);
    }

    public void updateString(String columnName, String x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateString", columnName, x);
        }
        updateString(findColumnX(columnName), x);
    }

    public void updateBytes(String columnName, byte x[]) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateBytes", columnName, x);
        }
        updateBytes(findColumnX(columnName), x);
    }

    public void updateBinaryStream(String columnName,
                                   java.io.InputStream x,
                                   int length) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateBinaryStream", columnName, x, length);
        }
        updateBinaryStream(findColumnX(columnName), x, length);
    }

    public void updateAsciiStream(String columnName,
                                  java.io.InputStream x,
                                  int length) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateAsciiStream", columnName, x, length);
        }
        updateAsciiStream(findColumnX(columnName), x, length);
    }

    public void updateCharacterStream(String columnName,
                                      java.io.Reader x,
                                      int length) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateCharacterStream", columnName, x, length);
        }
        updateCharacterStream(findColumnX(columnName), x, length);
    }

    public void updateObject(String columnName, Object x, int scale) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateObject", columnName, x, scale);
        }
        updateObject(findColumnX(columnName), x, scale);
    }

    public void updateObject(String columnName, Object x) throws SqlException {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceEntry(this, "updateObject", columnName, x);
        }
        updateObject(findColumnX(columnName), x);
    }

    // ---------------------------------------------------------------------------

    public void insertRow() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "insertRow");
            }
            checkForClosedResultSet();
            throw new SqlException(agent_.logWriter_, "Driver not capable: insertRow");
        }
    }

    public void updateRow() throws java.sql.SQLException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "updateRow");
            }
            //If updateXXX were issued on the row before updateRow, then
            //position the ResultSet to right before the next row after updateRow
            if (updateRowX())
                isValidCursorPosition_ = false;
        }
    }

    //if no updateXXX were issued before this updateRow, then return false
    private boolean updateRowX() throws java.sql.SQLException {
        checkForClosedResultSet();
        if (isOnInsertRow_ || resultSetConcurrency_ == java.sql.ResultSet.CONCUR_READ_ONLY) {
            throw new SqlException(agent_.logWriter_, "This method cannot be invoked while the cursor is on the insert " +
                    "row or if the concurrency of this ResultSet object is CONCUR_READ_ONLY.");
        }

        //if not on a valid row, then do not accept updateXXX calls
        if (!isValidCursorPosition_)
            throw new SqlException(agent_.logWriter_, "Invalid operation to " +
                    "update at current cursor position");

        // If no updateXXX has been called on this ResultSet object, then
        // updatedColumns_ will be null and hence no action required
        if (updatedColumns_ == null) {
            return false;
        }

        // updateXXX has been called on this ResultSet object, but check if it
        // has been called on the current row. If no column got updated on this
        // current row, then just return.
        boolean didAnyColumnGetUpdated = false;
        for (int i=0; i < updatedColumns_.length; i++) {
            if (columnUpdated_[i]) {
                didAnyColumnGetUpdated = true;
                break;
            }
        }
        if (didAnyColumnGetUpdated == false)
            return false;

        // User might not be updating all the updatable columns selected in the
        // select sql and hence every updateRow on the same ResultSet can be
        // potentially different than the previous one. Because of that, we
        // should get a new prepared statement to do updates every time
        getPreparedStatementForUpdate();

        // build the inputs array for the prepared statement for update
        int paramNumber = 0;
        for (int i = 0; i < updatedColumns_.length; i++) {
            if (resultSetMetaData_.sqlxUpdatable_[i] == 1) {
                // Since user may choose not to update all the columns in the
                // select list, check first if the column has been updated
                if (columnUpdated_[i] == false)
                    continue;
                paramNumber++;

                // column is updated either if the updatedColumns_ entry is not null,
                // or if the updatedColumns_ entry is null, but columnUpdated_ boolean is
                // set to true, which means columns is updated to a null.
                if (updatedColumns_[i] != null ||
                        (updatedColumns_[i] == null && columnUpdated_[i])) {
                    preparedStatementForUpdate_.setInput(paramNumber, updatedColumns_[i]);
                } else {
                    // Check if the original column is null.  Calling CrossConverters.setObject on a null
                    // column causes "Data Conversion" Exception.
                    Object originalObj = getObject(i + 1);
                    if (originalObj == null) {
                        preparedStatementForUpdate_.setInput(paramNumber, null);
                    } else {
                        preparedStatementForUpdate_.setInput(paramNumber, agent_.crossConverters_.setObject(resultSetMetaData_.types_[i], originalObj));
                    }
                }
            }
        }
        // need to cancel updates if the actual update was not successful at the server.
        // alternative is to check for updateCount_ in "positionToCurrentRowAndUpdate".
        // cancelRowUpdates if updateCount_ != 1, else set updateRowCalled_ to true.
        try {
            if (isRowsetCursor_ || sensitivity_ == sensitivity_sensitive_dynamic__) {
                update();
            } else {
                positionToCurrentRowAndUpdate();
            }
            updateRowCalled_ = true;
        } catch (SqlException e) {
            cancelRowUpdates();
            throw e;
        }
        return true;
    }

    public void deleteRow() throws java.sql.SQLException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "deleteRow");
            }
            deleteRowX();
            //the cursor is not positioned on the deleted row after deleteRow.
            //User needs to issue ResultSet.next to reposition the ResultSet
            //on a valid row
            isValidCursorPosition_ = false;
        }
    }

    private void deleteRowX() throws java.sql.SQLException {
        checkForClosedResultSet();

        // discard all previous updates
        resetUpdatedColumns();

        if (isOnInsertRow_ || resultSetConcurrency_ == java.sql.ResultSet.CONCUR_READ_ONLY) {
            throw new SqlException(agent_.logWriter_, "This method cannot be invoked while the cursor is on the insert " +
                    "row or if the concurrency of this ResultSet object is CONCUR_READ_ONLY.");
        }

        if (preparedStatementForDelete_ == null) {
            getPreparedStatementForDelete();
        }

        if (isRowsetCursor_ || sensitivity_ == sensitivity_sensitive_dynamic__) {
            delete();
        } else {
            positionToCurrentRowAndDelete();
        }

        Boolean nullIndicator = Cursor.ROW_IS_NULL;
        if (resultSetType_ == java.sql.ResultSet.TYPE_FORWARD_ONLY) {
            cursor_.isUpdateDeleteHole_ = true;
        } else {
            cursor_.isUpdateDeleteHoleCache_.set((int) currentRowInRowset_, nullIndicator);
            cursor_.isUpdateDeleteHole_ = ((Boolean) cursor_.isUpdateDeleteHoleCache_.get((int) currentRowInRowset_)).booleanValue();
        }
    }

    public void refreshRow() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "refreshRow");
            }
            refreshRowX();
        }
    }

    private void refreshRowX() throws SqlException {
        checkForClosedResultSet();
        checkThatResultSetTypeIsScrollable();
        if (isBeforeFirstX() || isAfterLastX() || isOnInsertRow_ ||
                resultSetConcurrency_ == java.sql.ResultSet.CONCUR_READ_ONLY) {
            throw new SqlException(agent_.logWriter_,
                    "This method cannot be invoked while the cursor is on the insert " +
                    "row, if the cursor is not on a valid row, or if this ResultSet " +
                    "object has a concurrency of CONCUR_READ_ONLY.");
        }

        // this method does nothing if ResultSet is TYPE_SCROLL_INSENSITIVE
        if (resultSetType_ == java.sql.ResultSet.TYPE_SCROLL_SENSITIVE) {
            isValidCursorPosition_ = getRefreshRowset();
            cancelRowUpdates();
        }
    }

    public void cancelRowUpdates() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "cancelRowUpdates");
            }
            checkForClosedResultSet();
            if (isOnInsertRow_ || resultSetConcurrency_ == java.sql.ResultSet.CONCUR_READ_ONLY) {
                throw new SqlException(agent_.logWriter_, "This method cannot be invoked while the cursor is on the insert " +
                        "row or if this ResultSet object has a concurrency of CONCUR_READ_ONLY.");
            }

            // if not on a valid row, then do not accept cancelRowUpdates call
            if (!isValidCursorPosition_)
                throw new SqlException(agent_.logWriter_, "Invalid operation " +
                        "at current cursor position.");

            // if updateRow() has already been called, then cancelRowUpdates should have
            // no effect.  updateRowCalled_ is reset to false as soon as the cursor moves to a new row.
            if (!updateRowCalled_) {
                resetUpdatedColumns();
            }
        }
    }

    public void moveToInsertRow() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "moveToInsertRow");
            }
            checkForClosedResultSet();
            throw new SqlException(agent_.logWriter_, "Driver not capable");
        }
    }

    public void moveToCurrentRow() throws SqlException {
        synchronized (connection_) {
            if (agent_.loggingEnabled()) {
                agent_.logWriter_.traceEntry(this, "moveToCurrentRow");
            }
            checkForClosedResultSet();
            if (resultSetConcurrency_ == java.sql.ResultSet.CONCUR_READ_ONLY) {
                throw new SqlException(agent_.logWriter_, "This method should only be called on ResultSet objects that are " +
                        "updatable(concurrency type CONCUR_UPDATABLE).");
            }

            if (!isOnInsertRow_) {
                // no affect
            } else {
                throw new SqlException(agent_.logWriter_, "Driver no capable");
            }
        }
    }

    public java.sql.Statement getStatement() {
        if (agent_.loggingEnabled()) {
            agent_.logWriter_.traceExit(this, "getStatement", statement_);
        }
        return statement_;
    }

    //-------------------------- JDBC 3.0 ----------------------------------------

    public java.net.URL getURL(int columnIndex) throws SqlException {
        throw new SqlException(agent_.logWriter_, "JDBC 3 method called - not yet supported");
    }

    public java.net.URL getURL(String columnName) throws SqlException {
        throw new SqlException(agent_.logWriter_, "JDBC 3 method called - not yet supported");
    }

    public void updateRef(int columnIndex, java.sql.Ref x) throws SqlException {
        throw new SqlException(agent_.logWriter_, "JDBC 3 method called - not yet supported");
    }

    public void updateRef(String columnName, java.sql.Ref x) throws SqlException {
        throw new SqlException(agent_.logWriter_, "JDBC 3 method called - not yet supported");
    }

    public void updateBlob(int columnIndex, java.sql.Blob x) throws SqlException {
        throw new SqlException(agent_.logWriter_, "JDBC 3 method called - not yet supported");
    }

    public void updateBlob(String columnName, java.sql.Blob x) throws SqlException {
        throw new SqlException(agent_.logWriter_, "JDBC 3 method called - not yet supported");
    }

    public void updateClob(int columnIndex, java.sql.Clob x) throws SqlException {
        throw new SqlException(agent_.logWriter_, "JDBC 3 method called - not yet supported");
    }

    public void updateClob(String columnName, java.sql.Clob x) throws SqlException {
        throw new SqlException(agent_.logWriter_, "JDBC 3 method called - not yet supported");
    }

    public void updateArray(int columnIndex, java.sql.Array x) throws SqlException {
        throw new SqlException(agent_.logWriter_, "JDBC 3 method called - not yet supported");
    }

    public void updateArray(String columnName, java.sql.Array x) throws SqlException {
        throw new SqlException(agent_.logWriter_, "JDBC 3 method called - not yet supported");
    }

    public boolean repositionScrollableResultSetBeforeJDBC1PositionedUpdateDelete() throws SqlException {
        boolean repositionedCursor = false;

        // calculate the absolutePosition of the current row directly.
        long rowToFetch = getRowUncast() - absolutePosition_;

        // if rowToFetch is zero, already positioned on the current row
        if (rowToFetch != 0 || cursorUnpositionedOnServer_) {
            writePositioningFetch_((generatedSection_ == null) ? statement_.section_ : generatedSection_,
                    scrollOrientation_relative__,
                    rowToFetch);
            // adjust the absolute position on the client
            absolutePosition_ += rowToFetch;
            repositionedCursor = true;
        }
        return repositionedCursor;
    }
    //--------------------categorize the methods below -----------------

    public void flowPositioningFetch(int scrollOrientation,
                                     int rowToFetch) throws DisconnectException {
        // need the try-catch block here because agent_.beginWriteChain throws
        // an SqlException
        try {
            agent_.beginWriteChain(statement_);

            writePositioningFetch_((generatedSection_ == null) ? statement_.section_ : generatedSection_,
                    scrollOrientation,
                    rowToFetch);

            agent_.flow(statement_);
            readPositioningFetch_();
            agent_.endReadChain();
        } catch (SqlException e) {
            throw new DisconnectException(agent_, e);
        }
    }

    protected void positionToCurrentRowAndUpdate() throws SqlException {
        agent_.beginWriteChain(statement_);

        // calculate the position of the current row relative to the absolute position on server
        long currentRowPosRelativeToAbsoluteRowPos = getRowUncast() - absolutePosition_;

        // if currentRowPosRelativeToAbsoluteRowPos is zero, already on the current row
        // reposition only if a commit has been sent
        // do not reposition forward-only cursors
        if (resultSetType_ != java.sql.ResultSet.TYPE_FORWARD_ONLY &&
                (currentRowPosRelativeToAbsoluteRowPos != 0 ||
                (currentRowPosRelativeToAbsoluteRowPos == 0 && cursorUnpositionedOnServer_))) {
            writePositioningFetch_((generatedSection_ == null) ? statement_.section_ : generatedSection_,
                    scrollOrientation_relative__,
                    currentRowPosRelativeToAbsoluteRowPos);
        }

        // re-prepare the update statement if repreparing is needed after a commit.
        if (!preparedStatementForUpdate_.openOnServer_) {
            preparedStatementForUpdate_.materialPreparedStatement_.writePrepare_(preparedStatementForUpdate_.sql_,
                    preparedStatementForUpdate_.section_);
        }

        boolean chainAutoCommit = connection_.willAutoCommitGenerateFlow();
        writeUpdateRow(chainAutoCommit);
        if (chainAutoCommit) {
            connection_.writeCommit();
        }

        agent_.flow(statement_);

        // adjust the absolute position on the client
        absolutePosition_ += currentRowPosRelativeToAbsoluteRowPos;

        if (resultSetType_ != java.sql.ResultSet.TYPE_FORWARD_ONLY &&
                (currentRowPosRelativeToAbsoluteRowPos != 0 ||
                (currentRowPosRelativeToAbsoluteRowPos == 0 && cursorUnpositionedOnServer_))) {
            readPositioningFetch_();
            cursorUnpositionedOnServer_ = false;
            listenToUnitOfWork();
        }

        // read prepare replies if the update statement is re-prepared after a commit.
        if (!preparedStatementForUpdate_.openOnServer_) {
            preparedStatementForUpdate_.materialPreparedStatement_.readPrepare_();
        }
        readUpdateRow();

        if (chainAutoCommit) {
            connection_.readCommit();
        }
        agent_.endReadChain();
    }

    protected void update() throws SqlException {
        agent_.beginWriteChain(statement_);

        // re-prepare the update statement if repreparing is needed after a commit.
        if (!preparedStatementForUpdate_.openOnServer_) {
            preparedStatementForUpdate_.materialPreparedStatement_.writePrepare_(preparedStatementForUpdate_.sql_,
                    preparedStatementForUpdate_.section_);
        }

        if (isRowsetCursor_) {
            preparedStatementForUpdate_.setInt(updatedColumns_.length + 1, (int) (currentRowInRowset_ + 1));
        }

        boolean chainAutoCommit = connection_.willAutoCommitGenerateFlow();
        writeUpdateRow(chainAutoCommit);
        if (chainAutoCommit) {
            connection_.writeCommit();
        }

        agent_.flow(statement_);

        // read prepare replies if the update statement is re-prepared after a commit.
        if (!preparedStatementForUpdate_.openOnServer_) {
            preparedStatementForUpdate_.materialPreparedStatement_.readPrepare_();
        }

        readUpdateRow();

        if (chainAutoCommit) {
            connection_.readCommit();
        }
        agent_.endReadChain();
    }

    protected void positionToCurrentRowAndDelete() throws SqlException {
        agent_.beginWriteChain(statement_);

        // calculate the position of the current row relative to the absolute position on server
        long currentRowPosRelativeToAbsoluteRowPos = getRowUncast() - absolutePosition_;

        // if rowToFetch is zero, already positioned on the current row
        // do not reposition forward-only cursors.
        if (resultSetType_ != java.sql.ResultSet.TYPE_FORWARD_ONLY &&
                (currentRowPosRelativeToAbsoluteRowPos != 0 ||
                (currentRowPosRelativeToAbsoluteRowPos == 0 && cursorUnpositionedOnServer_))) {
            writePositioningFetch_((generatedSection_ == null) ? statement_.section_ : generatedSection_,
                    scrollOrientation_relative__,
                    currentRowPosRelativeToAbsoluteRowPos);
        }

        // re-prepare the update statement if repreparing is needed after a commit.
        if (!preparedStatementForDelete_.openOnServer_) {
            preparedStatementForDelete_.materialPreparedStatement_.writePrepare_(preparedStatementForDelete_.sql_,
                    preparedStatementForDelete_.section_);
        }

        writeDeleteRow();
        if (connection_.autoCommit_) {
            connection_.writeAutoCommit();
        }

        agent_.flow(statement_);

        // adjust the absolute position on the client.
        absolutePosition_ += currentRowPosRelativeToAbsoluteRowPos;

        if (resultSetType_ != java.sql.ResultSet.TYPE_FORWARD_ONLY &&
                (currentRowPosRelativeToAbsoluteRowPos != 0 ||
                (currentRowPosRelativeToAbsoluteRowPos == 0 && cursorUnpositionedOnServer_))) {
            readPositioningFetch_();
            cursorUnpositionedOnServer_ = false;
            listenToUnitOfWork();
        }

        // read prepare replies if the update statement is re-prepared after a commit.
        if (!preparedStatementForDelete_.openOnServer_) {
            preparedStatementForDelete_.materialPreparedStatement_.readPrepare_();
        }
        readDeleteRow();
        if (connection_.autoCommit_) {
            connection_.readAutoCommit();
        }
        agent_.endReadChain();
    }

    protected void delete() throws SqlException {
        agent_.beginWriteChain(statement_);

        // re-prepare the update statement if repreparing is needed after a commit.
        if (!preparedStatementForDelete_.openOnServer_) {
            preparedStatementForDelete_.materialPreparedStatement_.writePrepare_(preparedStatementForDelete_.sql_,
                    preparedStatementForDelete_.section_);
        }

        if (isRowsetCursor_) {
            preparedStatementForDelete_.setInt(1, (int) (currentRowInRowset_ + 1));
        }

        writeDeleteRow();

        if (connection_.autoCommit_) {
            connection_.writeAutoCommit();
        }

        agent_.flow(statement_);

        // read prepare replies if the update statement is re-prepared after a commit.
        if (!preparedStatementForDelete_.openOnServer_) {
            preparedStatementForDelete_.materialPreparedStatement_.readPrepare_();
        }
        readDeleteRow();
        if (connection_.autoCommit_) {
            connection_.readAutoCommit();
        }
        agent_.endReadChain();
    }

    // Resets all rowset related flags.
    // Called by getRowSet() from material layer.
    public void setRowsetAfterLastEvent() throws SqlException {
        firstRowInRowset_ = 0;
        lastRowInRowset_ = 0;
        absolutePosition_ = rowCount_ + 1;
        currentRowInRowset_ = 0;
        rowsReceivedInCurrentRowset_ = 0;
    }

    public void setRowsetBeforeFirstEvent() throws SqlException {
        firstRowInRowset_ = 0;
        lastRowInRowset_ = 0;
        absolutePosition_ = 0;
        currentRowInRowset_ = -1;
        rowsReceivedInCurrentRowset_ = 0;
    }

    public void setRowsetNoRowsEvent() {
        rowCount_ = 0;
        firstRowInRowset_ = 0;
        lastRowInRowset_ = 0;
        absolutePosition_ = 0;
        currentRowInRowset_ = -1;
        rowsReceivedInCurrentRowset_ = 0;
    }

    private boolean isServersCursorPositionBeforeFirst() throws SqlException {
        return (isBeforeFirstX() && firstRowInRowset_ == 0 && lastRowInRowset_ == 0 && absolutePosition_ == 0);
    }

    private boolean isServerCursorPositionAfterLast() throws SqlException {
        return (absolutePosition_ == (rowCount_ + 1));
    }

    public void setValidCursorPosition(boolean isValidCursorPosition) {
        isValidCursorPosition_ = isValidCursorPosition;
    }

    protected void moveToAfterLast() throws DisconnectException {
        flowPositioningFetch(ResultSet.scrollOrientation_after__, 0);
    }

    // Positions the cursor at before the first row.
    protected void moveToBeforeFirst() throws DisconnectException {
        flowPositioningFetch(ResultSet.scrollOrientation_before__, 0);
    }

    // analyze the error handling here, and whether or not can be pushed to common
    // can we make this the common layer fetch method
    // Called by the read/skip Fdoca bytes methods in the net
    // whenever data reads exhaust the internal buffer used by this reply
    public void flowFetch() throws DisconnectException, SqlException {
        agent_.beginWriteChain(statement_);
        writeFetch_((generatedSection_ == null) ? statement_.section_ : generatedSection_);
        agent_.flow(statement_);
        readFetch_();
        agent_.endReadChain();
    }

    public void writeUpdateRow(boolean chainedWritesFollowingSetLob) throws SqlException {
        preparedStatementForUpdate_.materialPreparedStatement_.writeExecute_(preparedStatementForUpdate_.section_,
                preparedStatementForUpdate_.parameterMetaData_,
                preparedStatementForUpdate_.parameters_,
                preparedStatementForUpdate_.parameterMetaData_.getColumnCount(),
                false, // false means we're not expecting output
                chainedWritesFollowingSetLob);  // chaining after the execute
    }

    public void writeDeleteRow() throws SqlException {
        if (isRowsetCursor_) {
            preparedStatementForDelete_.materialPreparedStatement_.writeExecute_(preparedStatementForDelete_.section_,
                    preparedStatementForDelete_.parameterMetaData_,
                    preparedStatementForDelete_.parameters_,
                    preparedStatementForDelete_.parameterMetaData_.getColumnCount(),
                    false, // false means we're not expecting output
                    false);  // false means we don't chain anything after the execute
        } else {
            preparedStatementForDelete_.materialPreparedStatement_.writeExecute_(preparedStatementForDelete_.section_,
                    null, // do not need parameterMetaData since there is no input
                    null, // no inputs
                    0, // number of input columns is 0 for positioned delete
                    false, // false means we're not expecting output
                    false);  // false means we don't chain anything after the execute
        }
    }

    public void readUpdateRow() throws DisconnectException, SqlException {
        preparedStatementForUpdate_.materialPreparedStatement_.readExecute_();
    }

    public void readDeleteRow() throws DisconnectException, SqlException {
        preparedStatementForDelete_.materialPreparedStatement_.readExecute_();
    }

    //------------------material layer event callback methods-----------------------

    boolean listenToUnitOfWork_ = false;

    public void listenToUnitOfWork() {
        if (!listenToUnitOfWork_) {
            listenToUnitOfWork_ = true;
            connection_.CommitAndRollbackListeners_.add(this);
        }
    }

    public void completeLocalCommit(java.util.Iterator listenerIterator) {
        cursorUnpositionedOnServer_ = true;
        markAutoCommitted();
        if (!cursorHold_) {
            // only non-held cursors need to be closed at commit
            markClosed();
            nullOutReferenceInStatement();
            // remove from listener list
            listenerIterator.remove();
            listenToUnitOfWork_ = false;
        }
    }

    public void completeLocalRollback(java.util.Iterator listenerIterator) {
        markAutoCommitted();
        // all cursors