All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.sqlserver.jdbc.SQLServerResultSet Maven / Gradle / Ivy

Go to download

Microsoft JDBC 4.2 Driver for SQL Server. The Azure Key Vault feature in Microsoft JDBC Driver for SQL Server depends on Azure SDK for JAVA and Azure Active Directory Library For Java.

There is a newer version: 12.8.1.jre11
Show newest version
//---------------------------------------------------------------------------------------------------------------------------------
// File: SQLServerResultSet.java
//
//
// Microsoft JDBC Driver for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), 
//  to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//  and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
//  IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
 
 
package com.microsoft.sqlserver.jdbc;

import java.io.*;
import java.math.*;
import java.sql.*;
import java.util.*;
import java.util.logging.*;
import java.text.*;


/**
 * Indicates the type of the row received from the server
 */
enum RowType
{
	ROW,
	NBCROW,
	UNKNOWN,
}
/**
 * Top-level JDBC ResultSet implementation
 */
public class SQLServerResultSet implements ISQLServerResultSet
{

   /** Generate the statement's logging ID */
   private static int lastResultSetID = 0;
   private final String traceID;
   private synchronized static int nextResultSetID() { return ++lastResultSetID; }
   final static java.util.logging.Logger logger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerResultSet");
   public String toString() { return traceID; }
   String logCursorState() { return " currentRow:" + currentRow + " numFetchedRows:" + numFetchedRows + " rowCount:" + rowCount; }
   protected static final java.util.logging.Logger loggerExternal =
      java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.ResultSet");

    final private String loggingClassName ;
    String getClassNameLogging()
        {
            return loggingClassName;
        }


   /** the statement that generated this result set*/
   private final SQLServerStatement stmt;

   /** max rows to return from this result set */
   private final int maxRows;

   /** the meta data for this result set */
   private ResultSetMetaData metaData;

   /** is the result set close */
   private boolean isClosed = false;

   private final int serverCursorId;

   /** the intended fetch direction to optimize cursor performance */
   private int fetchDirection;

   /** the desired fetch size to optimize cursor performance */
   private int fetchSize;

   /** true if the cursor is positioned on the insert row*/
   private boolean isOnInsertRow = false;

    /** true if the last value read was SQL NULL */
    private boolean lastValueWasNull = false;

    /** The index (1-based) of the last column in the current row that has been marked for reading */
    private int lastColumnIndex;

    //Indicates if the null bit map is loaded for the current row 
    //in the resultset
    private boolean areNullCompressedColumnsInitialized = false;
    
    //Indicates the type of the current row in the result set  
    private RowType resultSetCurrentRowType = RowType.UNKNOWN;
        
    //getter for resultSetCurrentRowType
    final RowType getCurrentRowType() 
    { 
    	return resultSetCurrentRowType; 
    }
    
   //setter for resultSetCurrentRowType    
    final void setCurrentRowType(RowType rowType) 
    { 
    	resultSetCurrentRowType = rowType; 
    }

    
    /** Currently active Stream Note only one stream can be active at a time, JDBC spec calls for the streams to be closed when a 
    column or row move occurs */
    private Closeable activeStream;
    
    /**
     * A window of fetchSize quickly accessible rows for scrollable result sets
     */
    private final ScrollWindow scrollWindow;

    /**
     * Current row, which is either the actual (1-based) value or one
     * of the special values defined below.
     */
    private static final int BEFORE_FIRST_ROW = 0;
    private static final int AFTER_LAST_ROW   = -1;
    private static final int UNKNOWN_ROW      = -2;
    private int currentRow = BEFORE_FIRST_ROW;

    /** Flag set to true if the current row was updated through this ResultSet object */
    private boolean updatedCurrentRow = false;
    final boolean getUpdatedCurrentRow() { return updatedCurrentRow; }
    final void setUpdatedCurrentRow(boolean rowUpdated) { updatedCurrentRow = rowUpdated; }

    /** Flag set to true if the current row was deleted through this ResultSet object */
    private boolean deletedCurrentRow = false;
    final boolean getDeletedCurrentRow() { return deletedCurrentRow; }
    final void setDeletedCurrentRow(boolean rowDeleted) { deletedCurrentRow = rowDeleted; }

    /**
     * Count of rows in this result set.
     *
     * The number of rows in the result set may be known when this ResultSet object is
     * created, after the first full traversal of the result set, or possibly never
     * (as is the case with DYNAMIC cursors).
     */
    static final int UNKNOWN_ROW_COUNT = -3;
    private int rowCount;

    /** The current row's column values */
    private final Column[] columns;

    // The CekTable retrieved from the COLMETADATA token for this resultset.
    private CekTable cekTable = null;
    
    /* Gets the CekTable */
    CekTable getCekTable()
    {
    	return cekTable;
    }
    
   
   final void setColumnName(int index, String name)
   {
     columns[index-1].setColumnName(name);
   }

    /**
     * Skips columns between the last marked column and the target column, inclusive,
     * optionally discarding their values as they are skipped.
     */
    private final void skipColumns(int columnsToSkip, boolean discardValues) throws SQLServerException
    {
        assert lastColumnIndex >= 1;
        assert 0 <= columnsToSkip && columnsToSkip <= columns.length;
    
        for (int columnsSkipped = 0; columnsSkipped < columnsToSkip; ++columnsSkipped)
        {
            Column column = getColumn(lastColumnIndex++);
            column.skipValue(tdsReader, discardValues && isForwardOnly());
            if (discardValues)
                column.clear();
        }
    }


   /** TDS reader from which row values are read */
   private TDSReader tdsReader;

    private final FetchBuffer fetchBuffer;

    /**
     * Make a new result set
     * @param stmtIn the generating statement
     */
    SQLServerResultSet(SQLServerStatement stmtIn) throws SQLServerException
    {
        int resultSetID = nextResultSetID();
        loggingClassName =  "com.microsoft.sqlserver.jdbc.SQLServerResultSet"  + ":"  + resultSetID;
        traceID = "SQLServerResultSet:" + resultSetID; 

        // Common initializer class for server-cursored and client-cursored ResultSets.
        // The common initializer builds columns from the column metadata and other table
        // info when present.  Specialized subclasses take care of behavior that is specific
        // to either server-cursored or client-cursored ResultSets.
        abstract class CursorInitializer extends TDSTokenHandler
        {
            abstract int getRowCount();
            abstract int getServerCursorId();

            private StreamColumns columnMetaData = null;
            private StreamColInfo colInfo = null;
            private StreamTabName tabName = null;
            final Column[] buildColumns() throws SQLServerException
            {
                return columnMetaData.buildColumns(colInfo, tabName);
            }

            CursorInitializer(String name)
            {
                super(name);
            }

            boolean onColInfo(TDSReader tdsReader) throws SQLServerException
            {
                colInfo = new StreamColInfo();
                colInfo.setFromTDS(tdsReader);
                return true;
            }

            boolean onTabName(TDSReader tdsReader) throws SQLServerException
            {
                tabName = new StreamTabName();
                tabName.setFromTDS(tdsReader);
                return true;
            }

            boolean onColMetaData(TDSReader tdsReader) throws SQLServerException
            {
                columnMetaData = new StreamColumns(Util.shouldHonorAEForRead(stmt.stmtColumnEncriptionSetting, stmt.connection));            	
                columnMetaData.setFromTDS(tdsReader);
                cekTable = columnMetaData.getCekTable();
                return true;
            }
        }

        // Server-cursor initializer expects a cursorID and row count to be
        // returned in OUT parameters from the sp_cursor[prep]exec call.
        // There should not be any rows present when initializing a server-cursored
        // ResultSet (until/unless support for cursor auto-fetch is implemented).
        final class ServerCursorInitializer extends CursorInitializer
        {
            private final SQLServerStatement stmt;
            final int getRowCount() { return stmt.getServerCursorRowCount(); }
            final int getServerCursorId() { return stmt.getServerCursorId(); }

            ServerCursorInitializer(SQLServerStatement stmt)
            {
                super("ServerCursorInitializer");
                this.stmt = stmt;
            }

            boolean onRetStatus(TDSReader tdsReader) throws SQLServerException
            {
                // With server-cursored result sets, the column metadata is
                // followed by a return status and cursor-related OUT parameters
                // for the sp_cursor[prep]exec call.  Two of those OUT parameters
                // are the cursor ID and row count needed to construct this
                // ResultSet.
                stmt.consumeExecOutParam(tdsReader);
                return true;
            }

            boolean onRetValue(TDSReader tdsReader) throws SQLServerException
            {
                // The first OUT parameter after the sp_cursor[prep]exec OUT parameters
                // is the start of the application OUT parameters.  Leave parsing
                // of them up to CallableStatement OUT param handlers.
                return false;
            }
        }

        // Client-cursor initializer expects 0 or more rows or a row-level error
        // to follow the column metadata.
        final class ClientCursorInitializer extends CursorInitializer
        {
            private int rowCount = UNKNOWN_ROW_COUNT;
            final int getRowCount() { return rowCount; }
            final int getServerCursorId() { return 0; }

            ClientCursorInitializer()
            {
                super("ClientCursorInitializer");
            }

            boolean onRow(TDSReader tdsReader) throws SQLServerException
            {
                // A ROW token indicates the start of the fetch buffer
                return false;
            }

            boolean onNBCRow(TDSReader tdsReader) throws SQLServerException
            {
                // A NBCROW token indicates the start of the fetch buffer
                return false;
            }

            boolean onError(TDSReader tdsReader) throws SQLServerException
            {
                // An ERROR token indicates a row error in lieu of a row.
                // In this case, the row error is in lieu of the first row.
                // Stop parsing and let the fetch buffer handle the error.
                rowCount = 0;
                return false;
            }

            boolean onDone(TDSReader tdsReader) throws SQLServerException
            {
                // When initializing client-cursored ResultSets, a DONE token
                // following the column metadata indicates an empty result set.
                rowCount = 0;
                return false;
            }
        }

        this.stmt = stmtIn;
        this.maxRows = stmtIn.maxRows;
        this.fetchSize = stmtIn.nFetchSize;
        this.fetchDirection = stmtIn.nFetchDirection;

        CursorInitializer initializer =
            stmtIn.executedSqlDirectly ?
                (new ClientCursorInitializer()) :
                (new ServerCursorInitializer(stmtIn));

        TDSParser.parse(stmtIn.resultsReader(), initializer);
        this.columns = initializer.buildColumns();
        this.rowCount = initializer.getRowCount();
        this.serverCursorId = initializer.getServerCursorId();

        // If this result set does not use a server cursor, then the result set rows
        // (if any) are already present in the fetch buffer at which the statement's
        // TDSReader now points.
        //
        // If this result set uses a server cursor, then without support for server
        // cursor autofetch, there are initially no rows with which to populate the
        // fetch buffer.  The app will have to do a server cursor fetch first.
        this.tdsReader = (0 == serverCursorId) ? stmtIn.resultsReader() : null;

        this.fetchBuffer = new FetchBuffer();

        this.scrollWindow = isForwardOnly() ? null : new ScrollWindow(fetchSize);
        this.numFetchedRows = 0;

        // increment opened resultset counter
        stmtIn.incrResultSetCount();
        
        if(logger.isLoggable(java.util.logging.Level.FINE))
        {
            logger.fine(toString() + " created by (" + stmt.toString() + ")");
        }
    }

    public boolean isWrapperFor(Class iface) throws SQLException
    {
        loggerExternal.entering(getClassNameLogging(),  "isWrapperFor");
        DriverJDBCVersion.checkSupportsJDBC4();
        boolean f =  iface.isInstance(this);
        loggerExternal.exiting(getClassNameLogging(),  "isWrapperFor", Boolean.valueOf(f));
        return f;
    }

    public  T unwrap(Class iface) throws SQLException
    {
        loggerExternal.entering(getClassNameLogging(),  "unwrap");
        DriverJDBCVersion.checkSupportsJDBC4();
        T t;
        try
        {
            t = iface.cast(this);
        }
        catch (ClassCastException e)
        {
            throw new SQLServerException(e.getMessage(), e);
        }
        loggerExternal.exiting(getClassNameLogging(),  "unwrap", t);
        return t;
    }


    private SQLServerException rowErrorException = null;

   /**
    * Check if the result set is closed
    * @throws SQLServerException
    */
   /*L0*/ void checkClosed() throws SQLServerException {

      if (isClosed) {
        SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_resultsetClosed"), null, false);
      }

      stmt.checkClosed();

      // This ResultSet isn't closed, but also check whether it's effectively dead
      // due to a row error.  Once a ResultSet encounters a row error, nothing more
      // can be done with it other than closing it.
      if (null != rowErrorException)
          throw rowErrorException;
   }

    public boolean isClosed() throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();

        loggerExternal.entering(getClassNameLogging(), "isClosed");
        boolean result = isClosed || stmt.isClosed();
        loggerExternal.exiting(getClassNameLogging(), "isClosed", result);
        return result;
    }

    /**
     * Called by ResultSet API methods to disallow method use on
     * forward only result sets.
     *
     * @throws SQLServerException if the result set is forward only.
     */
    private final void throwNotScrollable() throws SQLServerException
    {
        SQLServerException.makeFromDriverError(
            stmt.connection,
            this,
            SQLServerException.getErrString("R_requestedOpNotSupportedOnForward"),
            null,
            true);
    }

    private final boolean isForwardOnly()
    {
        return
            TYPE_SS_DIRECT_FORWARD_ONLY == stmt.getSQLResultSetType() ||
            TYPE_SS_SERVER_CURSOR_FORWARD_ONLY == stmt.getSQLResultSetType();
    }

    private final boolean isDynamic()
    {
        return 0 != serverCursorId && TDS.SCROLLOPT_DYNAMIC == stmt.getCursorType();
    }

    private final void verifyResultSetIsScrollable() throws SQLServerException
    {
        if (isForwardOnly())
            throwNotScrollable();
    }
 
    /**
     * Called by ResultSet API methods to disallow method use on
     * read only result sets.
     *
     * @throws SQLServerException if the result set is read only.
     */
    private final void throwNotUpdatable() throws SQLServerException
    {
        SQLServerException.makeFromDriverError(
            stmt.connection,
            this,
            SQLServerException.getErrString("R_resultsetNotUpdatable"),
            null,
            true);
    }

    private final void verifyResultSetIsUpdatable() throws SQLServerException
    {
        if (CONCUR_READ_ONLY == stmt.resultSetConcurrency || 0 == serverCursorId)
            throwNotUpdatable();
    }

    /**
     * Checks whether the result set has a current row.
     *
     * @return true if there is a current row
     * @return false if the result set is positioned before the first row or after the last row.
     */
    private boolean hasCurrentRow()
    {
        return
            BEFORE_FIRST_ROW != currentRow &&
            AFTER_LAST_ROW != currentRow;
    }

    /**
     * Verifies whether this result set has a current row.
     *
     * This check DOES NOT consider whether the cursor is on the insert row.
     * The result set may or may not have a current row regardless whether
     * the cursor is on the insert row.  Consider the following scenarios:
     *
     * beforeFirst(); moveToInsertRow(); relative(1);
     * No current row to move relative to.  Throw "no current row" exception.
     *
     * first(); moveToInsertRow(); relative(1);
     * Call to relative moves off of the insert row one row past the current
     * row.  That is, the cursor ends up on the second row of the result set.
     *
     * @throws SQLServerException if the result set has no current row
     */
    private void verifyResultSetHasCurrentRow() throws SQLServerException
    {
        if (!hasCurrentRow())
        {
            SQLServerException.makeFromDriverError(
                stmt.connection,
                stmt,
                SQLServerException.getErrString("R_resultsetNoCurrentRow"),
                null,
                true);
        }
    }

    /**
     * Called by ResultSet API methods to disallow method use when
     * cursor is on a deleted row.
     *
     * @throws SQLServerException if the cursor is not on an updatable row.
     */
    private void verifyCurrentRowIsNotDeleted(String errResource) throws SQLServerException
    {
        if (currentRowDeleted())
        {
            SQLServerException.makeFromDriverError(
                stmt.connection,
                stmt,
                SQLServerException.getErrString(errResource),
                null,
                true);
        }
    }

  /**
   * Called by ResultSet API methods to disallow method use when
   * the column index is not in the range of columns returned in the results.
   *
   * @throws SQLServerException if the column index is out of bounds
   */
  private void verifyValidColumnIndex(int index) throws SQLServerException
  {
    int nCols = columns.length;

    // Rows that come back from server side cursors tack on a "hidden" ROWSTAT column
    // (used to detect deletes from a keyset) at the end of each row.  Don't include
    // that column in the list of valid columns.
    if (0 != serverCursorId)
      --nCols;

    if (index < 1  || index > nCols) 
    {
      MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_indexOutOfRange"));
      Object[] msgArgs = {new Integer(index)};
      SQLServerException.makeFromDriverError(stmt.connection, stmt,
        form.format(msgArgs), "07009", false);
    }
  }

 /**
  * Called by ResultSet API methods to disallow method use when
  * cursor is on the insert row.
  *
  * @throws SQLServerException if the cursor is on the insert row.
  */
   private void verifyResultSetIsNotOnInsertRow() throws SQLServerException
   {
     if (isOnInsertRow)
     {
       SQLServerException.makeFromDriverError(stmt.connection, stmt,
         SQLServerException.getErrString("R_mustNotBeOnInsertRow"), null, true);
     }
   }

    private final void throwUnsupportedCursorOp() throws SQLServerException
    {
        // Absolute positioning of dynamic cursors is unsupported.
        SQLServerException.makeFromDriverError(
            stmt.connection,
            this,
            SQLServerException.getErrString("R_unsupportedCursorOperation"),
            null,
            true);
    }

    /**
     * Close the result set.
     *
     * Note that the public close() method performs all of the cleanup work
     * through this internal method which cannot throw any exceptions.  This is
     * done deliberately to ensure that ALL of the object's client-side and
     * server-side state is cleaned up as best as possible, even under
     * conditions which would normally result in exceptions being thrown.
     */
    private void closeInternal()
    {
        // Calling close on a closed ResultSet is a no-op per JDBC spec
        if (isClosed)
            return;

        // Mark this ResultSet as closed, then clean up.
        isClosed = true;

        // Discard the current fetch buffer contents.
        discardFetchBuffer();

        // Close the server cursor if there is one.
        closeServerCursor();

        // Clean up client-side state
        metaData = null;
        
        // decrement opened resultset counter
        stmt.decrResultSetCount();
    }

    public void close() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "close"); 
        if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
        {
    		loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
        }
        closeInternal();
        loggerExternal.exiting(getClassNameLogging(), "close");
    }

    /**
     * Find a column index given a column name
     * @param columnName the name
     * @throws SQLServerException
     * @return the column index
     */
    public int findColumn(String columnName) throws SQLServerException
    {
            loggerExternal.entering(getClassNameLogging(),  "findColumn", columnName); 
		checkClosed();

		// In order to be as accurate as possible when locating column name
		// indexes, as well as be deterministic when running on various client 
		// locales, we search for column names using the following scheme:

		 // Per JDBC spec 27.1.5 "if there are multiple columns with the same name
		// [findColumn] will return the value of the first matching name".

		// 1. Search using case-sensitive non-locale specific (binary) compare first.
		// 2. Search using case-insensitive, non-locale specific (binary) compare last.

		// NOTE: Any attempt to use a locale aware comparison will fail because:
		//
		// 1. SQL allows any valid UNICODE characters in the column name.
		// 2. SQL does not store any locale info associated with the column name.
		// 3. We cannot second guess the developer and decide to use VM locale or 
		//    database default locale when making comparisons, this would produce
		//    inconsistent results on different clients or different servers.

		// Search using case-sensitive, non-locale specific (binary) compare.
		// If the user supplies a true match for the column name, we will find it here.
		int i;
		for (i=0; i>3) + 1;//equivalent of (int)Math.ceil(this.columns.length/8.0) and gives better perf
        	for(int byteNo = 0; byteNo< noOfBytes; byteNo++)
        	{
        		
        		int byteValue = tdsReader.readUnsignedByte();
        		
        		//if this byte is 0, skip to the next byte
        		//and increment the column number by 8(no of bits)
        		if(byteValue==0)
        		{
        			columnNo = columnNo + 8;
        			continue;
        		}
        		
        		for(int bitNo = 0; bitNo < 8 && columnNo < this.columns.length; bitNo++)
        		{        			
        			if((byteValue & (1< lastColumnIndex && (!this.columns[index-1].isInitialized()) )
            skipColumns(index - lastColumnIndex, false);

        // Then return the target column
        return getColumn(index);
    }

   /*L0*/ private void NotImplemented() throws SQLServerException   {
     SQLServerException.makeFromDriverError(stmt.connection, stmt, SQLServerException.getErrString("R_notSupported"), null, false);
   }


   /**
    * Clear result set warnings
    * @throws SQLServerException
    */
   /*L0*/ public void clearWarnings() throws SQLServerException 
   {
       loggerExternal.entering(getClassNameLogging(),  "clearWarnings"); 
       loggerExternal.exiting(getClassNameLogging(), "clearWarnings");
   }

   /* ----------------- JDBC API methods ------------------ */

    private void moverInit() throws SQLServerException
    {
        cancelInsert();
        cancelUpdates();
    }

    public boolean relative(int rows) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "relative", rows); 
    
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() +" rows:" + rows + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if (1) there is no curent row or (2)
        // the type of this ResultSet object is TYPE_FORWARD_ONLY.
        verifyResultSetIsScrollable();
        verifyResultSetHasCurrentRow();

        moverInit();
        moveRelative(rows);
        boolean value = hasCurrentRow();
         loggerExternal.exiting(getClassNameLogging(), "relative", value);
         return value;
    }

    private final void moveRelative(int rowsToMove) throws SQLServerException
    {
        // Relative moves must be from somewhere within the result set
        assert hasCurrentRow();

        // If rows is 0, the cursor's position does not change.
        if (0 == rowsToMove)
            return;

        if (rowsToMove > 0)
            moveForward(rowsToMove);
        else
            moveBackward(rowsToMove);
    }

    private final void moveForward(int rowsToMove) throws SQLServerException
    {
        assert hasCurrentRow();
        assert rowsToMove > 0;

        // If there's a chance that the move can happen just in the scroll window then try that first
        if (scrollWindow.getRow() + rowsToMove <= scrollWindow.getMaxRows())
        {
            int rowsMoved = 0;
            while (rowsToMove > 0 && scrollWindow.next(this))
            {
                ++rowsMoved;
                --rowsToMove;
            }

            // Update the current row
            updateCurrentRow(rowsMoved);

            // If the move happened entirely in the scroll window, then we're done.
            if (0 == rowsToMove)
                return;
        }

        // All or part of the move lies outside the scroll window.
        assert rowsToMove > 0;

        // For client-cursored result sets, where the fetch buffer contains all of the rows, moves outside of
        // the scroll window are done via an absolute in the fetch buffer.
        if (0 == serverCursorId)
        {
            assert UNKNOWN_ROW != currentRow;
            currentRow = clientMoveAbsolute(currentRow + rowsToMove);
            return;
        }

        // For server-cursored result sets (where the fetch buffer and scroll window are the same size),
        // moves outside the scroll window require fetching more rows from the server.
        //
        // A few words on fetching strategy with server cursors
        // There is an assumption here that moving past the current position is an indication
        // that the result set is being traversed in forward order, so it makes sense to grab a
        // block of fetchSize rows from the server, starting at the desired location, to maximize
        // the number of rows that can be consumed before the next server fetch.  That assumption
        // isn't necessarily true.
        if (1 == rowsToMove)
            doServerFetch(TDS.FETCH_NEXT, 0, fetchSize);
        else
            doServerFetch(TDS.FETCH_RELATIVE, rowsToMove + scrollWindow.getRow() - 1, fetchSize);

        // If the new fetch buffer returned no rows, then the cursor has reached the end of the result set.
        if (!scrollWindow.next(this))
        {
            currentRow = AFTER_LAST_ROW;
            return;
        }

        // The move succeeded, so update the current row.
        updateCurrentRow(rowsToMove);
    }

    private final void moveBackward(int rowsToMove) throws SQLServerException
    {
        assert hasCurrentRow();
        assert rowsToMove < 0;

        // If the move is contained in scroll window then handle it there.
        if (scrollWindow.getRow() + rowsToMove >= 1)
        {
            for (int rowsMoved = 0; rowsMoved > rowsToMove; --rowsMoved)
                scrollWindow.previous(this);

            updateCurrentRow(rowsToMove);
            return;
        }

        // The move lies outside the scroll window.

        // For client-cursored result sets, where the fetch buffer contains all of the rows, moves outside of
        // the scroll window are done via an absolute move in the fetch buffer.
        if (0 == serverCursorId)
        {
            assert UNKNOWN_ROW != currentRow;

            // Relative moves to before the first row must be handled here; a negative argument
            // to clientMoveAbsolute is interpreted as relative to the last row, not the first.
            if (currentRow + rowsToMove < 1)
            {
                moveBeforeFirst();
            }
            else
            {
                currentRow = clientMoveAbsolute(currentRow + rowsToMove);
            }

            return;
        }

        // For server-cursored result sets (where the fetch buffer and scroll window are the same size),
        // moves outside the scroll window require fetching more rows from the server.
        //
        // A few words on fetching strategy with server cursors
        // There is an assumption here that moving to the previous row is an indication
        // that the result set is being traversed in reverse order, so it makes sense to grab a
        // block of fetchSize rows from the server, ending with the desired location, to maximize
        // the number of rows that can be consumed before the next server fetch.  That assumption
        // isn't necessarily true.
        //
        // Also, when moving further back than the previous row, it is not generally feasible to
        // try to fetch a block of rows ending with the target row, since a move far enough back
        // that the start of the fetch buffer would be before the first row of the result set would
        // position the cursor before the first row and return no rows, even though the target row
        // may not be before the first row.  Instead, such moves are done so that the target row
        // is the first row in the returned block of rows rather than the last row.
        if (-1 == rowsToMove)
        {
            doServerFetch(TDS.FETCH_PREV_NOADJUST, 0, fetchSize);

            // If the new fetch buffer returned no rows, then the cursor has reached the start of the result set.
            if (!scrollWindow.next(this))
            {
                currentRow = BEFORE_FIRST_ROW;
                return;
            }

            // Scroll past the last of the returned rows, and ...
            while (scrollWindow.next(this))
                ;

            // back up one row.
            scrollWindow.previous(this);
        }
        else
        {
            doServerFetch(TDS.FETCH_RELATIVE, rowsToMove + scrollWindow.getRow() - 1, fetchSize);

            // If the new fetch buffer returned no rows, then the cursor has reached the start of the result set.
            if (!scrollWindow.next(this))
            {
                currentRow = BEFORE_FIRST_ROW;
                return;
            }
        }

        // The move succeeded, so update the current row.
        updateCurrentRow(rowsToMove);
    }

    /**
     * Update the current row's position if known.
     *
     * If known, the current row is assumed to be at a valid position somewhere in the ResultSet.
     * That is, the current row is not before the first row or after the last row.
     */
    private final void updateCurrentRow(int rowsToMove)
    {
        if (UNKNOWN_ROW != currentRow)
        {
            assert currentRow >= 1;
            currentRow += rowsToMove;
            assert currentRow >= 1;
        }
    }

    /**
     * Initially moves the cursor to the first row of this ResultSet object, with
     * subsequent calls moving the cursor to the second row, the third row, and so on.
     *
     * @return false when there are no more rows to read
     * @return true otherwise
     */
    public boolean next() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "next"); 
        if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
        {
    		loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
        }
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        moverInit();
        
        // If the cursor is already positioned after the last row in this result set
        // then it can't move any farther forward.
        if (AFTER_LAST_ROW == currentRow)
        {
             loggerExternal.exiting(getClassNameLogging(), "next", false);
            return false;
        }

        // For scrollable cursors, next() is just a special case of relative()
        if (!isForwardOnly())
        {
            if (BEFORE_FIRST_ROW == currentRow)
                moveFirst();
            else
                moveForward(1);
            boolean value = hasCurrentRow();
             loggerExternal.exiting(getClassNameLogging(), "next",value);
             return value;
        }

        // Fast path for forward only cursors...

        // Server forward only cursors do not honor SET ROWCOUNT,
        // so enforce any maxRows limit here.
        if (0 != serverCursorId && maxRows > 0)
        {
            if (currentRow == maxRows)
            {
                currentRow = AFTER_LAST_ROW;
                 loggerExternal.exiting(getClassNameLogging(), "next", false);
                return false;
            }
        }

        // There is no scroll window for forward only cursors,
        // so try to get the next row directly from the fetch buffer.
        if (fetchBufferNext())
        {
            // Update the current row.
            // Note that if the position was before the first row, the current
            // row should be updated to row 1.
            if (BEFORE_FIRST_ROW == currentRow)
                currentRow = 1;
            else
                updateCurrentRow(1);

            // We should never be asked to read more rows than maxRows.
            // Server forward only is handled above, and maxRows should
            // be enforced by the server for DIRECT forward only cursors.
            assert 0 == maxRows || currentRow <= maxRows;
             loggerExternal.exiting(getClassNameLogging(), "next", true);
            // Return that a row was read.
            return true;
        }

        // We're out of rows in the fetch buffer.  If this is a server
        // cursor, then try to load up the fetch buffer with the next
        // set of fetchSize rows.
        if (0 != serverCursorId)
        {
            doServerFetch(TDS.FETCH_NEXT, 0, fetchSize);

            // If there are rows in the freshly-loaded fetch buffer
            // then return the first of them.
            if (fetchBufferNext())
            {
                if (BEFORE_FIRST_ROW == currentRow)
                    currentRow = 1;
                else
                    updateCurrentRow(1);

                assert 0 == maxRows || currentRow <= maxRows;
                 loggerExternal.exiting(getClassNameLogging(), "next", true);
                return true;
            }
        }

        // Otherwise, we have reached the end of the result set
        if (UNKNOWN_ROW_COUNT == rowCount)
            rowCount = currentRow;

        currentRow = AFTER_LAST_ROW;
         loggerExternal.exiting(getClassNameLogging(), "next", false);
        return false;
    }

    public boolean wasNull() throws SQLServerException 
    {
        loggerExternal.entering(getClassNameLogging(),  "wasNull"); 
        checkClosed();
         loggerExternal.exiting(getClassNameLogging(), "wasNull", lastValueWasNull);
        return lastValueWasNull;
    }

    /**
     * @return true if the cursor is before the first row in this result set
     * @return false otherwise or if thie result set contains no rows.
     */
    public boolean isBeforeFirst() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "isBeforeFirst"); 
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the type of this ResultSet object is TYPE_FORWARD_ONLY.
        //
        // We deviate from JDBC spec here and allow this call on scrollable result sets.
        // Other drivers do the same.  Hibernate requires this behavior.
        // verifyResultSetIsScrollable();

        if (0 != serverCursorId)
        {
            switch (stmt.getCursorType())
            {
                case TDS.SCROLLOPT_FORWARD_ONLY:
                    throwNotScrollable();
                    break;

                case TDS.SCROLLOPT_DYNAMIC:
                    throwUnsupportedCursorOp();
                    break;

                case TDS.SCROLLOPT_FAST_FORWARD:
                    throwNotScrollable();
                    break;

                // All other types (KEYSET, STATIC) return a row count up front
    			default:
    				break;
            }
        }

        if (isOnInsertRow)
            return false;

        // If the cursor is not positioned before the first row in this result set
        // then the answer is obvious:
        if (BEFORE_FIRST_ROW != currentRow)
            return false;

        // If the cursor is positioned before the first row in this result set then
        // isBeforeFirst returns true only if the result set is also not empty.

        // For client-cursored result sets, determining whether the result set is empty
        // is just a matter of checking whether there are rows in the fetch buffer.
        if (0 == serverCursorId)
            return fetchBufferHasRows();

        // For server-cursored result sets, the row count tells whether the result set
        // is empty.  Assumption: server cursors that do not provide a row count (e.g. DYNAMIC)
        // are handled above.
        assert rowCount >= 0;
        boolean value = rowCount > 0;
         loggerExternal.exiting(getClassNameLogging(), "isBeforeFirst", value);
         return value;
    }

    public boolean isAfterLast() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "isAfterLast"); 
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the type of this ResultSet object is TYPE_FORWARD_ONLY.
        //
        // We deviate from JDBC spec here and allow this call on forward only client-cursored
        // result sets.  Other drivers do the same.  Hibernate requires this behavior.
        if (0 != serverCursorId)
        {
            verifyResultSetIsScrollable();

            // Scrollable DYNAMIC cursors do not support isAfterLast() since they
            // don't provide a row count and cannot distinguish an empty fetch
            // buffer from an empty result set.
            if (TDS.SCROLLOPT_DYNAMIC == stmt.getCursorType() && !isForwardOnly())
                throwUnsupportedCursorOp();
        }

        if (isOnInsertRow)
            return false;

        // By the time the cursor is positioned after the last row of the result set,
        // the count of rows must be known.
        assert !(AFTER_LAST_ROW == currentRow && UNKNOWN_ROW_COUNT == rowCount);

        boolean value = AFTER_LAST_ROW == currentRow && rowCount > 0;
        loggerExternal.exiting(getClassNameLogging(), "isAfterLast", value);
        return value;
    }

    /**
     * Determines whether the cursor is on the first row in this ResultSet object.
     *
     * This method should be called only on ResultSet objects that are scrollable:
     *   TYPE_SCROLL_SENSITIVE,
     *   TYPE_SCROLL_INSENSITIVE,
     *   TYPE_SS_SCROLL_STATIC,
     *   TYPE_SS_SCROLL_KEYSET,
     *   TYPE_SS_SCROLL_DYNAMIC.
     *
     * @return true if the cursor is on the first row in this result set
     * @return false otherwise
     */
    public boolean isFirst() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "isFirst"); 
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the type of this ResultSet object is TYPE_FORWARD_ONLY.
        verifyResultSetIsScrollable();

        // DYNAMIC cursors do not support isFirst().  There is no way to determine absolute
        // position within the result set with a DYNAMIC cursor.
        if (isDynamic())
            throwUnsupportedCursorOp();

        if (isOnInsertRow)
            return false;

        // At this point we must have a cursor that is scrollable and non-DYNAMIC.
        // That is, we have a cursor that has a notion of absolute position.
        assert UNKNOWN_ROW != currentRow;

        // Just return whether that absolution position is the first row.
        boolean value = 1 == currentRow;
        loggerExternal.exiting(getClassNameLogging(), "isFirst", value);
        return value;
    }

    /**
     * Determines whether the cursor is on the last row in this ResultSet object.
     *
     * This method should be called only on ResultSet objects that are scrollable:
     *   TYPE_SCROLL_SENSITIVE,
     *   TYPE_SCROLL_INSENSITIVE,
     *   TYPE_SS_SCROLL_STATIC,
     *   TYPE_SS_SCROLL_KEYSET,
     *   TYPE_SS_SCROLL_DYNAMIC.
     *
     * @return true if the cursor is on the last row in this result set
     * @return false otherwise
     */
    public boolean isLast() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "isLast"); 
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the type of this ResultSet object is TYPE_FORWARD_ONLY.
        verifyResultSetIsScrollable();

        // DYNAMIC cursors do not support isLast().  There is no way to determine absolute
        // position within the result set with a DYNAMIC cursor.
        if (isDynamic())
            throwUnsupportedCursorOp();
			
        if (isOnInsertRow)
            return false;

        // If the cursor is before the first row or after the last row then
        // it is by definition not on the last row.
        if (!hasCurrentRow())
            return false;

        // At this point circumstances are such that we must know the current row
        assert currentRow >= 1;

        // Determining whether the current row is the last row is easy if we know the row count
        if (UNKNOWN_ROW_COUNT != rowCount)
        {
            assert currentRow <= rowCount;
            return currentRow == rowCount;
        }

        // If we don't know the row count, determining whether the current row is
        // the last row is not quite as straightforward, but still reasonably efficient.
        // Presumably since we've ruled out a DYNAMIC cursor, the only way we would
        // not know the row count at this point is if we have a client cursor.
        assert 0 == serverCursorId;

        // All server cursors other than DYNAMIC give us a row count.  If we have
        // a client cursor, then we can tell whether the current row is the last
        // row just by checking whether there are any more rows in the fetch buffer.
        // A call to isLast() logically should not modify the current position in
        // the response, so save the current position and restore it on exit.
        boolean isLast = !next();
        previous();
        loggerExternal.exiting(getClassNameLogging(), "isLast", isLast);
        return isLast;
    }

    public void beforeFirst() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "beforeFirst"); 
        if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
        {
    		loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
        }
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the type of this ResultSet object is TYPE_FORWARD_ONLY.
        verifyResultSetIsScrollable();

        moverInit();
        moveBeforeFirst();
        loggerExternal.exiting(getClassNameLogging(), "beforeFirst");
    }

    private final void moveBeforeFirst() throws SQLServerException
    {
        if (0 == serverCursorId)
        {
            fetchBufferBeforeFirst();
            scrollWindow.clear();
        }
        else
        {
            doServerFetch(TDS.FETCH_FIRST, 0, 0);
        }

        currentRow = BEFORE_FIRST_ROW;
    }

    public void afterLast() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "afterLast"); 
        if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
        {
    		loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
        }
    
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the type of this ResultSet object is TYPE_FORWARD_ONLY.
        verifyResultSetIsScrollable();

        moverInit();
        moveAfterLast();
        loggerExternal.exiting(getClassNameLogging(), "afterLast");
    }

    private void moveAfterLast() throws SQLServerException
    {
        assert !isForwardOnly();

        if (0 == serverCursorId)
            clientMoveAfterLast();
        else
            doServerFetch(TDS.FETCH_LAST, 0, 0);

        currentRow = AFTER_LAST_ROW;
    }

    /**
     * Moves the cursor to the first row in this ResultSet object.
     *
     * This method should be called only on ResultSet objects that are scrollable:
     *   TYPE_SCROLL_SENSITIVE,
     *   TYPE_SCROLL_INSENSITIVE,
     *   TYPE_SS_SCROLL_STATIC,
     *   TYPE_SS_SCROLL_KEYSET,
     *   TYPE_SS_SCROLL_DYNAMIC.
     *
     * @return true if the cursor is on a valid row
     * @return false if there are no rows in this ResultSet object
     */
    public boolean first() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "first"); 
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the type of this ResultSet object is TYPE_FORWARD_ONLY.
        verifyResultSetIsScrollable();

        moverInit();
        moveFirst();
        boolean value =  hasCurrentRow();
        loggerExternal.exiting(getClassNameLogging(), "first", value);
        return value;
    }

    private final void moveFirst() throws SQLServerException
    {
        if (0 == serverCursorId)
        {
            moveBeforeFirst();
        }
        else
        {
            // Fetch the first block of up to fetchSize rows
            doServerFetch(TDS.FETCH_FIRST, 0, fetchSize);
        }

        // Start the scroll window at the first row in the fetch buffer
        if (!scrollWindow.next(this))
        {
            // If there are no rows in the result set then just ensure the current row
            // is positioned at a consistent location so that subsequent ResultSet
            // operations behave consistently.
            //
            // The actual position of the server cursor does not matter in this case.
            currentRow = AFTER_LAST_ROW;
            return;
        }

        // Adjust the current row appropriately
        currentRow = isDynamic() ? UNKNOWN_ROW : 1;
    }

    /**
     * Moves the cursor to the last row in this ResultSet object.
     *
     * This method should be called only on ResultSet objects that are scrollable:
     *   TYPE_SCROLL_SENSITIVE,
     *   TYPE_SCROLL_INSENSITIVE,
     *   TYPE_SS_SCROLL_STATIC,
     *   TYPE_SS_SCROLL_KEYSET,
     *   TYPE_SS_SCROLL_DYNAMIC.
     *
     * @return true if the cursor is on a valid row
     * @return false if there are no rows in this ResultSet object
     */
    public boolean last() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "last");     
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the type of this ResultSet object is TYPE_FORWARD_ONLY.
        verifyResultSetIsScrollable();

        moverInit();
        moveLast();
        boolean value =  hasCurrentRow();
        loggerExternal.exiting(getClassNameLogging(), "last", value);
        return value;
    }

    private final void moveLast() throws SQLServerException
    {
        if (0 == serverCursorId)
        {
            currentRow = clientMoveAbsolute(-1);
            return;
        }

        // Fetch the last block of up to fetchSize rows from the result set
        doServerFetch(TDS.FETCH_LAST, 0, fetchSize);

        // Start the scroll window at the first row in the fetch buffer
        if (!scrollWindow.next(this))
        {
            // If there are no rows in the result set then just ensure the current row
            // is positioned at a consistent location so that subsequent ResultSet
            // operations behave consistently.
            //
            // The actual position of the server cursor does not matter in this case.
            currentRow = AFTER_LAST_ROW;
            return;
        }

        // Scroll to the last of the returned rows
        while (scrollWindow.next(this))
            ;
        scrollWindow.previous(this);

        // Adjust the current row appropriately
        currentRow = isDynamic() ? UNKNOWN_ROW : rowCount;
    }

    /**
     * Retrieves the number of the current row in this ResultSet object.
     * The first row is number 1, the second is 2, and so on.
     *
     * @return the number of the current row; 0 if there is no current row
     */
    public int getRow() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getRow"); 
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // DYNAMIC (scrollable) cursors do not support getRow() since they do not have any
        // concept of absolute position.
        if (isDynamic() && !isForwardOnly())
            throwUnsupportedCursorOp();

        // From JDBC spec:
        // [returns] 0 if there is no current row.
        //
        // From our ResultSet Cursors feature spec:
        // getRow returns 0 when in insert mode.
        if (!hasCurrentRow() || isOnInsertRow)
            return 0;

        // We should be dealing with a cursor type that has a notion of absolute position
        assert currentRow >= 1;

        // Return that absolute position
        loggerExternal.exiting(getClassNameLogging(), "getRow", currentRow);
        return currentRow;
    }

    /**
     * Moves the cursor to the specified row in this ResultSet object.
     * The specified row may be positive, negative or zero.
     *
     * This method should be called only on ResultSet objects that are scrollable:
     *   TYPE_SCROLL_SENSITIVE,
     *   TYPE_SCROLL_INSENSITIVE,
     *   TYPE_SS_SCROLL_STATIC,
     *   TYPE_SS_SCROLL_KEYSET,
     *   TYPE_SS_SCROLL_DYNAMIC.
     *
     * @return true if the cursor is on a valid row in this result set
     * @return false if the cursor is before the first row or after the last row
     */
    public boolean absolute(int row) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "absolute"); 
        if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
        {
    		loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
        }
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + " row:" + row + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the type of this ResultSet object is TYPE_FORWARD_ONLY.
        verifyResultSetIsScrollable();

        // DYNAMIC cursors do not support absolute().  There is no way to determine absolute
        // position within the result set with a DYNAMIC cursor.
        if (isDynamic())
            throwUnsupportedCursorOp();

        moverInit();
        moveAbsolute(row);
        boolean value = hasCurrentRow();
        loggerExternal.exiting(getClassNameLogging(), "absolute", value);
        return value;
    }

    private void moveAbsolute(int row) throws SQLServerException
    {
        // Absolute positioning is not allowed for cursor types that don't support
        // knowing the absolute position.
        assert UNKNOWN_ROW != currentRow;
        assert !isDynamic();

        switch (row)
        {
            // If row is 0, the cursor is positioned before the first row.
            case 0:
                moveBeforeFirst();
                return;

            // Calling absolute(1) is the same as calling the method first().
            case 1:
                moveFirst();
                return;

            // Calling absolute(-1) is the same as calling the method last().
            case -1:
                moveLast();
                return;
        }

        // Depending on how much we know about the result set, an absolute move
        // can be translated into a relative move.  The advantage to doing this
        // is that we gain the benefit of using the scroll window, which reduces
        // calls to the server when absolute moves can translate to small moves
        // relative to the current row.
        if (hasCurrentRow())
        {
            assert currentRow >= 1;

            // If the absolute move is from the start of the result set (+ve rows)
            // then we can easily express it as a relative (to the current row) move:
            // the amount to move is just the difference between the current row and
            // the target absolute row.
            if (row > 0)
            {
                moveRelative(row - currentRow);
                return;
            }

            // If the absolute move is from the end of the result set (-ve rows)
            // then we also need to know how many rows are in the result set.
            // If we do then we can convert to an absolute move from the start
            // of the result set, and apply the logic above.
            if (UNKNOWN_ROW_COUNT != rowCount)
            {
                assert row < 0;
                moveRelative((rowCount + row + 1) - currentRow);
                return;
            }
        }

        // Ok, so there's no chance of a relative move.  In other words, the current
        // position may be before the first row or after the last row.  Or perhaps
        // it's an absolute move from the end of the result set and we don't know
        // how many rows there are yet (can happen with a scrollable client cursor).
        // In that case, we need to move absolutely.

        // Try to fetch a block of up to fetchSize rows starting at row row.
        if (0 == serverCursorId)
        {
            currentRow = clientMoveAbsolute(row);
            return;
        }

        doServerFetch(TDS.FETCH_ABSOLUTE, row, fetchSize);

        // If the absolute server fetch didn't land somewhere on the result set
        // then it's either before the first row or after the last row.
        if (!scrollWindow.next(this))
        {
            currentRow = (row < 0) ? BEFORE_FIRST_ROW : AFTER_LAST_ROW;
            return;
        }

        // The absolute server fetch landed somewhere on the result set,
        // so update the current row to reflect the new position.
        if (row > 0)
        {
            // The current row is just the row to which we moved.
            currentRow = row;
        }
        else
        {
            // Absolute fetch with -ve row is relative to the end of the result set.
            assert row < 0;
            assert rowCount + row + 1 >= 1;
            currentRow = rowCount + row + 1;
        }
    }

    private final boolean fetchBufferHasRows() throws SQLServerException
    {
        // Never call this with server cursors without first determining whether the
        // fetch buffer exists yet.
        assert 0 == serverCursorId;
        assert null != tdsReader;

        assert lastColumnIndex >= 0;

        // If we're somewhere in the middle of a row, then obviously the fetch buffer has rows!
        if (lastColumnIndex >= 1)
            return true;

        // We're not somewhere in the middle of a row, so we're either at the start of a row
        // or looking at an empty fetch buffer.  Peeking at the next TDS token tells us which.
        int tdsTokenType = tdsReader.peekTokenType();

        // Return whether the next item in the response appears to be a row or something
        // that should have been a row.
        return (TDS.TDS_ROW == tdsTokenType ||
        		TDS.TDS_NBCROW == tdsTokenType ||
                TDS.TDS_MSG == tdsTokenType ||
                TDS.TDS_ERR == tdsTokenType);
    }

    final void discardCurrentRow() throws SQLServerException
    {
        assert lastColumnIndex >= 0;

        updatedCurrentRow = false;
        deletedCurrentRow = false;
        if (lastColumnIndex >= 1)
        {
        	initializeNullCompressedColumns();
            // Discard columns up to, but not including, the last indexed column
            for (int columnIndex = 1; columnIndex < lastColumnIndex; ++columnIndex)
                getColumn(columnIndex).clear();

            // Skip and discard the remainder of the last indexed column
            // and all subsequent columns
            skipColumns(columns.length + 1 - lastColumnIndex, true);
        }
        
        //reset areNullCompressedColumnsInitialized to false and row type to unknown
        resultSetCurrentRowType = RowType.UNKNOWN; 
        areNullCompressedColumnsInitialized = false;
    }

    final int fetchBufferGetRow()
    {
        if (isForwardOnly())
            return numFetchedRows;

        return scrollWindow.getRow();
    }

    final void fetchBufferBeforeFirst() throws SQLServerException
    {
        // Never call this with server cursors without first determining whether the
        // fetch buffer exists yet.
        assert 0 == serverCursorId;
        assert null != tdsReader;

        discardCurrentRow();

        fetchBuffer.reset();
        lastColumnIndex = 0;
    }

    final TDSReaderMark fetchBufferMark()
    {
        // Never call this if we don't have a fetch buffer...
        assert null != tdsReader;

        return tdsReader.mark();
    }

    final void fetchBufferReset(TDSReaderMark mark) throws SQLServerException
    {
        // Never call this if we don't have a fetch buffer...
        assert null != tdsReader;

        assert null != mark;

        discardCurrentRow();

        tdsReader.reset(mark);
        
        lastColumnIndex = 1;
    }

    final boolean fetchBufferNext() throws SQLServerException
    {
        // If we don't have a fetch buffer yet then there are no rows to fetch
        if (null == tdsReader)
            return false;

        // We do have a fetch buffer.  So discard the current row in the fetch buffer and ...
        discardCurrentRow();

        // ... scan for the next row.
        // If we didn't find one, then we're done.
        RowType fetchBufferCurrentRowType = RowType.UNKNOWN;
        try
        {
        	fetchBufferCurrentRowType = fetchBuffer.nextRow();
            if (fetchBufferCurrentRowType.equals(RowType.UNKNOWN))
                return false;
        }
        catch (SQLServerException e)
        {
            currentRow = AFTER_LAST_ROW;
            rowErrorException = e;
            throw e;
        }
        finally
        {
        	lastColumnIndex = 0;
        	resultSetCurrentRowType = fetchBufferCurrentRowType;
        }

        // Otherwise, we found a row.
        ++numFetchedRows;
        lastColumnIndex = 1;
        return true;
    }

    private final void clientMoveAfterLast() throws SQLServerException
    {
        assert UNKNOWN_ROW != currentRow;

        int rowsSkipped = 0;
        while (fetchBufferNext())
            ++rowsSkipped;

        if (UNKNOWN_ROW_COUNT == rowCount)
        {
            assert AFTER_LAST_ROW != currentRow;
            rowCount = ((BEFORE_FIRST_ROW == currentRow) ? 0 : currentRow) + rowsSkipped;
        }
    }

    private final int clientMoveAbsolute(int row) throws SQLServerException
    {
        assert 0 == serverCursorId;

        scrollWindow.clear();

        // Because there is no way to know how far from the end of the result
        // set we are, if we are asked to move some number of rows from the end
        // of the result set then we must translate that into some number of rows
        // to move from the start (i.e. convert a negative row move to a positive
        // row move).
        if (row < 0)
        {
            // In order to convert a negative move to an absolute positive move,
            // we need to know the number of rows in the result set.  If we don't
            // already know the row count, then moving after the last row is
            // the only way to compute it (as a side effect).
            if (UNKNOWN_ROW_COUNT == rowCount)
            {
                clientMoveAfterLast();
                currentRow = AFTER_LAST_ROW;
            }

            // Now that we know the row count, we can translate the negative
            // move into a positive one.
            assert rowCount >= 0;

            // If we are moving backward from the end more rows than are in the
            // result set, then the ultimate position ends up before the first row.
            if (rowCount + row < 0)
            {
                moveBeforeFirst();
                return BEFORE_FIRST_ROW;
            }

            row = rowCount + row + 1;
        }

        // At this point we were either given a positive row movement from 
        // the start of the result set or we have converted the negative row
        // movement that we were given from the end of the result set into a
        // positive row movememnt.
        assert row > 0;

        // If the target row lies somewhere before the current row (including the
        // current row itself, because moving to the current row moves back to
        // the _beginning_ of the current row), then we have to move all the way
        // back to the beginning of the result set, and then move from there.
        if (AFTER_LAST_ROW == currentRow || row <= currentRow)
            moveBeforeFirst();

        // Now move from the current row (which may be before the first row)
        // to the target row.
        assert BEFORE_FIRST_ROW == currentRow || currentRow < row;
        while (currentRow != row)
        {
            if (!fetchBufferNext())
            {
                if (UNKNOWN_ROW_COUNT == rowCount)
                    rowCount = currentRow;
                return AFTER_LAST_ROW;
            }

            // Update the current row.
            // Note that if the position was before the first row, the current
            // row should be updated to row 1.
            if (BEFORE_FIRST_ROW == currentRow)
                currentRow = 1;
            else
                updateCurrentRow(1);
        }

        return row;
    }

    /**
     * Moves the cursor to the previous row in this ResultSet object.
     *
     * This method should be called only on ResultSet objects that are scrollable:
     *   TYPE_SCROLL_SENSITIVE,
     *   TYPE_SCROLL_INSENSITIVE,
     *   TYPE_SS_SCROLL_STATIC,
     *   TYPE_SS_SCROLL_KEYSET,
     *   TYPE_SS_SCROLL_DYNAMIC.
     *
     * @return true if the cursor is on a valid row in this result set
     * @return false otherwise
     */
    public boolean previous() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "previous"); 
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the type of this ResultSet object is TYPE_FORWARD_ONLY.
        verifyResultSetIsScrollable();

        moverInit();

        if (BEFORE_FIRST_ROW == currentRow)
            return false;

        if (AFTER_LAST_ROW == currentRow)
            moveLast();
        else
            moveBackward(-1);

        boolean value = hasCurrentRow();
        loggerExternal.exiting(getClassNameLogging(), "previous", value);
        return value;
    }

   private final void cancelInsert()
   {
     if (isOnInsertRow)
     {
       isOnInsertRow = false;
       clearColumnsValues();
     }
   }

   /** Clear any updated column values for the current row in the result set. */
   final void clearColumnsValues()
   {
     int l = columns.length;
     for (int i=0; i set the column state to initialized.  A call to get for an
        // uninitialized column throws an exception.
        // It doesn't say anything about calls to initialized columns (i.e. what happens
        // if update has been called).  Shipped behavior is that the value returned
        // is the value of the current row, not the updated value in the insert row!

        verifyResultSetHasCurrentRow();
        verifyCurrentRowIsNotDeleted("R_cantGetColumnValueFromDeletedRow");
        verifyValidColumnIndex(index);
        

        if (updatedCurrentRow)
        {
            doRefreshRow();
            verifyResultSetHasCurrentRow();
        }


        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() +" Getting Column:"+index);

        return loadColumn(index);
    }

    private final Object getValue(int columnIndex, JDBCType jdbcType) throws SQLServerException
    {
        return getValue(columnIndex, jdbcType, null, null);
    }

    private final Object getValue(int columnIndex, JDBCType jdbcType, Calendar cal) throws SQLServerException
    {
        return getValue(columnIndex, jdbcType, null, cal);
    }

    private final Object getValue(int columnIndex, JDBCType jdbcType, InputStreamGetterArgs getterArgs) throws SQLServerException
    {
        return getValue(columnIndex, jdbcType, getterArgs, null);
    }

    private final Object getValue(int columnIndex, JDBCType jdbcType, InputStreamGetterArgs getterArgs, Calendar cal) throws SQLServerException
    {
        Object o = getterGetColumn(columnIndex).getValue(jdbcType, getterArgs, cal, tdsReader);
        lastValueWasNull = (null == o);
        return o;
    }

    private Object getStream(int columnIndex, StreamType streamType) throws SQLServerException
    {
        Object value = getValue(
            columnIndex,
            streamType.getJDBCType(),
            new InputStreamGetterArgs(
                streamType,
                stmt.getExecProps().isResponseBufferingAdaptive(),
                isForwardOnly(),
                toString()));

        activeStream = (Closeable) value;
        return value;
    }
    private SQLXML getSQLXMLInternal(int columnIndex) throws SQLServerException
    {
        SQLServerSQLXML value = (SQLServerSQLXML)getValue(
            columnIndex,
            JDBCType.SQLXML,
            new InputStreamGetterArgs(
                StreamType.SQLXML,
                stmt.getExecProps().isResponseBufferingAdaptive(),
                isForwardOnly(),
                toString()));

        if(null != value)
            activeStream = (Closeable) value.getStream();
        return value;
    }
    

    public java.io.InputStream getAsciiStream(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getAsciiStream", columnIndex); 
        checkClosed();
        InputStream value = (InputStream) getStream(columnIndex, StreamType.ASCII);
        loggerExternal.exiting(getClassNameLogging(), "getAsciiStream",value);
        return value;
    }

    public java.io.InputStream getAsciiStream(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getAsciiStream", columnName); 
        checkClosed();
        InputStream value = (InputStream) getStream(findColumn(columnName), StreamType.ASCII);
        loggerExternal.exiting(getClassNameLogging(), "getAsciiStream",value);
        return value;
    }

    @Deprecated public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getBigDecimal", new Object[]{columnIndex, scale} ); 
        checkClosed();
        BigDecimal value = (BigDecimal) getValue(columnIndex, JDBCType.DECIMAL);
        if (null != value)
           value = value.setScale(scale, BigDecimal.ROUND_DOWN);
        loggerExternal.exiting(getClassNameLogging(), "getBigDecimal",value);
        return value;
    }

    @Deprecated public BigDecimal getBigDecimal(String columnName, int scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "columnName", new Object[]{columnName, scale} ); 
        checkClosed();
        BigDecimal value = (BigDecimal) getValue(findColumn(columnName), JDBCType.DECIMAL);
        if (null != value)
           value = value.setScale(scale, BigDecimal.ROUND_DOWN);
        loggerExternal.exiting(getClassNameLogging(), "getBigDecimal",value);
        return value;
    }

    public java.io.InputStream getBinaryStream(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getBinaryStream", columnIndex); 
        checkClosed();
        InputStream value = (InputStream) getStream(columnIndex, StreamType.BINARY);
        loggerExternal.exiting(getClassNameLogging(), "getBinaryStream",value);
        return value;
    }

    public java.io.InputStream getBinaryStream(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getBinaryStream", columnName);
        checkClosed();
        InputStream value = (InputStream) getStream(findColumn(columnName), StreamType.BINARY);
        loggerExternal.exiting(getClassNameLogging(), "getBinaryStream",value);
        return value;
    }

    public boolean getBoolean(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getBoolean", columnIndex);
        checkClosed();
        Boolean value = (Boolean) getValue(columnIndex, JDBCType.BIT);
        loggerExternal.exiting(getClassNameLogging(), "getBoolean",value);
        return null != value ? value.booleanValue() : false;
    }

    public boolean getBoolean(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getBoolean", columnName);
        checkClosed();
        Boolean value = (Boolean) getValue(findColumn(columnName), JDBCType.BIT);
        loggerExternal.exiting(getClassNameLogging(), "getBoolean",value);
        return null != value ? value.booleanValue() : false;
    }

    public byte getByte(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getByte", columnIndex);
        checkClosed();
        Short value = (Short) getValue(columnIndex, JDBCType.TINYINT);
        loggerExternal.exiting(getClassNameLogging(), "getByte",value);
        return null != value ? value.byteValue() : 0;
    }

    public byte getByte(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getByte", columnName); 
        checkClosed();
        Short value = (Short) getValue(findColumn(columnName), JDBCType.TINYINT);
        loggerExternal.exiting(getClassNameLogging(), "getByte",value);
        return null != value ? value.byteValue() : 0;
    }

    public byte[] getBytes(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getBytes", columnIndex); 
        checkClosed();
        byte[] value = (byte[]) getValue(columnIndex, JDBCType.BINARY);
        loggerExternal.exiting(getClassNameLogging(), "getBytes",value);
        return value;
    }

    public byte[] getBytes(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getBytes", columnName); 
        checkClosed();
        byte[] value = (byte[]) getValue(findColumn(columnName), JDBCType.BINARY);
        loggerExternal.exiting(getClassNameLogging(), "getBytes",value);
        return value;
    }

    public java.sql.Date getDate(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getDate", columnIndex); 
        checkClosed();
        java.sql.Date value = (java.sql.Date) getValue(columnIndex, JDBCType.DATE);
        loggerExternal.exiting(getClassNameLogging(), "getDate",value);
        return value;
    }

    public java.sql.Date getDate(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getDate", columnName); 
        checkClosed();
        java.sql.Date value = (java.sql.Date) getValue(findColumn(columnName), JDBCType.DATE);
        loggerExternal.exiting(getClassNameLogging(), "getDate",value);
        return value;
    }

    public java.sql.Date getDate(int columnIndex, Calendar cal) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getDate", new Object[]{columnIndex, cal}); 
        checkClosed();
        java.sql.Date value = (java.sql.Date) getValue(columnIndex, JDBCType.DATE, cal);
        loggerExternal.exiting(getClassNameLogging(), "getDate",value);
        return value;
    }

    public java.sql.Date getDate(String colName, Calendar cal) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getDate", new Object[]{colName, cal});
        checkClosed();
        java.sql.Date value = (java.sql.Date) getValue(findColumn(colName), JDBCType.DATE, cal);
        loggerExternal.exiting(getClassNameLogging(), "getDate",value);
        return value;
    }

    public double getDouble(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getDouble", columnIndex); 
        checkClosed();
        Double value = (Double) getValue(columnIndex, JDBCType.DOUBLE);
        loggerExternal.exiting(getClassNameLogging(), "getDouble",value);
        return null != value ? value.doubleValue() : 0;
    }

    public double getDouble(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getDouble", columnName); 
        checkClosed();
        Double value = (Double) getValue(findColumn(columnName), JDBCType.DOUBLE);
        loggerExternal.exiting(getClassNameLogging(), "getDouble",value);
        return null != value ? value.doubleValue() : 0;
    }

    public float getFloat(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getFloat", columnIndex); 
        checkClosed();
        Float value = (Float) getValue(columnIndex, JDBCType.REAL);
        loggerExternal.exiting(getClassNameLogging(), "getFloat",value);
        return null != value ? value.floatValue() : 0;
    }

    public float getFloat(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getFloat", columnName); 
        checkClosed();
        Float value = (Float) getValue(findColumn(columnName), JDBCType.REAL);
        loggerExternal.exiting(getClassNameLogging(), "getFloat",value);
        return null != value ? value.floatValue() : 0;
    }

    public int getInt(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getInt", columnIndex); 
        checkClosed();
        Integer value = (Integer) getValue(columnIndex, JDBCType.INTEGER);
        loggerExternal.exiting(getClassNameLogging(), "getInt",value);
        return null != value ? value.intValue() : 0;
    }

    public int getInt(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getInt", columnName); 
        checkClosed();
        Integer value = (Integer) getValue(findColumn(columnName), JDBCType.INTEGER);
        loggerExternal.exiting(getClassNameLogging(), "getInt",value);
        return null != value ? value.intValue() : 0;
    }

    public long getLong(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getLong", columnIndex); 
        checkClosed();
        Long value = (Long) getValue(columnIndex, JDBCType.BIGINT);
        loggerExternal.exiting(getClassNameLogging(), "getLong",value);
        return null != value ? value.longValue() : 0;
    }

    public long getLong(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getLong", columnName); 
        checkClosed();
        Long value = (Long) getValue(findColumn(columnName), JDBCType.BIGINT);
        loggerExternal.exiting(getClassNameLogging(), "getLong",value);
        return null != value ? value.longValue() : 0;
    }

    public java.sql.ResultSetMetaData getMetaData() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getMetaData"); 
        checkClosed();
        if (metaData == null)
            metaData = new SQLServerResultSetMetaData(stmt.connection, this);
        loggerExternal.exiting(getClassNameLogging(), "getMetaData",metaData);
        return metaData;
    }

    public Object getObject(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getObject", columnIndex); 
        checkClosed();
        Object value = getValue(columnIndex, getterGetColumn(columnIndex).getTypeInfo().getSSType().getJDBCType());
        loggerExternal.exiting(getClassNameLogging(), "getObject",value);
        return value;
    }
    
    public T getObject(int columnIndex, Class type) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC41();

    	// The driver currently does not implement JDDBC 4.1 APIs
    	throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));    	
    }

    public Object getObject(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getObject", columnName); 
        checkClosed();
        Object value = getObject(findColumn(columnName));
        loggerExternal.exiting(getClassNameLogging(), "getObject",value);
        return value;
    }

    public T getObject(String columnName, Class type) throws SQLException
    {    	
        DriverJDBCVersion.checkSupportsJDBC41();

    	// The driver currently does not implement JDDBC 4.1 APIs
    	throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));    	
    }
    
    public short getShort(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getShort", columnIndex); 
        checkClosed();
        Short value = (Short) getValue(columnIndex, JDBCType.SMALLINT);
        loggerExternal.exiting(getClassNameLogging(), "getShort",value);
        return null != value ? value.shortValue() : 0;
    }

    public short getShort(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getShort", columnName); 
        checkClosed();
        Short value = (Short) getValue(findColumn(columnName), JDBCType.SMALLINT);
        loggerExternal.exiting(getClassNameLogging(), "getShort",value);
        return null != value ? value.shortValue() : 0;
    }

    public String getString(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getString", columnIndex); 
        checkClosed();
        
        String value = null;
        Object objectValue = getValue(columnIndex, JDBCType.CHAR);
        if(null != objectValue){
        	value = objectValue.toString();
        }
        loggerExternal.exiting(getClassNameLogging(), "getString",value);
        return value;
    }

    public String getString(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getString", columnName); 
        checkClosed();
        
        String value = null;
        Object objectValue = getValue(findColumn(columnName), JDBCType.CHAR);
        if(null != objectValue){
        	value = objectValue.toString();
        }
        loggerExternal.exiting(getClassNameLogging(), "getString",value);
        return value;
    }

    public String getNString(int columnIndex) throws SQLException
    {
        loggerExternal.entering(getClassNameLogging(),  "getNString", columnIndex); 
        DriverJDBCVersion.checkSupportsJDBC4();
        checkClosed();
        String value = (String) getValue(columnIndex, JDBCType.NCHAR);
        loggerExternal.exiting(getClassNameLogging(), "getNString",value);
        return value;
    }

    public String getNString(String columnLabel) throws SQLException
    {
        loggerExternal.entering(getClassNameLogging(),  "getNString", columnLabel); 
        DriverJDBCVersion.checkSupportsJDBC4();
        checkClosed();
        String value = (String) getValue(findColumn(columnLabel), JDBCType.NCHAR);
        loggerExternal.exiting(getClassNameLogging(), "getNString",value);
        return value;
    }
    
    public String getUniqueIdentifier(int columnIndex) throws SQLException
    {
        loggerExternal.entering(getClassNameLogging(),  "getUniqueIdentifier", columnIndex); 
        checkClosed();
        String value = (String) getValue(columnIndex, JDBCType.GUID);
        loggerExternal.exiting(getClassNameLogging(), "getUniqueIdentifier",value);
        return value;
    }

    public String getUniqueIdentifier(String columnLabel) throws SQLException
    {
        loggerExternal.entering(getClassNameLogging(),  "getUniqueIdentifier", columnLabel); 
        checkClosed();
        String value = (String) getValue(findColumn(columnLabel), JDBCType.GUID);
        loggerExternal.exiting(getClassNameLogging(), "getUniqueIdentifier",value);
        return value;
    }

    public java.sql.Time getTime(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getTime", columnIndex); 
        checkClosed();
        java.sql.Time value = (java.sql.Time) getValue(columnIndex, JDBCType.TIME);
        loggerExternal.exiting(getClassNameLogging(), "getTime",value);
        return value;
    }

    public java.sql.Time getTime(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getTime", columnName); 
        checkClosed();
        java.sql.Time value = (java.sql.Time) getValue(findColumn(columnName), JDBCType.TIME);
        loggerExternal.exiting(getClassNameLogging(), "getTime",value);
        return value;
    }

    public java.sql.Time getTime(int columnIndex, Calendar cal) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getTime", new Object[]{columnIndex, cal}); 
        checkClosed();
        java.sql.Time value = (java.sql.Time) getValue(columnIndex, JDBCType.TIME, cal);
        loggerExternal.exiting(getClassNameLogging(), "getTime",value);
        return value;
    }

    public java.sql.Time getTime(String colName, Calendar cal) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getTime", new Object[]{colName, cal}); 
        checkClosed();
        java.sql.Time value = (java.sql.Time) getValue(findColumn(colName), JDBCType.TIME, cal);
        loggerExternal.exiting(getClassNameLogging(), "getTime",value);
        return value;
    }

    public java.sql.Timestamp getTimestamp(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getTimestamp", columnIndex); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(columnIndex, JDBCType.TIMESTAMP);
        loggerExternal.exiting(getClassNameLogging(), "getTimestamp",value);
        return value;
    }

    public java.sql.Timestamp getTimestamp(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getTimestamp", columnName); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(findColumn(columnName), JDBCType.TIMESTAMP);
        loggerExternal.exiting(getClassNameLogging(), "getTimestamp",value);
        return value;
    }

    public java.sql.Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getTimestamp", new Object[]{columnIndex, cal}); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(columnIndex, JDBCType.TIMESTAMP, cal);
        loggerExternal.exiting(getClassNameLogging(), "getTimeStamp",value);
        return value;
    }

    public java.sql.Timestamp getTimestamp(String colName, Calendar cal) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getTimestamp", new Object[]{colName, cal}); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(findColumn(colName), JDBCType.TIMESTAMP, cal);
        loggerExternal.exiting(getClassNameLogging(), "getTimestamp",value);
        return value;
    }
    
    public java.sql.Timestamp getDateTime(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getDateTime", columnIndex); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(columnIndex, JDBCType.TIMESTAMP);
        loggerExternal.exiting(getClassNameLogging(), "getDateTime",value);
        return value;
    }

    public java.sql.Timestamp getDateTime(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getDateTime", columnName); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(findColumn(columnName), JDBCType.TIMESTAMP);
        loggerExternal.exiting(getClassNameLogging(), "getDateTime",value);
        return value;
    }

    public java.sql.Timestamp getDateTime(int columnIndex, Calendar cal) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getDateTime", new Object[]{columnIndex, cal}); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(columnIndex, JDBCType.TIMESTAMP, cal);
        loggerExternal.exiting(getClassNameLogging(), "getDateTime",value);
        return value;
    }

    public java.sql.Timestamp getDateTime(String colName, Calendar cal) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getDateTime", new Object[]{colName, cal}); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(findColumn(colName), JDBCType.TIMESTAMP, cal);
        loggerExternal.exiting(getClassNameLogging(), "getDateTime",value);
        return value;
    }
    
    public java.sql.Timestamp getSmallDateTime(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getSmallDateTime", columnIndex); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(columnIndex, JDBCType.TIMESTAMP);
        loggerExternal.exiting(getClassNameLogging(), "getSmallDateTime",value);
        return value;
    }

    public java.sql.Timestamp getSmallDateTime(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getSmallDateTime", columnName); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(findColumn(columnName), JDBCType.TIMESTAMP);
        loggerExternal.exiting(getClassNameLogging(), "getSmallDateTime",value);
        return value;
    }

    public java.sql.Timestamp getSmallDateTime(int columnIndex, Calendar cal) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getSmallDateTime", new Object[]{columnIndex, cal}); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(columnIndex, JDBCType.TIMESTAMP, cal);
        loggerExternal.exiting(getClassNameLogging(), "getSmallDateTime",value);
        return value;
    }

    public java.sql.Timestamp getSmallDateTime(String colName, Calendar cal) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getSmallDateTime", new Object[]{colName, cal}); 
        checkClosed();
        java.sql.Timestamp value = (java.sql.Timestamp) getValue(findColumn(colName), JDBCType.TIMESTAMP, cal);
        loggerExternal.exiting(getClassNameLogging(), "getSmallDateTime",value);
        return value;
    }

    public microsoft.sql.DateTimeOffset getDateTimeOffset(int columnIndex) throws SQLException
    {
        loggerExternal.entering(getClassNameLogging(),  "getDateTimeOffset", columnIndex); 
        checkClosed();

        // DateTimeOffset is not supported with SQL Server versions earlier than Katmai
        if (!stmt.connection.isKatmaiOrLater())
            throw new SQLServerException(
                SQLServerException.getErrString("R_notSupported"),
                SQLState.DATA_EXCEPTION_NOT_SPECIFIC,
                DriverError.NOT_SET,
                null);

        microsoft.sql.DateTimeOffset value = (microsoft.sql.DateTimeOffset) getValue(columnIndex, JDBCType.DATETIMEOFFSET);
        loggerExternal.exiting(getClassNameLogging(), "getDateTimeOffset",value);
        return value;
    }

    public microsoft.sql.DateTimeOffset getDateTimeOffset(String columnName) throws SQLException
    {
        loggerExternal.entering(getClassNameLogging(),  "getDateTimeOffset", columnName); 
        checkClosed();

        // DateTimeOffset is not supported with SQL Server versions earlier than Katmai
        if (!stmt.connection.isKatmaiOrLater())
            throw new SQLServerException(
                SQLServerException.getErrString("R_notSupported"),
                SQLState.DATA_EXCEPTION_NOT_SPECIFIC,
                DriverError.NOT_SET,
                null);

        microsoft.sql.DateTimeOffset value = (microsoft.sql.DateTimeOffset) getValue(findColumn(columnName), JDBCType.DATETIMEOFFSET);
        loggerExternal.exiting(getClassNameLogging(), "getDateTimeOffset",value);
        return value;
    }

    @Deprecated public java.io.InputStream getUnicodeStream(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getUnicodeStream", columnIndex); 
        NotImplemented();
        return null;
    }

    @Deprecated public java.io.InputStream getUnicodeStream(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getUnicodeStream", columnName); 
        NotImplemented();
        return null;
    }

    public Object getObject(int i, java.util.Map> map) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "getObject", new Object[]{i, map}); 
        NotImplemented();
        return null;
    }

    public Ref getRef(int i) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getRef"); 
        NotImplemented();
        return null;
    }

    public Blob getBlob(int i) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getBlob", i); 
        checkClosed();
        Blob value = (Blob) getValue(i, JDBCType.BLOB);
        loggerExternal.exiting(getClassNameLogging(), "getBlob",value);
        return value;
    }

    public Blob getBlob(String colName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getBlob", colName); 
        checkClosed();
        Blob value = (Blob) getValue(findColumn(colName), JDBCType.BLOB);
        loggerExternal.exiting(getClassNameLogging(), "getBlob",value);
        return value;
    }

    public Clob getClob(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getClob", columnIndex); 
        checkClosed();
        Clob value = (Clob) getValue(columnIndex, JDBCType.CLOB);
        loggerExternal.exiting(getClassNameLogging(), "getClob",value);
        return value;
    }

    public Clob getClob(String colName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getClob", colName); 
        checkClosed();
        Clob value = (Clob) getValue(findColumn(colName), JDBCType.CLOB);
        loggerExternal.exiting(getClassNameLogging(), "getClob",value);
        return value;
    }

    public NClob getNClob(int columnIndex) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        loggerExternal.entering(getClassNameLogging(),  "getNClob", columnIndex); 
        checkClosed();
        NClob value = (NClob) getValue(columnIndex, JDBCType.NCLOB);
        loggerExternal.exiting(getClassNameLogging(), "getNClob",value);	        
        return value;
    }

    public NClob getNClob(String columnLabel) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        loggerExternal.entering(getClassNameLogging(),  "getNClob", columnLabel);         
        checkClosed();
        NClob value = (NClob) getValue(findColumn(columnLabel), JDBCType.NCLOB);
        loggerExternal.exiting(getClassNameLogging(), "getNClob",value);
        return value;
    }

    public Array getArray(int i) throws SQLServerException
    {
        NotImplemented();
        return null;
    }

    public Object getObject(String colName, java.util.Map> map) throws SQLServerException
    {
        NotImplemented();
        return null;
    }

    public Ref getRef(String colName) throws SQLServerException
    {
        NotImplemented();
        return null;
    }

    public Array getArray(String colName) throws SQLServerException
    {
        NotImplemented();
        return null;
    }

    public String getCursorName() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getCursorName"); 
        SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_positionedUpdatesNotSupported"), null, false);
        loggerExternal.exiting(getClassNameLogging(), "getCursorName", null);
        return null;
    }

    public java.io.Reader getCharacterStream(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getCharacterStream", columnIndex); 
        checkClosed();
        Reader value = (Reader) getStream(columnIndex, StreamType.CHARACTER);
        loggerExternal.exiting(getClassNameLogging(), "getCharacterStream",value);
        return value;
    }

    public java.io.Reader getCharacterStream(String columnName) throws SQLServerException
    {
        checkClosed();
        loggerExternal.entering(getClassNameLogging(),  "getCharacterStream", columnName); 
        Reader value = (Reader) getStream(findColumn(columnName), StreamType.CHARACTER);
        loggerExternal.exiting(getClassNameLogging(), "getCharacterStream",value);
        return value;
    }

    public Reader getNCharacterStream(int columnIndex) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        loggerExternal.entering(getClassNameLogging(),  "getNCharacterStream", columnIndex); 
        checkClosed();
        Reader value = (Reader) getStream(columnIndex, StreamType.NCHARACTER);
        loggerExternal.exiting(getClassNameLogging(), "getNCharacterStream",value);
        return value;
    }

    public Reader getNCharacterStream(String columnLabel) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        loggerExternal.entering(getClassNameLogging(),  "getNCharacterStream", columnLabel); 
        checkClosed();
        Reader value = (Reader) getStream(findColumn(columnLabel), StreamType.NCHARACTER);
        loggerExternal.exiting(getClassNameLogging(), "getNCharacterStream",value);
        return value;
    }

    public BigDecimal getBigDecimal(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getBigDecimal", columnIndex); 
        checkClosed();
        BigDecimal value = (BigDecimal) getValue(columnIndex, JDBCType.DECIMAL);
        loggerExternal.exiting(getClassNameLogging(), "getBigDecimal",value);
        return value;
    }

    public BigDecimal getBigDecimal(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getBigDecimal", columnName); 
        checkClosed();
        BigDecimal value = (BigDecimal) getValue(findColumn(columnName), JDBCType.DECIMAL);
        loggerExternal.exiting(getClassNameLogging(), "getBigDecimal", value);
        return value;
    }
    
    public BigDecimal getMoney(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getMoney", columnIndex); 
        checkClosed();
        BigDecimal value = (BigDecimal) getValue(columnIndex, JDBCType.DECIMAL);
        loggerExternal.exiting(getClassNameLogging(), "getMoney",value);
        return value;
    }

    public BigDecimal getMoney(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getMoney", columnName); 
        checkClosed();
        BigDecimal value = (BigDecimal) getValue(findColumn(columnName), JDBCType.DECIMAL);
        loggerExternal.exiting(getClassNameLogging(), "getMoney", value);
        return value;
    }
    
    public BigDecimal getSmallMoney(int columnIndex) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getSmallMoney", columnIndex); 
        checkClosed();
        BigDecimal value = (BigDecimal) getValue(columnIndex, JDBCType.DECIMAL);
        loggerExternal.exiting(getClassNameLogging(), "getSmallMoney",value);
        return value;
    }

    public BigDecimal getSmallMoney(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "getSmallMoney", columnName); 
        checkClosed();
        BigDecimal value = (BigDecimal) getValue(findColumn(columnName), JDBCType.DECIMAL);
        loggerExternal.exiting(getClassNameLogging(), "getSmallMoney", value);
        return value;
    }

    public RowId getRowId(int columnIndex) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();

        // Not implemented
        throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));
    }

    public RowId getRowId(String columnLabel) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();

        // Not implemented
        throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));
    }

    public SQLXML getSQLXML(int columnIndex) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        loggerExternal.entering(getClassNameLogging(),  "getSQLXML", columnIndex); 
        SQLXML xml= getSQLXMLInternal(columnIndex);
        loggerExternal.exiting(getClassNameLogging(), "getSQLXML", xml);
        return xml;
    }

    public SQLXML getSQLXML(String columnLabel) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        loggerExternal.entering(getClassNameLogging(),  "getSQLXML", columnLabel); 
        SQLXML xml= getSQLXMLInternal(findColumn(columnLabel));
        loggerExternal.exiting(getClassNameLogging(), "getSQLXML", xml);
        return xml;
    }

    public boolean rowUpdated() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "rowUpdated");
        checkClosed();
        // From JDBC spec:
        // Throws SQLException if the concurrency of this ResultSet object is CONCUR_READ_ONLY.
        verifyResultSetIsUpdatable();

        // From ResultSet cursor feature spec:
        // SQL Server does not detect updated rows for any cursor type
        loggerExternal.exiting(getClassNameLogging(), "rowUpdated", false);
        return false;
    }

    public boolean rowInserted() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "rowInserted"); 
        checkClosed();
                
        // From JDBC spec:
        // Throws SQLException if the concurrency of this ResultSet object is CONCUR_READ_ONLY.
        verifyResultSetIsUpdatable();

        // From ResultSet cursor feature spec:
        // SQL Server does not detect inserted rows for any cursor type
        loggerExternal.exiting(getClassNameLogging(), "rowInserted", false);
        return false;
    }

    public boolean rowDeleted() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "rowDeleted"); 
        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the concurrency of this ResultSet object is CONCUR_READ_ONLY.
        verifyResultSetIsUpdatable();

        if (isOnInsertRow || !hasCurrentRow())
            return false;

        boolean deleted = currentRowDeleted();
        loggerExternal.exiting(getClassNameLogging(), "rowDeleted", deleted);
        return deleted;
    }

    /**
     * Determines whether the current row of this result set is deleted.
     *
     * A row may be deleted via the result set cursor (via ResultSet.deleteRow)
     * or it may have been deleted outside the cursor.  This function checks
     * for both possibilities.
     */
    private final boolean currentRowDeleted() throws SQLServerException
    {
        // Never call this function without a current row
        assert hasCurrentRow();

        // Having a current row implies we have a fetch buffer in which that row exists.
        assert null != tdsReader;

        return
            deletedCurrentRow ||
            (0 != serverCursorId && TDS.ROWSTAT_FETCH_MISSING == loadColumn(columns.length).getInt(tdsReader));
    }

   /* ---------------- Column updates ---------------------- */

    /**
     * Does all the common stuff necessary when calling a getter for
     * the column at index.
     *
     * @param index the index of the column to get
     */
    final private Column updaterGetColumn(int index) throws SQLServerException
    {
        // From JDBC spec:
        // Throws SQLException if the concurrency of this ResultSet object is CONCUR_READ_ONLY.
        verifyResultSetIsUpdatable();

        verifyValidColumnIndex(index);

        // Verify that the column is updatable (i.e. that it is not a computed column).
        if (!columns[index-1].isUpdatable())
        {
            SQLServerException.makeFromDriverError(
                stmt.connection,
                stmt,
                SQLServerException.getErrString("R_cantUpdateColumn"),
                "07009",
                false);
        }

        // Column values on the insert row are always updatable,
        // regardless whether this ResultSet has any current row.
        if (!isOnInsertRow)
        {
            // Column values can only be updated on the insert row and the current row.
            // We just determined that we're not on the insert row, so make sure
            // that this ResultSet has a current row (i.e. that the ResultSet's position
            // is not before the first row or after the last row).
            if (!hasCurrentRow())
            {
                SQLServerException.makeFromDriverError(
                    stmt.connection,
                    stmt,
                    SQLServerException.getErrString("R_resultsetNoCurrentRow"),
                    null,
                    true);
            }

            // A current row exists.  Its column values are updatable only if the row
            // is not a deleted row ("hole").
            verifyCurrentRowIsNotDeleted("R_cantUpdateDeletedRow");
        }

        return getColumn(index);
    }
    
    private void updateValue(
            int columnIndex,
            JDBCType jdbcType,
            Object value,
            JavaType javaType,
            boolean forceEncrypt) throws SQLServerException
        {
            updaterGetColumn(columnIndex).updateValue(
                jdbcType,
                value,
                javaType,
                null,
                null,
                null,
                stmt.connection,
                stmt.stmtColumnEncriptionSetting,
                null,
                forceEncrypt,
                columnIndex);
        }
    
    private void updateValue(
            int columnIndex,
            JDBCType jdbcType,
            Object value,
            JavaType javaType,
            Calendar cal,
            boolean forceEncrypt) throws SQLServerException
        {
            updaterGetColumn(columnIndex).updateValue(
                jdbcType,
                value,
                javaType,
                null,
                cal,
                null,
                stmt.connection,
                stmt.stmtColumnEncriptionSetting,
                null,
                forceEncrypt,
                columnIndex);
        }
    
    private void updateValue(
            int columnIndex,
            JDBCType jdbcType,
            Object value,
            JavaType javaType,
            Integer precision,
            Integer scale,
            boolean forceEncrypt) throws SQLServerException
        {
            updaterGetColumn(columnIndex).updateValue(
                jdbcType,
                value,
                javaType,
                null,
                null,
                scale,
                stmt.connection,
                stmt.stmtColumnEncriptionSetting,
                precision,
                forceEncrypt,
                columnIndex);
        }

    private void updateStream(
        int columnIndex,
        StreamType streamType,
        Object value,
        JavaType javaType,
        long length) throws SQLServerException
    {
        updaterGetColumn(columnIndex).updateValue(
            streamType.getJDBCType(),
            value,
            javaType,
            new StreamSetterArgs(streamType, length),
            null,
            null,
            stmt.connection,
            stmt.stmtColumnEncriptionSetting,
            null,
            false,
            columnIndex);
    }

    private final void updateSQLXMLInternal(int columnIndex, SQLXML value) throws SQLServerException
    {
        updaterGetColumn(columnIndex).updateValue(
            JDBCType.SQLXML,
            value,
            JavaType.SQLXML,
            new StreamSetterArgs(StreamType.SQLXML, DataTypes.UNKNOWN_STREAM_LENGTH),
            null,
            null,
            stmt.connection,
            stmt.stmtColumnEncriptionSetting,
            null,
            false,
            columnIndex);
    }

    public void updateNull(int index) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "updateNull", index);

        checkClosed();
        updateValue(
            index,
            updaterGetColumn(index).getTypeInfo().getSSType().getJDBCType(),
            null,
            JavaType.OBJECT,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateNull");
    }

    public void updateBoolean(int index, boolean x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBoolean",  new Object[]{index, x});
        checkClosed();
        updateValue(
            index,
            JDBCType.BIT,
            Boolean.valueOf(x),
            JavaType.BOOLEAN,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateBoolean");
    }
    
    public void updateBoolean(int index, boolean x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBoolean",  new Object[]{index, x, forceEncrypt});
        checkClosed();
        updateValue(
            index,
            JDBCType.BIT,
            Boolean.valueOf(x),
            JavaType.BOOLEAN,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateBoolean");
    }

    public void updateByte(int index, byte x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateByte",  new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.TINYINT,
            Byte.valueOf(x),
            JavaType.BYTE,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateByte");
    }
    
    public void updateByte(int index, byte x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateByte",  new Object[]{index, x, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.TINYINT,
            Byte.valueOf(x),
            JavaType.BYTE,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateByte");
    }

    public void updateShort(int index, short x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateShort",  new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.SMALLINT,
            Short.valueOf(x),
            JavaType.SHORT,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateShort");
    }
    
    public void updateShort(int index, short x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateShort",  new Object[]{index, x, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.SMALLINT,
            Short.valueOf(x),
            JavaType.SHORT,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateShort");
    }

    public void updateInt(int index, int x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateInt",  new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.INTEGER,
            Integer.valueOf(x),
            JavaType.INTEGER,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateInt");
    }
    
    public void updateInt(int index, int x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateInt",  new Object[]{index, x, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.INTEGER,
            Integer.valueOf(x),
            JavaType.INTEGER,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateInt");
    }

    public void updateLong(int index, long x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateLong", new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.BIGINT,
            Long.valueOf(x),
            JavaType.LONG,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateLong");
    }
    
    public void updateLong(int index, long x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateLong", new Object[]{index, x, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.BIGINT,
            Long.valueOf(x),
            JavaType.LONG,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateLong");
    }

    public void updateFloat(int index, float x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateFloat", new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.REAL,
            Float.valueOf(x),
            JavaType.FLOAT,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateFloat");
    }
    
    public void updateFloat(int index, float x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateFloat", new Object[]{index, x, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.REAL,
            Float.valueOf(x),
            JavaType.FLOAT,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateFloat");
    }

    public void updateDouble(int index, double x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDouble", new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.DOUBLE,
            Double.valueOf(x),
            JavaType.DOUBLE,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateDouble");
    }
    
    public void updateDouble(int index, double x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDouble", new Object[]{index, x, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.DOUBLE,
            Double.valueOf(x),
            JavaType.DOUBLE,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateDouble");
    }

    public void updateMoney(int index, BigDecimal x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateMoney",  new Object[]{index, x});
        checkClosed();
        updateValue(
            index,
            JDBCType.MONEY,
            x,
            JavaType.BIGDECIMAL,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateMoney");
    }
    
    public void updateMoney(int index, BigDecimal x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateMoney",  new Object[]{index, x, forceEncrypt});
        checkClosed();
        updateValue(
            index,
            JDBCType.MONEY,
            x,
            JavaType.BIGDECIMAL,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateMoney");
    }

    public void updateMoney(String columnName, BigDecimal x) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateMoney",  new Object[]{columnName, x});
		checkClosed();
		updateValue(
				findColumn(columnName),
				JDBCType.MONEY,
				x,
				JavaType.BIGDECIMAL,
				false);

		loggerExternal.exiting(getClassNameLogging(), "updateMoney");
	}

	public void updateMoney(String columnName, BigDecimal x, boolean forceEncrypt) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateMoney",  new Object[]{columnName, x, forceEncrypt});
		checkClosed();
		updateValue(
				findColumn(columnName),
				JDBCType.MONEY,
				x,
				JavaType.BIGDECIMAL,
				forceEncrypt);

		loggerExternal.exiting(getClassNameLogging(), "updateMoney");
	}
	
    public void updateSmallMoney(int index, BigDecimal x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateSmallMoney",  new Object[]{index, x});
        checkClosed();
        updateValue(
            index,
            JDBCType.SMALLMONEY,
            x,
            JavaType.BIGDECIMAL,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateSmallMoney");
    }
    
    public void updateSmallMoney(int index, BigDecimal x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateSmallMoney",  new Object[]{index, x, forceEncrypt});
        checkClosed();
        updateValue(
            index,
            JDBCType.SMALLMONEY,
            x,
            JavaType.BIGDECIMAL,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateSmallMoney");
    }
    
	public void updateSmallMoney(String columnName, BigDecimal x) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateSmallMoney",  new Object[]{columnName, x});
		checkClosed();
		updateValue(
				findColumn(columnName),
				JDBCType.SMALLMONEY,
				x,
				JavaType.BIGDECIMAL,
				false);

		loggerExternal.exiting(getClassNameLogging(), "updateSmallMoney");
	}

	public void updateSmallMoney(String columnName, BigDecimal x, boolean forceEncrypt) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateSmallMoney",  new Object[]{columnName, x, forceEncrypt});
		checkClosed();
		updateValue(
				findColumn(columnName),
				JDBCType.SMALLMONEY,
				x,
				JavaType.BIGDECIMAL,
				forceEncrypt);

		loggerExternal.exiting(getClassNameLogging(), "updateSmallMoney");
	}
	
    public void updateBigDecimal(int index, BigDecimal x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBigDecimal",  new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.DECIMAL,
            x,
            JavaType.BIGDECIMAL,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateBigDecimal");
    }
    
    public void updateBigDecimal(int index, BigDecimal x, Integer precision, Integer scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBigDecimal",  new Object[]{index, x, scale});

        checkClosed();
        updateValue(
            index,
            JDBCType.DECIMAL,
            x,
            JavaType.BIGDECIMAL,
            precision,
            scale,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateBigDecimal");
    }
    
    public void updateBigDecimal(int index, BigDecimal x, Integer precision, Integer scale, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBigDecimal",  new Object[]{index, x, scale, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.DECIMAL,
            x,
            JavaType.BIGDECIMAL,
            precision,
            scale,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateBigDecimal");
    }

    public void updateString(int columnIndex, String stringValue) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateString",  new Object[]{columnIndex, stringValue});

        checkClosed();
        updateValue(
            columnIndex,
            JDBCType.VARCHAR,
            stringValue,
            JavaType.STRING,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateString");
    }
    
    public void updateString(int columnIndex, String stringValue, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateString",  new Object[]{columnIndex, stringValue, forceEncrypt});

        checkClosed();
        updateValue(
            columnIndex,
            JDBCType.VARCHAR,
            stringValue,
            JavaType.STRING,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateString");
    }

    public void updateNString(int columnIndex, String nString) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateNString",  new Object[]{columnIndex, nString});

        DriverJDBCVersion.checkSupportsJDBC4();
        checkClosed();
        updateValue(
            columnIndex,
            JDBCType.NVARCHAR,
            nString,
            JavaType.STRING,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateNString");
    }
    
    public void updateNString(int columnIndex, String nString, boolean forceEncrypt) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateNString",  new Object[]{columnIndex, nString, forceEncrypt});

        DriverJDBCVersion.checkSupportsJDBC4();
        checkClosed();
        updateValue(
            columnIndex,
            JDBCType.NVARCHAR,
            nString,
            JavaType.STRING,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateNString");
    }

    public void updateNString(String columnLabel, String nString) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateNString",  new Object[]{columnLabel, nString});

        DriverJDBCVersion.checkSupportsJDBC4();
        checkClosed();
        updateValue(
            findColumn(columnLabel),
            JDBCType.NVARCHAR,
            nString,
            JavaType.STRING,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateNString");
    }
    
    public void updateNString(String columnLabel, String nString, boolean forceEncrypt) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateNString",  new Object[]{columnLabel, nString, forceEncrypt});

        DriverJDBCVersion.checkSupportsJDBC4();
        checkClosed();
        updateValue(
            findColumn(columnLabel),
            JDBCType.NVARCHAR,
            nString,
            JavaType.STRING,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateNString");
    }

    public void updateBytes(int index, byte x[]) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBytes",  new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.BINARY,
            x,
            JavaType.BYTEARRAY,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateBytes");
    }
    
    public void updateBytes(int index, byte x[], boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBytes",  new Object[]{index, x, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.BINARY,
            x,
            JavaType.BYTEARRAY,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateBytes");
    }

    public void updateDate(int index, java.sql.Date x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDate",  new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.DATE,
            x,
            JavaType.DATE,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateDate");
    }
    
    public void updateDate(int index, java.sql.Date x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDate",  new Object[]{index, x, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.DATE,
            x,
            JavaType.DATE,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateDate");
    }

    public void updateTime(int index, java.sql.Time x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTime",  new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.TIME,
            x,
            JavaType.TIME,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateTime");
    }
    
    public void updateTime(int index, java.sql.Time x, Integer scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTime",  new Object[]{index, x, scale});

        checkClosed();
        updateValue(
            index,
            JDBCType.TIME,
            x,
            JavaType.TIME,
            null,
            scale,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateTime");
    }
    
    public void updateTime(int index, java.sql.Time x, Integer scale, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTime",  new Object[]{index, x, scale, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.TIME,
            x,
            JavaType.TIME,
            null,
            scale,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateTime");
    }

    public void updateTimestamp(int index, java.sql.Timestamp x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTimestamp",  new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.TIMESTAMP,
            x,
            JavaType.TIMESTAMP,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateTimestamp");
    }
    
    public void updateTimestamp(int index, java.sql.Timestamp x, int scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTimestamp",  new Object[]{index, x, scale});

        checkClosed();
        updateValue(
            index,
            JDBCType.TIMESTAMP,
            x,
            JavaType.TIMESTAMP,
            null,
            scale,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateTimestamp");
    }
    
    public void updateTimestamp(int index, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTimestamp",  new Object[]{index, x, scale, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.TIMESTAMP,
            x,
            JavaType.TIMESTAMP,
            null,
            scale,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateTimestamp");
    }
    
    public void updateDateTime(int index, java.sql.Timestamp x) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateDateTime",  new Object[]{index, x});

		checkClosed();
		updateValue(
				index,
				JDBCType.DATETIME,
				x,
				JavaType.TIMESTAMP,
				false);

		loggerExternal.exiting(getClassNameLogging(), "updateDateTime");
	}
    
	public void updateDateTime(int index, java.sql.Timestamp x, Integer scale) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateDateTime",  new Object[]{index, x, scale});

		checkClosed();
		updateValue(
				index,
				JDBCType.DATETIME,
				x,
				JavaType.TIMESTAMP,
				null,
				scale,
				false);

		loggerExternal.exiting(getClassNameLogging(), "updateDateTime");
	}
	
	public void updateDateTime(int index, java.sql.Timestamp x, Integer scale, boolean forceEncrypt) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateDateTime",  new Object[]{index, x, scale, forceEncrypt});

		checkClosed();
		updateValue(
				index,
				JDBCType.DATETIME,
				x,
				JavaType.TIMESTAMP,
				null,
				scale,
				forceEncrypt);

		loggerExternal.exiting(getClassNameLogging(), "updateDateTime");
	}
	
	public void updateSmallDateTime(int index, java.sql.Timestamp x) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateSmallDateTime",  new Object[]{index, x});

		checkClosed();
		updateValue(
				index,
				JDBCType.SMALLDATETIME,
				x,
				JavaType.TIMESTAMP,
				false);

		loggerExternal.exiting(getClassNameLogging(), "updateSmallDateTime");
	}
	
	public void updateSmallDateTime(int index, java.sql.Timestamp x, Integer scale) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateSmallDateTime",  new Object[]{index, x, scale});

		checkClosed();
		updateValue(
				index,
				JDBCType.SMALLDATETIME,
				x,
				JavaType.TIMESTAMP,
				null,
				scale,
				false);

		loggerExternal.exiting(getClassNameLogging(), "updateSmallDateTime");
	}
	
	public void updateSmallDateTime(int index, java.sql.Timestamp x, Integer scale, boolean forceEncrypt) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateSmallDateTime",  new Object[]{index, x, scale, forceEncrypt});

		checkClosed();
		updateValue(
				index,
				JDBCType.SMALLDATETIME,
				x,
				JavaType.TIMESTAMP,
				null,
				scale,
				forceEncrypt);

		loggerExternal.exiting(getClassNameLogging(), "updateSmallDateTime");
	}

    public void updateDateTimeOffset(int index, microsoft.sql.DateTimeOffset x) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDateTimeOffset",  new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.DATETIMEOFFSET,
            x,
            JavaType.DATETIMEOFFSET,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateDateTimeOffset");
    }
    
    public void updateDateTimeOffset(int index, microsoft.sql.DateTimeOffset x, Integer scale) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDateTimeOffset",  new Object[]{index, x, scale});

        checkClosed();
        updateValue(
            index,
            JDBCType.DATETIMEOFFSET,
            x,
            JavaType.DATETIMEOFFSET,
            null,
            scale,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateDateTimeOffset");
    }
    
    public void updateDateTimeOffset(int index, microsoft.sql.DateTimeOffset x, Integer scale, boolean forceEncrypt) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDateTimeOffset",  new Object[]{index, x, scale, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.DATETIMEOFFSET,
            x,
            JavaType.DATETIMEOFFSET,
            null,
            scale,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateDateTimeOffset");
    }
    
    public void updateUniqueIdentifier(int index, String x) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateUniqueIdentifier",  new Object[]{index, x});

        checkClosed();
        updateValue(
            index,
            JDBCType.GUID,
            x,
            JavaType.STRING,
            null,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateUniqueIdentifier");
    }
    
    public void updateUniqueIdentifier(int index, String x, boolean forceEncrypt) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateUniqueIdentifier",  new Object[]{index, x, forceEncrypt});

        checkClosed();
        updateValue(
            index,
            JDBCType.GUID,
            x,
            JavaType.STRING,
            null,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateUniqueIdentifier");
    }
    
    public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateAsciiStream",  new Object[]{columnIndex, x});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.ASCII,
            x,
            JavaType.INPUTSTREAM,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateAsciiStream");
    }

    public void updateAsciiStream(int index, java.io.InputStream x, int length) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateAsciiStream",  new Object[]{index, x, length});

        checkClosed();
        updateStream(
            index,
            StreamType.ASCII,
            x,
            JavaType.INPUTSTREAM,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateAsciiStream");
    }

    public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        loggerExternal.entering(getClassNameLogging(),  "updateAsciiStream",  new Object[]{columnIndex, x, length});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.ASCII,
            x,
            JavaType.INPUTSTREAM,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateAsciiStream");
    }

    public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateAsciiStream",  new Object[]{columnLabel, x});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.ASCII,
            x,
            JavaType.INPUTSTREAM,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateAsciiStream");
    }

    public void updateAsciiStream(java.lang.String columnName, java.io.InputStream x, int length) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateAsciiStream",  new Object[]{columnName, x, length});

        checkClosed();
        updateStream(
            findColumn(columnName),
            StreamType.ASCII,
            x,
            JavaType.INPUTSTREAM,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateAsciiStream");
    }

    public void updateAsciiStream(String columnName, InputStream streamValue, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateAsciiStream",  new Object[]{columnName, streamValue, length});

        checkClosed();
        updateStream(
            findColumn(columnName),
            StreamType.ASCII,
            streamValue,
            JavaType.INPUTSTREAM,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateAsciiStream");
    }

    public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBinaryStream",  new Object[]{columnIndex, x});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.BINARY,
            x,
            JavaType.INPUTSTREAM,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateBinaryStream");
    }

    public void updateBinaryStream(int columnIndex, InputStream streamValue, int length) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBinaryStream",  new Object[]{columnIndex, streamValue, length});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.BINARY,
            streamValue,
            JavaType.INPUTSTREAM,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateBinaryStream");
    }

    public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBinaryStream",  new Object[]{columnIndex, x, length});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.BINARY,
            x,
            JavaType.INPUTSTREAM,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateBinaryStream");
    }

    public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBinaryStream",  new Object[]{columnLabel, x});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.BINARY,
            x,
            JavaType.INPUTSTREAM,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateBinaryStream");
    }

    public void updateBinaryStream(String columnName, InputStream streamValue, int length) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBinaryStream",  new Object[]{columnName, streamValue, length});

        checkClosed();
        updateStream(
            findColumn(columnName),
            StreamType.BINARY,
            streamValue,
            JavaType.INPUTSTREAM,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateBinaryStream");
    }

    public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBinaryStream",  new Object[]{columnLabel, x, length});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.BINARY,
            x,
            JavaType.INPUTSTREAM,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateBinaryStream");
    }

    public void updateCharacterStream(int columnIndex, Reader x) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateCharacterStream",  new Object[]{columnIndex, x});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.CHARACTER,
            x,
            JavaType.READER,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateCharacterStream");
    }

    public void updateCharacterStream(int columnIndex, Reader readerValue, int length) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateCharacterStream",  new Object[]{columnIndex, readerValue, length});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.CHARACTER,
            readerValue,
            JavaType.READER,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateCharacterStream");
    }

    public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateCharacterStream",  new Object[]{columnIndex, x, length});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.CHARACTER,
            x,
            JavaType.READER,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateCharacterStream");
    }

    public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))    
            loggerExternal.entering(getClassNameLogging(),  "updateCharacterStream",  new Object[]{columnLabel, reader});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.CHARACTER,
            reader,
            JavaType.READER,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateCharacterStream");
    }

    public void updateCharacterStream(String columnName, Reader readerValue, int length) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateCharacterStream",  new Object[]{columnName, readerValue, length});

        checkClosed();
        updateStream(
            findColumn(columnName),
            StreamType.CHARACTER,
            readerValue,
            JavaType.READER,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateCharacterStream");
    }

    public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))    
            loggerExternal.entering(getClassNameLogging(),  "updateCharacterStream",  new Object[]{columnLabel, reader, length});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.CHARACTER,
            reader,
            JavaType.READER,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateNCharacterStream");
    }

    public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateNCharacterStream",  new Object[]{columnIndex, x});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.NCHARACTER,
            x,
            JavaType.READER,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateNCharacterStream");
    }

    public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateNCharacterStream",  new Object[]{columnIndex, x, length});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.NCHARACTER,
            x,
            JavaType.READER,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateNCharacterStream");
    }

    public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateNCharacterStream",  new Object[]{columnLabel, reader});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.NCHARACTER,
            reader,
            JavaType.READER,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateNCharacterStream");
    }

    public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateNCharacterStream",  new Object[]{columnLabel, reader, length});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.NCHARACTER,
            reader,
            JavaType.READER,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateNCharacterStream");
    }

    public void updateObject(int index, Object obj) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateObject",  new Object[]{index, obj});

        checkClosed();
        updateObject(index, obj, (Integer) null, null, null, false);

        loggerExternal.exiting(getClassNameLogging(), "updateObject");
    }

  
    public void updateObject(int index, Object x, int scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateObject",  new Object[]{index, x, scale});

        checkClosed();
        updateObject(index, x, Integer.valueOf(scale), null, null, false);

        loggerExternal.exiting(getClassNameLogging(), "updateObject");
    }
    
    public void updateObject(int index, Object x, int precision, int scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateObject",  new Object[]{index, x, scale});

        checkClosed();
        updateObject(index, x, Integer.valueOf(scale), null, precision, false);

        loggerExternal.exiting(getClassNameLogging(), "updateObject");
    }
    
    public void updateObject(int index, Object x, int precision, int scale, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateObject",  new Object[]{index, x, scale, forceEncrypt});

        checkClosed();
        updateObject(index, x, Integer.valueOf(scale), null, precision, forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateObject");
    }


    protected final void updateObject(int index, Object x, Integer scale, JDBCType jdbcType, Integer precision, boolean forceEncrypt) throws SQLServerException
    {
        Column column = updaterGetColumn(index);
        SSType ssType = column.getTypeInfo().getSSType();

        if (null == x)
        {
        	if (null == jdbcType || jdbcType.isUnsupported())
        	{
            	// JDBCType is not specified by user or is unsupported, derive from SSType 
        		jdbcType =  ssType.getJDBCType();
        	}
        	
            column.updateValue(
                jdbcType,
                x,
                JavaType.OBJECT,
                null, // streamSetterArgs
                null,
                scale,
                stmt.connection,
                stmt.stmtColumnEncriptionSetting,
                precision,
                forceEncrypt,
                index);
        }
        else
        {
            JavaType javaType = JavaType.of(x);
            JDBCType objectJdbcType = javaType.getJDBCType(ssType, ssType.getJDBCType());

            if (null == jdbcType)
            {
            	// JDBCType is not specified by user, derive from the object's JavaType 
            	jdbcType = objectJdbcType;
            }
            else
            {
                // Check convertibility of the value to the desired JDBC type.
                if (!objectJdbcType.convertsTo(jdbcType))
                    DataTypes.throwConversionError(objectJdbcType.toString(), jdbcType.toString());            	
            }

            StreamSetterArgs streamSetterArgs = null;
            switch (javaType)
            {
                case READER:
                    streamSetterArgs = new StreamSetterArgs(
                        StreamType.CHARACTER,
                        DataTypes.UNKNOWN_STREAM_LENGTH);
                    break;

                case INPUTSTREAM:
                    streamSetterArgs = new StreamSetterArgs(
                        jdbcType.isTextual() ? StreamType.CHARACTER : StreamType.BINARY,
                        DataTypes.UNKNOWN_STREAM_LENGTH);
                    break;

                case SQLXML:
                    streamSetterArgs = new StreamSetterArgs(
                        StreamType.SQLXML, 
                        DataTypes.UNKNOWN_STREAM_LENGTH);
                    break;
                    
                default:
					// Do nothing
                	break;
            }

            column.updateValue(
                jdbcType,
                x,
                javaType,
                streamSetterArgs,
                null,
                scale,
                stmt.connection,
                stmt.stmtColumnEncriptionSetting,
                precision,
                forceEncrypt,
                index);
        }
    }

    public void updateNull(String columnName) throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "updateNull",  columnName);

        checkClosed();
        int columnIndex = findColumn(columnName);
        updateValue(
            columnIndex,
            updaterGetColumn(columnIndex).getTypeInfo().getSSType().getJDBCType(),
            null,
            JavaType.OBJECT,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateNull");
    }


    public void updateBoolean(String columnName, boolean x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBoolean",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.BIT,
            Boolean.valueOf(x),
            JavaType.BOOLEAN,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateBoolean");
    }
    
    public void updateBoolean(String columnName, boolean x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBoolean",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.BIT,
            Boolean.valueOf(x),
            JavaType.BOOLEAN,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateBoolean");
    }

    public void updateByte(String columnName, byte x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateByte",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.BINARY,
            x,
            JavaType.BYTE,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateByte");
    }
    
    public void updateByte(String columnName, byte x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateByte",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.BINARY,
            x,
            JavaType.BYTE,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateByte");
    }

    public void updateShort(String columnName, short x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateShort",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.SMALLINT,
            Short.valueOf(x),
            JavaType.SHORT,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateShort");
    }
    
    public void updateShort(String columnName, short x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateShort",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.SMALLINT,
            Short.valueOf(x),
            JavaType.SHORT,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateShort");
    }

    public void updateInt(String columnName, int x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateInt",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.INTEGER,
            Integer.valueOf(x),
            JavaType.INTEGER,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateInt");
    }
    
    public void updateInt(String columnName, int x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateInt",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.INTEGER,
            Integer.valueOf(x),
            JavaType.INTEGER,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateInt");
    }

    public void updateLong(String columnName, long x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateLong",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.BIGINT,
            Long.valueOf(x),
            JavaType.LONG,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateLong");
    }
    
    public void updateLong(String columnName, long x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateLong",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.BIGINT,
            Long.valueOf(x),
            JavaType.LONG,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateLong");
    }

    public void updateFloat(String columnName, float x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateFloat",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.REAL,
            Float.valueOf(x),
            JavaType.FLOAT,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateFloat");
    }
    
    public void updateFloat(String columnName, float x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateFloat",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.REAL,
            Float.valueOf(x),
            JavaType.FLOAT,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateFloat");
    }

    public void updateDouble(String columnName, double x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDouble",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.DOUBLE,
            Double.valueOf(x),
            JavaType.DOUBLE,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateDouble");
    }
    
    public void updateDouble(String columnName, double x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDouble",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.DOUBLE,
            Double.valueOf(x),
            JavaType.DOUBLE,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateDouble");
    }

    public void updateBigDecimal(String columnName, BigDecimal x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBigDecimal",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.DECIMAL,
            x,
            JavaType.BIGDECIMAL,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateBigDecimal");
    }
    
    public void updateBigDecimal(String columnName, BigDecimal x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBigDecimal",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.DECIMAL,
            x,
            JavaType.BIGDECIMAL,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateBigDecimal");
    }
    
    public void updateBigDecimal(String columnName, BigDecimal x, Integer precision, Integer scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBigDecimal",  new Object[]{columnName, x, precision, scale});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.DECIMAL,
            x,
            JavaType.BIGDECIMAL,
            precision,
            scale,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateBigDecimal");
    }
    
    public void updateBigDecimal(String columnName, BigDecimal x, Integer precision, Integer scale, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBigDecimal",  new Object[]{columnName, x, precision, scale, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.DECIMAL,
            x,
            JavaType.BIGDECIMAL,
            precision,
            scale,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateBigDecimal");
    }

    public void updateString(String columnName, String x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateString",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.VARCHAR,
            x,
            JavaType.STRING,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateString");
    }
    
    public void updateString(String columnName, String x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateString",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.VARCHAR,
            x,
            JavaType.STRING,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateString");
    }

    public void updateBytes(String columnName, byte x[]) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBytes",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.BINARY,
            x,
            JavaType.BYTEARRAY,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateBytes");
    }
    
    public void updateBytes(String columnName, byte x[], boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBytes",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.BINARY,
            x,
            JavaType.BYTEARRAY,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateBytes");
    }

    public void updateDate(String columnName, java.sql.Date x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDate",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.DATE,
            x,
            JavaType.DATE,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateDate");
    }
    
    public void updateDate(String columnName, java.sql.Date x, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDate",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.DATE,
            x,
            JavaType.DATE,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateDate");
    }

    public void updateTime(String columnName, java.sql.Time x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTime",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.TIME,
            x,
            JavaType.TIME,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateTime");
    }
    
    public void updateTime(String columnName, java.sql.Time x, int scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTime",  new Object[]{columnName, x, scale});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.TIME,
            x,
            JavaType.TIME,
            null,
            scale,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateTime");
    }
    
    public void updateTime(String columnName, java.sql.Time x, int scale, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTime",  new Object[]{columnName, x, scale, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.TIME,
            x,
            JavaType.TIME,
            null,
            scale,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateTime");
    }

    public void updateTimestamp(String columnName, java.sql.Timestamp x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTimestamp",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.TIMESTAMP,
            x,
            JavaType.TIMESTAMP,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateTimestamp");
    }
    
    public void updateTimestamp(String columnName, java.sql.Timestamp x, int scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTimestamp",  new Object[]{columnName, x, scale});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.TIMESTAMP,
            x,
            JavaType.TIMESTAMP,
            null,
            scale,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateTimestamp");
    }
    
    public void updateTimestamp(String columnName, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateTimestamp",  new Object[]{columnName, x, scale, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.TIMESTAMP,
            x,
            JavaType.TIMESTAMP,
            null,
            scale,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateTimestamp");
    }
    
    public void updateDateTime(String columnName, java.sql.Timestamp x) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateDateTime",  new Object[]{columnName, x});

		checkClosed();
		updateValue(
				findColumn(columnName),
				JDBCType.DATETIME,
				x,
				JavaType.TIMESTAMP,
				false);

		loggerExternal.exiting(getClassNameLogging(), "updateDateTime");
	}
    
	public void updateDateTime(String columnName, java.sql.Timestamp x, int scale) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateDateTime",  new Object[]{columnName, x, scale});

		checkClosed();
		updateValue(
				findColumn(columnName),
				JDBCType.DATETIME,
				x,
				JavaType.TIMESTAMP,
				null,
				scale,
				false);

		loggerExternal.exiting(getClassNameLogging(), "updateDateTime");
	}
	
	public void updateDateTime(String columnName, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateDateTime",  new Object[]{columnName, x, scale, forceEncrypt});

		checkClosed();
		updateValue(
				findColumn(columnName),
				JDBCType.DATETIME,
				x,
				JavaType.TIMESTAMP,
				null,
				scale,
				forceEncrypt);

		loggerExternal.exiting(getClassNameLogging(), "updateDateTime");
	}
	
	public void updateSmallDateTime(String columnName, java.sql.Timestamp x) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateSmallDateTime",  new Object[]{columnName, x});

		checkClosed();
		updateValue(
				findColumn(columnName),
				JDBCType.SMALLDATETIME,
				x,
				JavaType.TIMESTAMP,
				false);

		loggerExternal.exiting(getClassNameLogging(), "updateSmallDateTime");
	}
	
	public void updateSmallDateTime(String columnName, java.sql.Timestamp x, int scale) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateSmallDateTime",  new Object[]{columnName, x, scale});

		checkClosed();
		updateValue(
				findColumn(columnName),
				JDBCType.SMALLDATETIME,
				x,
				JavaType.TIMESTAMP,
				null,
				scale,
				false);

		loggerExternal.exiting(getClassNameLogging(), "updateSmallDateTime");
	}
	
	public void updateSmallDateTime(String columnName, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException
	{
		if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
			loggerExternal.entering(getClassNameLogging(),  "updateSmallDateTime",  new Object[]{columnName, x, scale, forceEncrypt});

		checkClosed();
		updateValue(
				findColumn(columnName),
				JDBCType.SMALLDATETIME,
				x,
				JavaType.TIMESTAMP,
				null,
				scale,
				forceEncrypt);

		loggerExternal.exiting(getClassNameLogging(), "updateSmallDateTime");
	}
	
    public void updateDateTimeOffset(String columnName, microsoft.sql.DateTimeOffset x) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDateTimeOffset",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.DATETIMEOFFSET,
            x,
            JavaType.DATETIMEOFFSET,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateDateTimeOffset");
    }
    
    public void updateDateTimeOffset(String columnName, microsoft.sql.DateTimeOffset x, int scale) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDateTimeOffset",  new Object[]{columnName, x, scale});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.DATETIMEOFFSET,
            x,
            JavaType.DATETIMEOFFSET,
            null,
            scale,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateDateTimeOffset");
    }
    
    public void updateDateTimeOffset(String columnName, microsoft.sql.DateTimeOffset x, int scale, boolean forceEncrypt) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateDateTimeOffset",  new Object[]{columnName, x, scale, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.DATETIMEOFFSET,
            x,
            JavaType.DATETIMEOFFSET,
            null,
            scale,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateDateTimeOffset");
    }
    
    public void updateUniqueIdentifier(String columnName, String x) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateUniqueIdentifier",  new Object[]{columnName, x});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.GUID,
            x,
            JavaType.STRING,
            null,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateUniqueIdentifier");
    }
    
    public void updateUniqueIdentifier(String columnName, String x, boolean forceEncrypt) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateUniqueIdentifier",  new Object[]{columnName, x, forceEncrypt});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.GUID,
            x,
            JavaType.STRING,
            null,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateUniqueIdentifier");
    }
    
    public void updateObject(String columnName, Object x, int scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateObject",  new Object[]{columnName, x, scale});

        checkClosed();
        updateObject(
            findColumn(columnName),
            x,
            Integer.valueOf(scale),
            null, 
            null,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateObject");
    }
    
    public void updateObject(String columnName, Object x, int precision, int scale) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateObject",  new Object[]{columnName, x, precision, scale});

        checkClosed();
        updateObject(
            findColumn(columnName),
            x,
            Integer.valueOf(scale),
            null, 
            precision,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateObject");
    }
    
    public void updateObject(String columnName, Object x, int precision, int scale, boolean forceEncrypt) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateObject",  new Object[]{columnName, x, precision, scale, forceEncrypt});

        checkClosed();
        updateObject(
            findColumn(columnName),
            x,
            Integer.valueOf(scale),
            null, 
            precision,
            forceEncrypt);

        loggerExternal.exiting(getClassNameLogging(), "updateObject");
    }
    
    public void updateObject(String columnName, Object x) throws SQLServerException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateObject",  new Object[]{columnName, x});

        checkClosed(); 
        updateObject(
            findColumn(columnName),
            x,
            (Integer) null,
            null, 
            null,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateObject");
    }
    

    public void updateRowId(int columnIndex, RowId x) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();

        // Not implemented
        throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));
    }

    public void updateRowId(String columnLabel, RowId x) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();

        // Not implemented
        throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));
    }

    public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateSQLXML",  new Object[]{columnIndex, xmlObject});
        updateSQLXMLInternal(columnIndex, xmlObject);
        loggerExternal.exiting(getClassNameLogging(), "updateSQLXML");
    }

    public void updateSQLXML(String columnLabel, SQLXML x) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateSQLXML",  new Object[]{columnLabel, x});
        DriverJDBCVersion.checkSupportsJDBC4();
        updateSQLXMLInternal(findColumn(columnLabel), x);
        loggerExternal.exiting(getClassNameLogging(), "updateSQLXML");
    }

    public int getHoldability() throws SQLException
    {
        loggerExternal.entering(getClassNameLogging(), "getHoldability");

        DriverJDBCVersion.checkSupportsJDBC4();
        checkClosed();

        int holdability =

        // Client-cursored result sets are always holdable because there is
        // no server cursor for the server to close, and no way for the driver
        // to detect the commit anyway...
        (0 == stmt.getServerCursorId()) ? ResultSet.HOLD_CURSORS_OVER_COMMIT :

		// For Yukon and later server-cursored result sets, holdability
        // was determined at statement execution time and does not change.
        stmt.getExecProps().getHoldability();

        loggerExternal.exiting(getClassNameLogging(), "getHoldability", holdability);

        return holdability;
    }

    /* ----------------------- Update result set ------------------------- */

    public void insertRow() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "insertRow");
        if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
        {
    		loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
        }
        
        final class InsertRowRPC extends TDSCommand
        {
            final String tableName;

            InsertRowRPC(String tableName)
            {
                super("InsertRowRPC", 0);
                this.tableName = tableName;
            }

            final boolean doExecute() throws SQLServerException
            {
                doInsertRowRPC(this, tableName);
                return true;
            }
        }

        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();
        
        // From JDBC spec:
        // Throws SQLException if the concurrency of this ResultSet object is CONCUR_READ_ONLY.
        verifyResultSetIsUpdatable();

        if (!isOnInsertRow)
        {
            SQLServerException.makeFromDriverError(
                stmt.connection,
                stmt,
                SQLServerException.getErrString("R_mustBeOnInsertRow"),
                null,
                true);
        }

        // Determine the table/view into which the row is to be inserted.
        //
        // The logic for doing this is as follows:
        //
        // If values were set for any of the columns in this ResultSet
        // then use the table associated with the first column in the
        // SELECT list whose value was set.
        //
        // If no values were set for any of the columns (insert row with
        // default values) then choose the table name associated with the
        // first updatable column.  An updatable column is one that is not
        // a computed expression, not hidden, and has a non-empty table name.
        //
        // If no values were set for any columns and no columns are updatable,
        // then the table name cannot be determined, so error.
        Column tableColumn = null;
        for (int i = 0; i < columns.length; i++)
        {
            if (columns[i].hasUpdates())
            {
                tableColumn = columns[i];
                break;
            }

            if (null == tableColumn && columns[i].isUpdatable())
                tableColumn = columns[i];
        }

        if (null == tableColumn)
        {
            SQLServerException.makeFromDriverError(
                stmt.connection,
                stmt,
                SQLServerException.getErrString("R_noColumnParameterValue"),
                null,
                true);
        }

        assert tableColumn.isUpdatable();
        assert null != tableColumn.getTableName();
 
        stmt.executeCommand(new InsertRowRPC(tableColumn.getTableName().asEscapedString()));

        if (UNKNOWN_ROW_COUNT != rowCount)
            ++rowCount;
        loggerExternal.exiting(getClassNameLogging(), "insertRow");  
    }

    private final void doInsertRowRPC(TDSCommand command, String tableName) throws SQLServerException
    {
        assert 0 != serverCursorId;
        assert null != tableName;
        assert tableName.length() > 0;

        TDSWriter tdsWriter = command.startRequest(TDS.PKT_RPC);
        tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs
        tdsWriter.writeShort(TDS.PROCID_SP_CURSOR);
        tdsWriter.writeByte((byte) 0);  // RPC procedure option 1
        tdsWriter.writeByte((byte) 0);  // RPC procedure option 2
        tdsWriter.writeRPCInt(null, new Integer(serverCursorId), false);
        tdsWriter.writeRPCInt(null, new Integer(TDS.SP_CURSOR_OP_INSERT), false);
        tdsWriter.writeRPCInt(null, new Integer(fetchBufferGetRow()), false);

        if (hasUpdatedColumns())
        {
			tdsWriter.writeRPCStringUnicode(tableName);

			for (int i = 0; i < columns.length; i++)
				columns[i].sendByRPC(tdsWriter, stmt.connection);
        }
        else
        {
            tdsWriter.writeRPCStringUnicode("");
            tdsWriter.writeRPCStringUnicode("INSERT INTO " + tableName + " DEFAULT VALUES");
        }

        TDSParser.parse(command.startResponse(), command.getLogContext());
    }


    public void updateRow() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "updateRow");
        if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
        {
    		loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
        }
        final class UpdateRowRPC extends TDSCommand
        {
            UpdateRowRPC()
            {
                super("UpdateRowRPC", 0);
            }

            final boolean doExecute() throws SQLServerException
            {
                doUpdateRowRPC(this);
                return true;
            }
        }

        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();
        
        // From JDBC spec:
        // Throws SQLException if the concurrency of this ResultSet object is CONCUR_READ_ONLY.
        verifyResultSetIsUpdatable();

        // From JDBC spec:
        // [updateRow] must be called when the cursor is on the current row;
        // an exception will be thrown if it is called with the cursor is on the insert row.
        verifyResultSetIsNotOnInsertRow();
        verifyResultSetHasCurrentRow();

        // Deleted rows cannot be updated.
        verifyCurrentRowIsNotDeleted("R_cantUpdateDeletedRow");

        if (!hasUpdatedColumns())
        {
            SQLServerException.makeFromDriverError(
                stmt.connection,
                stmt,
                SQLServerException.getErrString("R_noColumnParameterValue"),
                null,
                true);
        }


        try
        {
            stmt.executeCommand(new UpdateRowRPC());
        }
        finally
        {
            cancelUpdates();
        }

        updatedCurrentRow = true;
        loggerExternal.exiting(getClassNameLogging(), "updateRow");
    }

    private final void doUpdateRowRPC(TDSCommand command) throws SQLServerException
    {
        assert 0 != serverCursorId;

        TDSWriter tdsWriter = command.startRequest(TDS.PKT_RPC);
        tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs
        tdsWriter.writeShort(TDS.PROCID_SP_CURSOR);
        tdsWriter.writeByte((byte) 0);  // RPC procedure option 1
        tdsWriter.writeByte((byte) 0);  // RPC procedure option 2
        tdsWriter.writeRPCInt(null, new Integer(serverCursorId), false);
        tdsWriter.writeRPCInt(null, new Integer(TDS.SP_CURSOR_OP_UPDATE | TDS.SP_CURSOR_OP_SETPOSITION), false);
        tdsWriter.writeRPCInt(null, new Integer(fetchBufferGetRow()), false);
        tdsWriter.writeRPCStringUnicode("");

        assert hasUpdatedColumns();

        for (int i = 0; i use ProcIDs
        tdsWriter.writeShort(TDS.PROCID_SP_CURSOR);
        tdsWriter.writeByte((byte) 0);  // RPC procedure option 1
        tdsWriter.writeByte((byte) 0);  // RPC procedure option 2
        tdsWriter.writeRPCInt(null, new Integer(serverCursorId), false);
        tdsWriter.writeRPCInt(null, new Integer(TDS.SP_CURSOR_OP_DELETE | TDS.SP_CURSOR_OP_SETPOSITION), false);
        tdsWriter.writeRPCInt(null, new Integer(fetchBufferGetRow()), false);
        tdsWriter.writeRPCStringUnicode("");

        TDSParser.parse(command.startResponse(), command.getLogContext());
    }

    public void refreshRow() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "refreshRow");
        if(loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn())
        {
    		loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
        }

        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // This method is not supported for ResultSet objects that are type TYPE_FORWARD_ONLY.
        verifyResultSetIsScrollable();

        // From JDBC spec:
        // Throws SQLException if the concurrency of this ResultSet object is CONCUR_READ_ONLY.
        verifyResultSetIsUpdatable();

        // From JDBC spec:
        // Throws SQLException if this method is called when the cursor is on the insert row.
        verifyResultSetIsNotOnInsertRow();

        // Verify that the cursor is not before the first row, after the last row, or on a deleted row.
        verifyResultSetHasCurrentRow();
        verifyCurrentRowIsNotDeleted("R_cantUpdateDeletedRow");

        // From the JDBC spec:
        // [This method] does nothing for [ResultSet objects] that are type TYPE_SCROLL_INSENSITIVE.
        //
        // Included in that definition is result sets for which the server was asked to return a server cursor,
        // but ended up returning the results directly instead.
        if (ResultSet.TYPE_SCROLL_INSENSITIVE == stmt.getResultSetType() || 0 == serverCursorId)
            return;

        // From JDBC spec:
        // If refreshRow is called after calling updater [methods] but before calling updateRow,
        // then the updates made to the row are lost.
        cancelUpdates();

        doRefreshRow();
        loggerExternal.exiting(getClassNameLogging(), "refreshRow");
    }

    private void doRefreshRow() throws SQLServerException
    {
        assert hasCurrentRow();

        // Save off the current row offset into the fetch buffer so that we can attempt to
        // restore to that position after refetching.
        int fetchBufferSavedRow = fetchBufferGetRow();

        // Refresh all the rows in the fetch buffer.  This is allowed by the JDBC spec:
        // If the fetch size is greater than one, the driver may refetch multiple rows at once.
        doServerFetch(TDS.FETCH_REFRESH, 0, 0);

        // Scroll back to the current row.  Note that with DYNAMIC cursors, there is no guarantee
        // that the contents of the fetch buffer after a refresh look anything like they did before
        // the refresh -- rows may have been added, modified, or deleted -- so the current row
        // may not end up where it was before the refresh.
        int fetchBufferRestoredRow = 0;
        while (fetchBufferRestoredRow < fetchBufferSavedRow &&
               (isForwardOnly() ? fetchBufferNext() : scrollWindow.next(this)))
        {
            ++fetchBufferRestoredRow;
        }

        if (fetchBufferRestoredRow < fetchBufferSavedRow)
        {
            currentRow = AFTER_LAST_ROW;
            return;
        }

        // Finally, ensure that we've cleared the flag that the current row was updated.  This ensures
        // that a subsequent getter doesn't do another unnecessary refresh when called.
        updatedCurrentRow = false;
    }

    private final void cancelUpdates()
    {
        if (!isOnInsertRow)
            clearColumnsValues();
    }

    public void cancelRowUpdates() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "cancelRowUpdates");
        checkClosed();

        // From JDBC spec:
        // Throws SQLException if this method is called when the cursor is on the insert row or if
        // this ResultSet object has a concurrency of CONCUR_READ_ONLY.
        verifyResultSetIsUpdatable();
        verifyResultSetIsNotOnInsertRow();

        cancelUpdates();
        loggerExternal.exiting(getClassNameLogging(), "cancelRowUpdates");
    }

    public void moveToInsertRow() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "moveToInsertRow");
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the concurrency of this ResultSet object is CONCUR_READ_ONLY.
        verifyResultSetIsUpdatable();

        cancelUpdates();
        isOnInsertRow = true;
        loggerExternal.exiting(getClassNameLogging(), "moveToInsertRow");
    }

    public void moveToCurrentRow() throws SQLServerException
    {
        loggerExternal.entering(getClassNameLogging(),  "moveToCurrentRow");
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + logCursorState());

        checkClosed();

        // From JDBC spec:
        // Throws SQLException if the concurrency of this ResultSet object is CONCUR_READ_ONLY.
        verifyResultSetIsUpdatable();

        // Note that we don't verify that the row is on the insert row.  From the JDBC spec:
        // This method should be called only when the cursor is on the insert row
        // and has no effect if the cursor is not on the insert row.

        cancelInsert();
        loggerExternal.exiting(getClassNameLogging(), "moveToCurrentRow");
        
    }

   /*L0*/ public java.sql.Statement getStatement() throws SQLServerException 
    {
        loggerExternal.entering(getClassNameLogging(),  "getStatement");
        checkClosed(); 
        loggerExternal.exiting(getClassNameLogging(), "getStatement", stmt);
        return stmt;
    }

   /* JDBC 3.0 */

    public void updateClob(int columnIndex, Clob clobValue) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateClob", new Object[]{columnIndex, clobValue});

        checkClosed();
        updateValue(
            columnIndex,
            JDBCType.CLOB,
            clobValue,
            JavaType.CLOB,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateClob");
    }

    public void updateClob(int columnIndex, Reader reader) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateClob", new Object[]{columnIndex, reader});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.CHARACTER,
            reader,
            JavaType.READER,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateClob");
    }

    public void updateClob(int columnIndex, Reader reader, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateClob", new Object[]{columnIndex, reader, length});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.CHARACTER,
            reader,
            JavaType.READER,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateClob");
    }

    public void updateClob(String columnName, Clob clobValue) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateClob", new Object[]{columnName, clobValue});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.CLOB,
            clobValue,
            JavaType.CLOB,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateClob");
    }

    public void updateClob(String columnLabel, Reader reader) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateClob", new Object[]{columnLabel, reader});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.CHARACTER,
            reader,
            JavaType.READER,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateClob");
    }

    public void updateClob(String columnLabel, Reader reader, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateClob", new Object[]{columnLabel, reader, length});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.CHARACTER,
            reader,
            JavaType.READER,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateClob");
    }

    public void updateNClob(int columnIndex, NClob nClob) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateClob", new Object[]{columnIndex, nClob});

        checkClosed();
        updateValue(
            columnIndex,
            JDBCType.NCLOB,
            nClob,
            JavaType.NCLOB,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateNClob");
    }

    public void updateNClob(int columnIndex, Reader reader) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateNClob", new Object[]{columnIndex, reader});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.NCHARACTER,
            reader,
            JavaType.READER,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateNClob");
    }

    public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))    
            loggerExternal.entering(getClassNameLogging(),  "updateNClob", new Object[]{columnIndex, reader, length});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.NCHARACTER,
            reader,
            JavaType.READER,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateNClob");
    }

    public void updateNClob(String columnLabel, NClob nClob) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateNClob", new Object[]{columnLabel, nClob});

        checkClosed();
        updateValue(
            findColumn(columnLabel),
            JDBCType.NCLOB,
            nClob,
            JavaType.NCLOB,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateNClob");
    }

    public void updateNClob(String columnLabel, Reader reader) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateNClob", new Object[]{columnLabel, reader});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.NCHARACTER,
            reader,
            JavaType.READER,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateNClob");
    }

    public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))    
            loggerExternal.entering(getClassNameLogging(),  "updateNClob", new Object[]{columnLabel, reader, length});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.NCHARACTER,
            reader,
            JavaType.READER,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateNClob");
    }

    public void updateBlob(int columnIndex, Blob blobValue) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBlob", new Object[]{columnIndex, blobValue});

        checkClosed();
        updateValue(
            columnIndex,
            JDBCType.BLOB,
            blobValue,
            JavaType.BLOB,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateBlob");
    }

    public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBlob", new Object[]{columnIndex, inputStream});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.BINARY,
            inputStream,
            JavaType.INPUTSTREAM,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateBlob");
    }

    public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBlob", new Object[]{columnIndex, inputStream, length});

        checkClosed();
        updateStream(
            columnIndex,
            StreamType.BINARY,
            inputStream,
            JavaType.INPUTSTREAM,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateBlob");
    }

    public void updateBlob(String columnName, Blob blobValue) throws SQLException
    {
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBlob", new Object[]{columnName, blobValue});

        checkClosed();
        updateValue(
            findColumn(columnName),
            JDBCType.BLOB,
            blobValue,
            JavaType.BLOB,
            false);

        loggerExternal.exiting(getClassNameLogging(), "updateBlob");
    }

    public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBlob", new Object[]{columnLabel, inputStream});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.BINARY,
            inputStream,
            JavaType.INPUTSTREAM,
            DataTypes.UNKNOWN_STREAM_LENGTH);

        loggerExternal.exiting(getClassNameLogging(), "updateBlob");
    }

    public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException
    {
        DriverJDBCVersion.checkSupportsJDBC4();
        if(loggerExternal.isLoggable(java.util.logging.Level.FINER))
            loggerExternal.entering(getClassNameLogging(),  "updateBlob", new Object[]{columnLabel, inputStream, length});

        checkClosed();
        updateStream(
            findColumn(columnLabel),
            StreamType.BINARY,
            inputStream,
            JavaType.INPUTSTREAM,
            length);

        loggerExternal.exiting(getClassNameLogging(), "updateBlob");
    }

   /*L3*/ public void updateArray(int columnIndex, Array x)throws SQLServerException {
     stmt.NotImplemented();
   }
   /*L3*/ public void updateArray(java.lang.String columnName, Array x) throws SQLServerException {
     stmt.NotImplemented();
   }
   /*L3*/ public void updateRef(int columnIndex, Ref x) throws SQLServerException {
     stmt.NotImplemented();
   }
   /*L3*/ public void updateRef(java.lang.String columnName, Ref x) throws SQLServerException {
     stmt.NotImplemented();
   }
   /*L3*/ public java.net.URL getURL(int columnIndex) throws SQLServerException {
     stmt.NotImplemented();
	 return null;
   }
   /*L3*/ public java.net.URL getURL(String sColumn) throws SQLServerException {
     stmt.NotImplemented();
	 return null;
   }

    /** Absolute position in this ResultSet where the fetch buffer starts */
    private int numFetchedRows;

    /**
     * Fetch buffer that provides a source of rows to this ResultSet.
     *
     * The FetchBuffer class is different conceptually from the ScrollWindow class.
     * The latter provides indexing and arbitrary scrolling over rows provided by the
     * fetch buffer.  The fetch buffer itself just provides the rows and supports
     * rewinding back to the start of the buffer.  When server cursors are involved,
     * the fetch buffer is typically the same size as the scroll window.  However,
     * with client side scrollable cursors, the fetch buffer would contain all of
     * the rows in the result set, but the scroll window would only contain some
     * of them (determined by ResultSet.setFetchSize).
     *
     * The fetch buffer contains 0 or more ROW tokens followed by a
     * DONE (cmd=SELECT, 0xC1) token indicating the number of rows
     * in the fetch buffer.
     *
     * For client-cursored result sets, the fetch buffer contains all of
     * the rows in the result set, and the DONE token indicates the total
     * number of rows in the result set, though we don't use that information,
     * as we always count rows as we encounter them.
     */
    private final class FetchBuffer
    {
        private final class FetchBufferTokenHandler extends TDSTokenHandler
        {
            FetchBufferTokenHandler()
            {
                super("FetchBufferTokenHandler");
            }

            // Even though the cursor fetch RPC call specified the "no metadata" option,
            // the server still returns a COLMETADATA_TOKEN containing the magic NoMetaData
            // value that we need to read through.
            boolean onColMetaData(TDSReader tdsReader) throws SQLServerException
            {
                (new StreamColumns(Util.shouldHonorAEForRead(stmt.stmtColumnEncriptionSetting, stmt.connection))).setFromTDS(tdsReader);
                return true;
            }

            boolean onRow(TDSReader tdsReader) throws SQLServerException
            {
                ensureStartMark();

                // Consume the ROW token, leaving tdsReader at the start of
                // this row's column values.
                if (TDS.TDS_ROW != tdsReader.readUnsignedByte()) assert false;
                fetchBufferCurrentRowType = RowType.ROW;
                return false;
            }

            boolean onNBCRow(TDSReader tdsReader) throws SQLServerException
            {
                ensureStartMark();

                // Consume the NBCROW token, leaving tdsReader at the start of
                // nullbitmap.
                if (TDS.TDS_NBCROW != tdsReader.readUnsignedByte()) assert false;
                
                fetchBufferCurrentRowType = RowType.NBCROW;
                return false;
            }

            boolean onDone(TDSReader tdsReader) throws SQLServerException
            {
                ensureStartMark();

                // Consume the done token
                StreamDone doneToken = new StreamDone();
                doneToken.setFromTDS(tdsReader);

                // Done with all the rows in this fetch buffer and done with parsing
                // unless it's a server cursor, in which case there is a RETSTAT and
                // another DONE token to follow.
                done = true;
                return 0 != serverCursorId;
            }

            boolean onRetStatus(TDSReader tdsReader) throws SQLServerException
            {
                // Check the return status for the bit indicating that
                // "counter-intuitive" cursor behavior has happened and
                // that a fixup is necessary.
                StreamRetStatus retStatusToken = new StreamRetStatus();
                retStatusToken.setFromTDS(tdsReader);
                needsServerCursorFixup = (2 == retStatusToken.getStatus());
                return true;
            }


            void onEOF(TDSReader tdsReader) throws SQLServerException
            {
                super.onEOF(tdsReader);
                done = true;
            }
        }

        private final FetchBufferTokenHandler fetchBufferTokenHandler = new FetchBufferTokenHandler();

        /** Location in the TDS response of the start of the fetch buffer */
        private TDSReaderMark startMark;
        final void clearStartMark() { startMark = null; }

        private RowType fetchBufferCurrentRowType = RowType.UNKNOWN;
        private boolean done;
        private boolean needsServerCursorFixup;
        final boolean needsServerCursorFixup() { return needsServerCursorFixup; }

        FetchBuffer()
        {
            init();
        }

        final void ensureStartMark()
        {
            if (null == startMark && !isForwardOnly())
            {
                if(logger.isLoggable(java.util.logging.Level.FINEST))
                    logger.finest(toString() + " Setting fetch buffer start mark");

                startMark = tdsReader.mark();
            }
        }

        /**
         * Repositions the fetch buffer back to the beginning.
         */
        final void reset()
        {
            assert null != tdsReader;
            assert null != startMark;

            tdsReader.reset(startMark);
            fetchBufferCurrentRowType = RowType.UNKNOWN;
            done = false;
        }

        /**
         * Initializes the fetch buffer with new contents and optionally sets a
         * TDSReaderMark at the start of the fetch buffer to allow the fetch buffer
         * to be scrolled back to the beginning.
         */
        final void init()
        {
            startMark = (0 == serverCursorId && !isForwardOnly()) ? tdsReader.mark() : null;
            fetchBufferCurrentRowType = RowType.UNKNOWN;
            done = false;
            needsServerCursorFixup = false;
        }

        /**
         * Moves to the next row in the fetch buffer.
         */
        final RowType nextRow() throws SQLServerException
        {
        	fetchBufferCurrentRowType = RowType.UNKNOWN;

            while (null != tdsReader && !done && fetchBufferCurrentRowType.equals(RowType.UNKNOWN))
                TDSParser.parse(tdsReader, fetchBufferTokenHandler);

            if (fetchBufferCurrentRowType.equals(RowType.UNKNOWN) && null != fetchBufferTokenHandler.getDatabaseError())
            {
                SQLServerException.makeFromDatabaseError(
                    stmt.connection,
                    null,
                    fetchBufferTokenHandler.getDatabaseError().getMessage(),
                    fetchBufferTokenHandler.getDatabaseError(),
                    false);
            }

            return fetchBufferCurrentRowType;
        }
    }

        private final class CursorFetchCommand extends TDSCommand
        {
            private final int serverCursorId;
            private int fetchType;
            private int startRow;
            private int numRows;

            CursorFetchCommand(
                int serverCursorId,
                int fetchType,
                int startRow,
                int numRows)
            {
                super("doServerFetch", stmt.queryTimeout);
                this.serverCursorId = serverCursorId;
                this.fetchType = fetchType;
                this.startRow = startRow;
                this.numRows = numRows;
            }

            final boolean doExecute() throws SQLServerException
            {
                TDSWriter tdsWriter = startRequest(TDS.PKT_RPC);
                tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs
                tdsWriter.writeShort(TDS.PROCID_SP_CURSORFETCH);
                tdsWriter.writeByte(TDS.RPC_OPTION_NO_METADATA);
                tdsWriter.writeByte((byte) 0);  // RPC procedure option 2
                tdsWriter.writeRPCInt(null, new Integer(serverCursorId), false);
                tdsWriter.writeRPCInt(null, new Integer(fetchType), false);
                tdsWriter.writeRPCInt(null, new Integer(startRow), false);
                tdsWriter.writeRPCInt(null, new Integer(numRows), false);

                // To free up the thread on the server that is feeding us these results,
                // read the entire response off the wire UNLESS this is a forward only
                // updatable result set AND responseBuffering was explicitly set to adaptive
                // at the Statement level.  This override is the only way that apps
                // can do a forward only updatable pass through a ResultSet with large
                // data values.
                tdsReader = startResponse(
                    isForwardOnly() &&
                    CONCUR_READ_ONLY != stmt.resultSetConcurrency &&
                    stmt.getExecProps().wasResponseBufferingSet() &&
                    stmt.getExecProps().isResponseBufferingAdaptive());

                return false;
            }

            final void processResponse(TDSReader responseTDSReader) throws SQLServerException
            {
                tdsReader = responseTDSReader;
                discardFetchBuffer();
            }
        }

    /**
     * Position a server side cursor.
     *
     * @param fetchType The type of fetch
     * @param startRow The starting row
     * @param numRows The number of rows to fetch
     * @exception SQLServerException The cursor was invalid.
     */
    final void doServerFetch(int fetchType, int startRow, int numRows) throws SQLServerException
    {
        if(logger.isLoggable(java.util.logging.Level.FINER))
            logger.finer(toString() + " fetchType:" + fetchType + " startRow:" + startRow + " numRows:" + numRows);

        // Discard the current fetch buffer contents
        discardFetchBuffer();

        // Reinitialize the fetch buffer
        fetchBuffer.init();

        // Fetch the requested block of rows from the server
        CursorFetchCommand cursorFetch = new CursorFetchCommand(serverCursorId, fetchType, startRow, numRows);
        stmt.executeCommand(cursorFetch);

        numFetchedRows = 0;
        resultSetCurrentRowType = RowType.UNKNOWN;
        areNullCompressedColumnsInitialized = false;
        lastColumnIndex = 0;

        // If necessary, resize the scroll window to the new fetch size
        if (null != scrollWindow && TDS.FETCH_REFRESH != fetchType)
            scrollWindow.resize(fetchSize);

        // Correct for SQL Server's "counter-intuitive" behavior which positions the cursor
        // on the first row of the result set when a negative move would have logically
        // positioned the cursor before the first row instead.  When this happens, the server
        // returns the first block of rows, which is indistinguishable from a regular request
        // for the first block of rows except for a flag set in the return status to indicate
        // what happened.  When this behavior does happen, force the cursor to move to before
        // the first row.  See the Engine Cursors Functional Specification for all the details....
        if (numRows < 0 || startRow < 0)
        {
            // Scroll past all the returned rows, caching in the scroll window as we go.
            try
            {
                while (scrollWindow.next(this))
                    ;
            }
            catch (SQLException e)
            {
                // If there is a row error in the results, don't throw an exception from here.
                // Ignore it for now and defer the exception until the app encounters the
                // error through normal cursor movement.
                if(logger.isLoggable(java.util.logging.Level.FINER))
                    logger.finer(toString() +" Ignored exception from row error during server cursor fixup: " + e.getMessage());
            }

            // Force the cursor to move to before the first row if necessary.
            if (fetchBuffer.needsServerCursorFixup())
            {
                doServerFetch(TDS.FETCH_FIRST, 0, 0);
                return;
            }

            // Put the scroll window back before the first row.
            scrollWindow.reset();
        }
    }

    /**
     * Discards the contents of the current fetch buffer.
     *
     * This method ensures that the contents of the current fetch buffer have
     * been completely read from the TDS channel, processed, and discarded.
     *
     * Note that exceptions resulting from database errors, such as row errors
     * or transaction rollbacks, and from I/O errors, such as a closed connection,
     * are caught, logged, and ignored.  The expectation is that callers of this
     * method just want the fetch buffer cleared out and do not care about what
     * errors may have occurred when it was last populated.  If the connection is
     * closed while discarding the fetch buffer, then the fetch buffer is considered
     * to be discarded.
     */
    private final void discardFetchBuffer()
    {
        // Clear the TDSReader mark at the start of the fetch buffer
        fetchBuffer.clearStartMark();

        // Clear all row TDSReader marks in the scroll window
        if (null != scrollWindow)
            scrollWindow.clear();

        // Once there are no TDSReader marks left referring to the fetch buffer
        // contents, process the remainder of the current row and all subsequent rows.
        try
        {
            while (fetchBufferNext())
                ;
        }
        catch (SQLServerException e)
        {
            if (logger.isLoggable(java.util.logging.Level.FINER))
                logger.finer(this + " Encountered exception discarding fetch buffer: " + e.getMessage());
        }
    }

  /**
   * Close a server side cursor and free up its resources in the database.
   *
   * If closing fails for any reason then the cursor is considered closed.
   */
  final void closeServerCursor()
  {
    if (0 == serverCursorId)
      return;

    // If the connection is already closed, don't bother trying to close the server cursor.
    // We won't be able to, and it's already closed on the server anyway.
    if (stmt.connection.isSessionUnAvailable())
    {
      if (logger.isLoggable(java.util.logging.Level.FINER))
        logger.finer(this + ": Not closing cursor:" + serverCursorId + "; connection is already closed.");
    }
    else
    {
      if(logger.isLoggable(java.util.logging.Level.FINER))
        logger.finer(toString() +" Closing cursor:"+serverCursorId);

      final class CloseServerCursorCommand extends UninterruptableTDSCommand
      {
        CloseServerCursorCommand()
        {
          super("closeServerCursor");
        }

        final boolean doExecute() throws SQLServerException
        {
          TDSWriter tdsWriter = startRequest(TDS.PKT_RPC);
          tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs
          tdsWriter.writeShort(TDS.PROCID_SP_CURSORCLOSE);
          tdsWriter.writeByte((byte) 0);  // RPC procedure option 1
          tdsWriter.writeByte((byte) 0);  // RPC procedure option 2
          tdsWriter.writeRPCInt(null, new Integer(serverCursorId), false);
          TDSParser.parse(startResponse(), getLogContext());
          return true;
        }
      }

      // Try to close the server cursor.  Any failure is caught, logged, and ignored.
      try
      {
        stmt.executeCommand(new CloseServerCursorCommand());
      }
      catch (SQLServerException e)
      {
        if(logger.isLoggable(java.util.logging.Level.FINER))
          logger.finer(toString() +" Ignored error closing cursor:"+serverCursorId + " " + e.getMessage());
      }

      if(logger.isLoggable(java.util.logging.Level.FINER))
        logger.finer(toString() +" Closed cursor:"+serverCursorId);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy