///////////////////////////////////////////////////////////////////////////////
//                                                                             
// JTOpen (IBM Toolbox for Java - OSS version)                                 
//                                                                             
// Filename: AS400JDBCResultSet.java
//                                                                             
// The source code contained herein is licensed under the IBM Public License   
// Version 1.0, which has been approved by the Open Source Initiative.         
// Copyright (C) 1997-2010 International Business Machines Corporation and     
// others. All rights reserved.                                                
//                                                                             
///////////////////////////////////////////////////////////////////////////////

package com.ibm.as400.access;

import java.io.InputStream;
import java.io.IOException;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DataTruncation;
import java.sql.Date;
/* ifdef JDBC40 
import java.sql.NClob;
endif */ 
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
/* ifdef JDBC40 
import java.sql.RowId;
endif */ 
import java.sql.SQLException;
import java.sql.SQLWarning;
/* ifdef JDBC40 
import java.sql.SQLXML;
endif */ 
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
/* ifdef JDBC40
import java.sql.Types;
endif */ 
import java.util.Calendar;
import java.util.Map;

/* ifdef JDBC42
import java.sql.SQLType; 
import java.sql.JDBCType; 
import java.sql.SQLFeatureNotSupportedException;
endif */


/**
<p>The AS400JDBCResultSet class provides access to a table
of data generated by a database query.

<p>A result set maintains a cursor pointing to its current
row of data.  Initially, the cursor is positioned before the
first row.  If the result set is scrollable, use any of the
cursor positioning methods to move the cursor within the result
set.  If the result set is not scrollable, then only use next()
to move the cursor.
           
<p>The get methods retrieve column values for the current row.
Values can be retrieved using either the column index or the
column name.  In general, using the column index is more efficient.
Column indexes are numbered starting with 1.  Column names are
not case sensitive.  If several columns have the same name,
then the first matching column is used.  

<p>Columns can have two names: a column name ("long name")
and a system column name ("short name").  The get methods and
findColumn() only support using the column name.

<p>In each get method, the driver attempts to convert the
underlying data to the specified Java type and returns a
suitable Java value.  If such a conversion is not appropriate,
an SQLException is thrown.

<p>If the result set is updatable, the update methods modify
column values for the current row, but not in the underlying
database.  updateRow() causes all updates to the current row
to be written to the database.  Use deleteRow() to delete the
current row in the database.

<p>For updatable result sets, there is also an insert row,
which is used as a staging area for the contents of a new row.
Use moveToInsertRow() to position the cursor to the insert row.
Once all updates to the insert row have been made, use insertRow()
to insert the row into the database.

<p>In the following cases, result sets are always read only
regardless of the concurrency set in the statement:
<ul>
<li>Stored procedure calls
<li>DatabaseMetaData catalog methods
</ul>

<p>In the following case, result sets are always read only 
regardless of the concurrency set in the statement if connecting 
to a system running OS/400 V4R5 or a previous release:
<ul>
<li>SELECT statements which do not specify FOR UPDATE
</ul>

<p>In the following case, result sets are always forward only
regardless of the type set in the statement:
<ul>
<li>Stored procedure calls
</ul>

<p>A result set is automatically closed by the statement that
generated it when the statement is closed, run again, or used
to retrieve the next result set from a sequence of multiple
result sets.

<p>The new JDBC 3.0 methods add the ability to 
retrieve information by column name in addition to column index.
Be aware you will see better performance accessing columns by their
index rather than accessing them by their name.
**/
//
// Implementation notes:
//
// 1. There are a few different types of result sets.  For example:
//
//    * Result sets from caller-issued selects.
//    * Result sets created and returned from DatabaseMetaData.
//    * Result sets generated on the IBM i system and mapped to
//      a different format by DatabaseMetaData.
//
//    One solution would be to provide a different implementation
//    of java.sql.ResultSet for each of these.  However, there is
//    a lot of overhead that is common to all of these.  As a result,
//    I have decided to use one implementation of java.sql.ResultSet
//    and write in terms of the following interfaces, which pinpoint
//    what is truly different about the different formats:
//
//    * JDRowCache - manages the set of rows and fetches as needed.
//    * JDRow - accesses various information about the format
//              of a row and manages the getting and setting
//              of data within a row.
//
//    There are implementations of each of these to handle the
//    different types of result sets.
//
// 2. We need to know the total number of rows in the result set
//    in order to make getRow() work in all cases (e.g. after
//    a last() or absolute(-).  In mod 5 the code was changed to
//    loop through the rows if we need a count.  This will be
//    slow but seemed to be the best way to do it.  
//    The mod 4 comment is:
//         The only way we could think of
//         to do this is to issue a SELECT COUNT(*) using the same
//         where clause as the original.  However there are 2 problems:
//
//         * There is a window of time between the original query
//           and the SELECT COUNT(*), so the value may not be
//           accurate.
//         * There is overhead in issuing another SELECT and getRow()
//           seems like it probably won't be used that often.
//
//         Given these problems, I have decided to make getRow() not
//         work in some documented cases.
//
// 3. In JDBC 2.0, there are some date/time/timestamp related
//    methods that take calendar parameters and some that don't.
//    The methods that do not take calendar parameters are supposed
//    to use the default calendar (retrieved using
//    AS400Calendar.getGregorianInstance()).
//
//    At first thought, I tried to create one static calendar
//    object to share for the entire JDBC driver, thinking that
//    this would minimize object creation and therefore improve
//    performance.  However, it turns out that this shared instance
//    does not reflect TimeZone changes made after it is created,
//    so the very example given in the spec does not work.  As a
//    result, we must create a new default Calendar each time.
//
public class AS400JDBCResultSet 
/* ifdef JDBC40 
extends ToolboxWrapper
endif */ 

implements ResultSet
{
    static final String copyright = "Copyright (C) 1997-2010 International Business Machines Corporation and others.";


    //New constants for JDBC 3.0.
    static final int HOLDABILITY_NOT_SPECIFIED = -9999;  //@G4A
    static final int HOLD_CURSORS_OVER_COMMIT = 1;       //@G4A
    static final int CLOSE_CURSORS_AT_COMMIT = 2;        //@G4A

    
    // Private data.
    private String                      catalog_;
    private boolean                     closed_;
    private int                         columnCount_;
    private int                         concurrency_;
    private AS400JDBCConnection         connection_;
    private String                      correlationName_;
    private String                      cursorName_;
    private boolean                     dataTruncation_;    // @B2A
    private PreparedStatement           deleteStatement_;
    private int                         fetchDirection_;
    private int                         fetchSize_;
    private AS400JDBCStatementLock      internalLock_;      // @D1A @C7C
    private int                         maxRows_;
    private InputStream                 openInputStream_;
    private Reader                      openReader_;
    private JDRow                       row_;
    private JDRowCache                  rowCache_;
    private String                      selectTable_;
    private SQLWarning                  sqlWarning_;
    private AS400JDBCStatement          statement_;
    private int                         type_;
    private boolean[]                   updateNulls_;
    private boolean[]                   updateDefaults_;    //@EIA
    private boolean[]                   updateUnassigned_;  //@EIA
    private JDRow                       updateRow_;
    private boolean[]                   updateSet_;
    private boolean                     wasNull_;
    private boolean                     wasDataMappingError_;
    boolean                             isMetadataResultSet = false; //@mdrs
    private DBReplyRequestedDS          reply_ = null; 
    private Class                       byteArrayClass_ = null; 
    private SQLException                savedException_;    /* Saved exception from combined open/fetch @F3A*/
    /* extendedColumnDescriptors need to be set with the result set from the time of creation, if possible */
    /* instead of being retrieved from the statement at the time of getRSMD  @P6A*/ 
    
    DBExtendedColumnDescriptors extendedDescriptors_; 
    SQLConversionSettings settings_;  /*@Q8A*/
    /*---------------------------------------------------------*/
    /*                                                         */
    /* MISCELLANEOUS METHODS.                                  */
    /*                                                         */
    /*---------------------------------------------------------*/



    /**
    Constructs an AS400JDBCResultSet object.
    
    @param  statement       The owning statement.
    @param  sqlStatement    The SQL statement.
    @param  rowCache        The row cache.
    @param  catalog         The catalog.
    @param  cursorName      The cursor name.
    @param  maxRows         The maximum rows limit, or
                            0 for no limit.
    @param  type            The type.
    @param  concurrency     The concurrency.
    @param  fetchDirection  The fetch direction.
    @param  fetchSize       The fetch size.
    @param  tableName       The table name, if any.
    
    @exception              SQLException    If an error occurs.
    **/
    AS400JDBCResultSet (AS400JDBCStatement statement,
                        JDSQLStatement sqlStatement,
                        JDRowCache rowCache,
                        String catalog,
                        String cursorName,
                        int maxRows,
                        int type,
                        int concurrency,
                        int fetchDirection,
                        int fetchSize,
                        DBExtendedColumnDescriptors extendedDescriptors) /*@P6A*/
    throws SQLException
    {
        // Initialization.
        catalog_                = catalog;
        closed_                 = false;
        concurrency_            = concurrency;
        connection_             = (AS400JDBCConnection) ((statement != null) ? statement.getConnection () : null);
        if (connection_ != null) {
          settings_               = SQLConversionSettings.getConversionSettings ((AS400JDBCConnection) connection_); /*@Q8A*/
        } else {
          settings_ = null; 
        }

        cursorName_             = cursorName;
        deleteStatement_        = null;
        fetchDirection_         = fetchDirection;
        fetchSize_              = fetchSize;
        internalLock_           = (statement != null) ? statement.internalLock_ : new AS400JDBCStatementLock();  // @D1A
        maxRows_                = maxRows;
        openInputStream_        = null;
        openReader_             = null;
        row_                    = rowCache.getRow ();
        rowCache_               = rowCache;
        sqlWarning_             = null;
        statement_              = statement;
        type_                   = type;
        wasNull_                = false;
        wasDataMappingError_    = false;

        columnCount_            = row_.getFieldCount ();
        
        /* @D9A Make sure that warning are provided to this result set object */ 
        rowCache_.setResultSet(this); 
        rowCache_.open ();
        extendedDescriptors_ = extendedDescriptors; /*@P6A*/
        
        // If no connection or SQL statement was provided,
        // or a SELECT with multiple tables or views was
        // specified, or the SELECT does not specify FOR UPDATE,
        // then we cannot do updates.  (@J3 In case you have
        // paraenthesis overload, the added check in mod 5
        // is if we are connected to a v5r1 (without PTF) or earlier 
        // system and "for update" is not specified)
        if((connection_  == null) ||
           (sqlStatement == null) ||
           (((((AS400JDBCConnection) connection_).getMustSpecifyForUpdate()) &&   // @J3a @J31c
             (! sqlStatement.isForUpdate()))))
        {
            selectTable_        = null;
            correlationName_    = null;
            concurrency_        = CONCUR_READ_ONLY;               
        }
        else
        {
            selectTable_        = sqlStatement.getSelectTable ();
            correlationName_    = sqlStatement.getCorrelationName ();
        }

        // Initialize the update row.
        if(concurrency_ == CONCUR_UPDATABLE)
        {
            updateRow_              = new JDSimpleRow (row_, true);
            updateSet_              = new boolean[columnCount_];
            updateNulls_            = new boolean[columnCount_];
            updateDefaults_         = new boolean[columnCount_];    //@EIA
            updateUnassigned_       = new boolean[columnCount_];    //@EIA
            for(int i = 0; i < columnCount_; ++i)
            {
                updateSet_[i]       = false;
                updateNulls_[i]     = true;                       //@EIC not needed since updateSet[] is checked first //@EIC2 initialize all to null for insert row logic 
            }
        }

        // Initialize the data truncation.                                             @B2A
        if(connection_ != null)                                                    // @B2A
            dataTruncation_ = ((AS400JDBCConnection) connection_).getProperties ().getBoolean (JDProperties.DATA_TRUNCATION); // @B2A
        else                                                                        // @B2A
            dataTruncation_ = false;

        // Trace messages.
        if(JDTrace.isTraceOn())
        {
            JDTrace.logOpen (this, statement_);                           // @J33a
            JDTrace.logProperty (this, "AS400JDBCResultSet", "Conncurrency", concurrency_);
            JDTrace.logProperty (this, "AS400JDBCResultSet", "Fetch direction", fetchDirection_);
            JDTrace.logProperty (this, "AS400JDBCResultSet", "Fetch size", fetchSize_);
            JDTrace.logProperty (this, "AS400JDBCResultSet", "Max rows", maxRows_);
            JDTrace.logProperty (this, "AS400JDBCResultSet", "Type", type_);
        }
    }



    /**
    Constructs an AS400JDBCResultSet object.
    
    @param  rowCache        The row cache.
    @param  catalog         The catalog.
    @param  cursorName      The cursor name.
    @param  reply           Reply object that must be returned to pool when result set closed 
    
    @exception              SQLException    If an error occurs.
    **/
    //
    // This constructor is specifically for DatabaseMetaData
    // result sets.
    //
    AS400JDBCResultSet (JDRowCache rowCache,
                        String catalog,
                        String cursorName,
                        AS400JDBCConnection con, 
                        DBReplyRequestedDS reply)  //@in2
    throws SQLException
    {
        this (null, null, rowCache, catalog, cursorName, 0,
              TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY,
              FETCH_FORWARD, 0, (reply == null) ? null : reply.getExtendedColumnDescriptors()); /*@P6C*/

    	this.reply_ = reply; 

        //connection is needed in AS400JDBCResultsetMetadata.  connection is passed in from AS400JDBCDatabaseMetaData
        if(con != null)         //@in2
            connection_ = con;  //@in2
    }



    /**
    Checks that the result set is open.  Public methods
    that require an open result set should call this first.
    
    @exception  SQLException    If the result set is not open.
    **/
    void checkOpen ()
    throws SQLException
    {
        if(closed_)
            JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
    }



    /**
    Clears any information associated with the current row.
    In addition, all warnings are cleared.
    **/
    private void clearCurrentRow ()
    throws SQLException
    {
        clearCurrentValue ();
        clearWarnings ();

        if(concurrency_ == CONCUR_UPDATABLE)
        {
            for(int i = 0; i < columnCount_; ++i)
            {
                updateNulls_[i]  = true;        //@IEC //@EIC2 
                updateDefaults_[i] = false;      //@EIA
                updateUnassigned_[i] = false;    //@EIA
                updateSet_[i]    = false;
            }
        }
    }



    /**
    Clears any information associated with the current value.
    **/
    private void clearCurrentValue ()
    {
        // Implicitly close the InputStream if left open.
        if(openInputStream_ != null)
        {
            try
            {
                openInputStream_.close ();
            }
            catch(IOException e)
            {
                // Ignore the exception.              
            }
            openInputStream_ = null;
        }

        // Implicitly close the InputStream if left open.
        if(openReader_ != null)
        {
            try
            {
                openReader_.close ();
            }
            catch(IOException e)
            {
                // Ignore the exception.           
            }
            openReader_ = null;
        }
    }




    /**
    Clears all warnings that have been reported for the result set.
    After this call, getWarnings() returns null until a new warning
    is reported for the result set.
    
    @exception SQLException If an error occurs.
    **/
    public void clearWarnings ()
    throws SQLException
    {
        sqlWarning_ = null;
    }



    /**
    Releases the result set's resources immediately instead of
    waiting for them to be automatically released.
    
    @exception SQLException If an error occurs.
    **/
    public void close ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // If this is already closed, then just do nothing.
            // 
            // The spec does not define what happens when a connection
            // is closed multiple times.  The official word from the Sun 
            // JDBC team is that "the driver's behavior in this case 
            // is implementation defined.   Applications that do this are 
            // non-portable." 
            if(isClosed ())
                return;

            rowCache_.close ();
            if (reply_ != null) { reply_.returnToPool(); reply_ = null; }
            closed_ = true;
            if(statement_ != null)
                statement_.notifyClose ();

            // Close the delete statement if opened.
            if(deleteStatement_ != null)
                deleteStatement_.close ();

            if(isMetadataResultSet == true)  //@mdclose
                statement_.close();          //@mdclose
            
            if(JDTrace.isTraceOn())
                JDTrace.logClose (this);
        }
    }



    /**
    Closes the result set if not explicitly closed by the caller.
    
    @exception   Throwable      If an error occurs.
    **/
    protected void finalize ()
    throws Throwable
    {
        try{
            if(! closed_) {
            	JDTrace.logInformation (this, "WARNING: Finalizer thread closing result set object.");
            	close ();
            }
        }
        catch(Exception e){
            //catch any exceptions and don't throw them
        }
        super.finalize ();
    }



    /**
    Returns the column index for the specified column name.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.findColumn("\"MixedCase\"").
    
    @param      columnName      The column name.
    @return                     The column index (1-based).
    
    @exception  SQLException    If the result set is not open
                                or the column name is not found.
    **/
    public int findColumn (String columnName)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            checkOpen ();
            return row_.findField ((columnName != null) ? columnName : "");
        }
    }



    // JDBC 2.0
    /**
    Returns the result set concurrency.
    
    @return The result set concurrency. Valid values are:
                                    <ul>
                                      <li>CONCUR_READ_ONLY
                                      <li>CONCUR_UPDATABLE
                                    </ul>
    
    
    @exception SQLException If the result set is not open.
    **/
    public int getConcurrency ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            checkOpen ();
            
            //@cur return value from cursor attribues if exists else return value as done in pre 550
            if ( statement_ != null )                                            //@cur
            {                                                                    //@cur
                if( statement_.cursor_.getCursorAttributeUpdatable() == 0)       //@cur
                    return ResultSet.CONCUR_READ_ONLY;                           //@cur
                else if( statement_.cursor_.getCursorAttributeUpdatable() == 1)  //@cur
                    return ResultSet.CONCUR_UPDATABLE;                           //@cur
                else                                                             //@cur
                    return concurrency_;                                         //@cur
            }                                                                    //@cur
            else                                                                 //@cur
                return concurrency_;
        }
    }



    // @D3C
    /**
    Returns the name of the SQL cursor in use by the result set.
    In SQL, results are retrieved through a named cursor.  The
    current row of a result can be updated or deleted using a
    positioned UPDATE or DELETE statement that references a
    cursor name.
           
    <p>Cursor names are case sensitive.  However, when using a cursor
    name within other SQL positioned UPDATE or DELETE statements,
    the cursor name will be uppercased.  If you use a cursor name
    with lowercase characters, you need to enclose it in double
    quotes when referring to it in other SQL statements.
    
    @return     The cursor name.
    
    @exception  SQLException    If the result is not open.
    **/
    public String getCursorName ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            checkOpen ();
            return cursorName_;
        }
    }



    // JDBC 2.0
    /**
    Returns the fetch direction.
    
    @return The fetch direction. 
            Valid values are:
                                <ul>
                                  <li>FETCH_FORWARD
                                  <li>FETCH_REVERSE
                                  <li>FETCH_UNKNOWN
                                </ul>
    
    
    
    @exception  SQLException    If the result is not open.
    **/
    public int getFetchDirection ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            checkOpen ();
            return fetchDirection_;
        }
    }



    // JDBC 2.0
    /**
    Returns the fetch size.
    
    @return The fetch size.
    
    @exception  SQLException    If the result is not open.
    **/
    public int getFetchSize ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            checkOpen ();
            return fetchSize_;
        }
    }



    /**
    Returns the row cache.
    
    @return     The row cache.
    **/
    JDRowCache getRowCache ()
    {
        return rowCache_;
    }



    // JDBC 2.0
    /**
    Returns the statement for this result set.
    
    @return The statement for this result set, or null if the
            result set was returned by a DatabaseMetaData
            catalog method.
    
    @exception SQLException If an error occurs.
    **/
    // Implementation note:
    //
    // * I made a conscious decision not to return the
    //   DatabaseMetaData's statement, if any, since I do
    //   not want users to be able to execute their own
    //   statements using this.
    //
    public Statement getStatement ()
    throws SQLException
    {
        if(isMetadataResultSet)//@mdrs
            return null;       //@mdrs
        else                   //@mdrs
            return statement_;
    }



    // JDBC 2.0
    /**
    Returns the result set type.  If the statement requested a result set type 
    ResultSet.TYPE_FORWARD_ONLY, then the result set type will be 
    ResultSet.TYPE_FORWARD_ONLY.  Otherwise, the result set type may be a type
    other than the requested type if the SQL statement that generated the 
    result set specified a different cursor type when opening the cursor.  
    
    @return The result set type. Valid values are:
                                    <ul>
                                      <li>TYPE_FORWARD_ONLY
                                      <li>TYPE_SCROLL_INSENSITIVE
                                      <li>TYPE_SCROLL_SENSITIVE
                                    </ul>
    
    
    
    @exception SQLException If the result set is not open.
    @since Modification 5
    **/
    public int getType ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            checkOpen ();

            // Always return FORWARD_ONLY if the application requested forward only
            // If this logic changes, also change the similar logic in AS400JDBCStatement. @C4A
            if (type_ == ResultSet.TYPE_FORWARD_ONLY) return ResultSet.TYPE_FORWARD_ONLY; 
            
            //@cur return value from cursor attributes if exists else return value as done in pre 550                                                               
            if( statement_ != null )                                                     //@cur
            {                                                                            //@cur
                if(statement_.cursor_.getCursorAttributeScrollable() == 0)               //@cur
                    return ResultSet.TYPE_FORWARD_ONLY;                                  //@cur
                else if(statement_.cursor_.getCursorAttributeSensitive() == 0)           //@cur
                    return ResultSet.TYPE_SCROLL_INSENSITIVE;                            //@cur
                else if(statement_.cursor_.getCursorAttributeSensitive() == 1)           //@cur
                    return ResultSet.TYPE_SCROLL_SENSITIVE;                              //@cur
                else                                                                     //@cur
                    return type_;                                                        //@cur
            }                                                                            //@cur
            else                                                                         //@cur
                return type_;
        }
    }



    //@G4A JDBC 3.0
    /**
    Returns the value of an SQL DATALINK output parameter as a
    java.net.URL object.
        
    @param  columnIndex     The column index (1-based).
    @return                 The parameter value or null if the value is SQL NULL.
        
    @exception  SQLException    If the statement is not open,
                                the index is not valid, the parameter name is
                                not registered as an output parameter,
                                the statement was not executed or
                                the requested conversion is not valid.
    @since Modification 5
    **/
    public URL getURL (int columnIndex)
    throws SQLException   
    {
        synchronized(internalLock_)
        {
            checkOpen ();
            try
            {   String string = getString(columnIndex);
                if(string == null)
                    return null;
                return new java.net.URL(string);
            }
            catch(MalformedURLException e)
            {
                // To be consistent with other testcases where the type does not match,
                // return a data type mismatch. 
                JDError.throwSQLException (JDError.EXC_DATA_TYPE_MISMATCH, e);
                return null;
            }
        }
    }



    //@G4A JDBC 3.0
    /**
    Returns the value of an SQL DATALINK output parameter as a
    java.net.URL object.
        
    @param  columnName      The column name.
    @return                 The parameter value or null if the value is SQL NULL.
        
    @exception  SQLException    If the statement is not open,
                                the index is not valid, the parameter name is
                                not registered as an output parameter,
                                the statement was not executed or
                                the requested conversion is not valid.
    **/
    public URL getURL (String columnName)
    throws SQLException
    {
        return getURL(findColumn(columnName));
    }



    /**
    Returns the first warning reported for the result set.
    Subsequent warnings may be chained to this warning.
    
    @return     The first warning or null if no warnings
                have been reported.
    
    @exception  SQLException    If an error occurs.
    **/
    public SQLWarning getWarnings ()
    throws SQLException
    {
        return sqlWarning_;
    }



    /**
    Indicates if the result set is closed.
    
    @return     true if this result set is closed;
                false otherwise.
    **/
    //@PDA jdbc40 make public and allow SQLException
    public boolean isClosed () throws SQLException
    {
        return closed_;
    }



    /**
    Posts a warning for this result set.
    
    @param   sqlWarning  The warning.
    **/
    void postWarning (SQLWarning sqlWarning)
    {
    	/*Check to see if the warning should be ignored @Q1A*/
        if ((statement_ != null) && 
            (statement_.connection_!= null) && 
            (statement_.connection_.ignoreWarning(sqlWarning))) {
           return; 
        } else { 
        if(sqlWarning_ == null)
            sqlWarning_ = sqlWarning;
        else
            sqlWarning_.setNextWarning (sqlWarning);
        } 
    }



    // JDBC 2.0
    /**
    Sets the direction in which the rows in a result set are
    processed.
    
    @param      fetchDirection  The fetch direction for processing rows.
                                Valid values are:
                                <ul>
                                  <li>FETCH_FORWARD
                                  <li>FETCH_REVERSE
                                  <li>FETCH_UNKNOWN
                                </ul>
                                The default is the statement's fetch
                                direction.
    
    @exception          SQLException    If the result set is not open,
                                        the result set is scrollable
                                        and the input value is not
                                        ResultSet.FETCH_FORWARD,
                                        or the input value is not valid.
    **/
    //
    // Implementation note:
    //
    // The fetch direction is intended to be a hint for the driver
    // to do some optimization (like fetch size helps with record
    // blocking).  However, we currently don't do anything with it.
    // I attempted to document this fact in the javadoc, but could
    // not come up with a wording that is not confusing.  I think it
    // is okay NOT to document the fact that we ignore this setting,
    // since it would not affect the behavior of the driver anyway.
    //
    public void setFetchDirection (int fetchDirection)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A //@cur
            if(((fetchDirection != FETCH_FORWARD)
                && (fetchDirection != FETCH_REVERSE)
                && (fetchDirection != FETCH_UNKNOWN))
               || ((getType() == ResultSet.TYPE_FORWARD_ONLY)
                   && (fetchDirection != ResultSet.FETCH_FORWARD)))
                JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);

            checkOpen ();
            fetchDirection_ = fetchDirection;

            if(JDTrace.isTraceOn())
                JDTrace.logProperty (this, "setFetchDirection", "Fetch direction", fetchDirection_);
        }
    }



    // JDBC 2.0
    /**
    Sets the number of rows to be fetched from the database when more
    rows are needed.  This may be changed at any time. If the value
    specified is zero, then the driver will choose an appropriate
    fetch size.
    
    <p>This setting only affects statements that meet the criteria
    specified in the "block criteria" property.  The fetch size
    is only used if the "block size" property is set to "0".
    
    @param fetchSize    The number of rows.  This must be greater than
                        or equal to 0 and less than or equal to the
                        maximum rows limit.  The default is the
                        statement's fetch size.
    
    @exception          SQLException    If the result set is not open
                                        or the input value is not valid.
    **/
    public void setFetchSize (int fetchSize)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            if((fetchSize < 0)
               || ((fetchSize > maxRows_) && (maxRows_ > 0)))
                JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);

            checkOpen ();
            fetchSize_ = fetchSize;

            // This is a kludgy way of keeping the fetch size
            // out of the JDRowCache interface.  It only applies
            // to JDServerRowCache anyway.
            if(rowCache_ instanceof JDServerRowCache)
                ((JDServerRowCache) rowCache_).setFetchSize (fetchSize_);

            if(JDTrace.isTraceOn())
                JDTrace.logProperty (this, "setFetchSize", "Fetch size", fetchSize_);
        }
    }



    /**
    Returns the name of the SQL cursor in use by the result set.
    
    @return     The cursor name.
    **/
    public String toString ()
    {
        return cursorName_;
    }



    /*---------------------------------------------------------*/
    /*                                                         */
    /* CURSOR POSITIONING.                                     */
    /*                                                         */
    /*---------------------------------------------------------*/



    // Private data.
    //
    // Either position from first or last or both is set
    // at any given moment, depending on what we can
    // determine.  Whether we can determine one or both of
    // these depends on how the caller has positioned the
    // cursor.
    //
    // For both of these values, 0 means after the last or
    // before the first.  -1 means not able to determine.
    // @E1: a new constant is added which also means we
    // don't know the value.  -1 is not used because it
    // is easy to incorrectly add 1 to -1 and make it look 
    // like a valid value (and a very hard bug to find).
    // Adding 1 to -9999 results in a strange value which
    // should be easier to debug. 
    //
    // The position insert flag is set when the cursor
    // is moved to the insert row.
    //                            
    // @E1: Fully supporting getRow() means at times
    // looping through the rows to count them.  Two
    // values are added to reduce the amount rows we
    // loop through.  We update highestKnownRow and
    // totalRows whenever possible to reduce the number
    // of rows we loop through.  Once set, these 
    // values do not change.  That means if rows are added      
    // or deleted during the life of the rs, these
    // constants will not reflect the change.  I talked
    // to the developer of the native driver and 
    // he feels it is safe (and much faster) to harden
    // the values once they are set.  The alternative
    // is to create a property where the app can tell us
    // to re-get the total at appropriate times.  The
    // performance of that would probably be unacceptably
    // slow. 
    // 

    private static final int NOT_KNOWN = -9999;                      // @E1a

    private int     positionFromFirst_  = 0;
    private int     positionFromLast_   = -1;
    private boolean positionInsert_     = false;
    private boolean positionValid_      = false;             

    // totalRows_ is the number of rows in the RS.  Highest
    // known row is the biggest row we have reached so far.  Eventually
    // they will be the same but until there is a need to figure
    // out how many rows are in the RS, total will be not-known and
    // highest will increase.
    private int     totalRows_          = NOT_KNOWN;                 // @E1a
    private int     highestKnownRow_    = NOT_KNOWN;                 // @E1a



    // JDBC 2.0
    /**
    Positions the cursor to an absolute row number.
    
    <p>Attempting to move any number of positions before
    the first row positions the cursor to before the first row. 
    Attempting to move beyond the last
    row positions the cursor after the last row.
    
    <p>If an InputStream from the current row is open, it is
    implicitly closed.  In addition, all warnings and pending updates
    are cleared.
    
    @param  rowNumber   The absolute row number.  If the absolute row
                        number is positive, this positions the cursor
                        with respect to the beginning of the result set.
                        If the absolute row number is negative, this
                        positions the cursor with respect to the end
                        of result set.
    @return             true if the requested cursor position is
                        valid; false otherwise.
    
    @exception SQLException  If the result set is not open,
                             the result set is not scrollable,
                             the row number is 0,
                             or an error occurs.
    */
    public boolean absolute (int rowNumber)
    throws SQLException
    {
        synchronized(internalLock_)                                              // @D1A
        {
            // @E2a absolute(0) moves you to before the first row
            if(rowNumber == 0)                                     // @E2a
            {
                // @E2a
                beforeFirst();                                       // @E2a
                return false;                                        // @E2a
            }                                                       // @E2a


            // Initialization.
            beforePositioning (true);
            // @E2d if (rowNumber == 0)                                                    
            // @E2d    JDError.throwSQLException (JDError.EXC_CURSOR_POSITION_INVALID);   

            // Handle max rows.
            // @E3, fixes to correctly handle maxRows,  (1) Make sure
            //      we don't go before first when absolute < 0, and (2) make sure
            //      we get the row number right because the system and row cache
            //      do not deal with maxRows.  They always deal with the entire
            //      result set.  
            //
            //      old code:
            //
            // if ((rowNumber > maxRows_) && (maxRows_ > 0)) 
            // {
            //     afterLast ();
            //     return false;
            // }
            //
            //      new code:
            if(maxRows_ > 0)                                        // @E3a
            {
                // @E3a
                if(rowNumber > 0)                                    // @E3a
                {
                    // @E3a
                    if(rowNumber > maxRows_)                          // @E3a
                    {
                        // @E3a
                        afterLast();                                    // @E3a
                        return false;                                   // @E3a
                    }                                                  // @E3a
                    // Don't need an else.  Drop through and call the rowCache as if maxRows not set.  
                }                                                     // @E3a
                else
                {                                                  // @E3a                                                     // @E3a
                    if(totalRows_ == NOT_KNOWN)                       // @E3a
                    {
                        // @E3a
                        findLastRow();                                  // @E3a
                    }                                                  // @E3a
                    int distanceFromFirst = totalRows_ + rowNumber;    // @E3a
                    if(distanceFromFirst < 0)                         // @E3a
                    {
                        // @E3a
                        beforeFirst();                                  // @E3a
                        return false;                                   // @E3a
                    }                                                  // @E3a
                    else                                               // @E3a
                        rowNumber = distanceFromFirst + 1;              // @E3a
                    // don't return.  Drop through and call the rowCache as if maxRows not set.
                }                                                     // @E3a
            }                                                        // @E3a


            // Position the cursor.
            rowCache_.absolute (rowNumber);
            positionValid_ = (rowCache_.isValid ());
            if(rowNumber > 0)
            {
                positionFromFirst_ = positionValid_ ? rowNumber : -1;
                positionFromLast_ = positionValid_ ? -1 : 0;         

                if(positionValid_)                                 // @E1a
                {
                    // @E1a
                    if(highestKnownRow_ < rowNumber)                // @E1a             
                        highestKnownRow_ = rowNumber;                 // @E1a      

                    if(totalRows_ != NOT_KNOWN)                         // @E2a
                        positionFromLast_ = totalRows_ - rowNumber + 1;   // @E2a
                }                                                   // @E1a
            }
            else
            {
                positionFromFirst_ = positionValid_ ? -1 : 0;
                positionFromLast_ = positionValid_ ? -rowNumber : -1;

                if(positionValid_)                                 // @E1a
                {
                    // @E1a
                    if(totalRows_ != NOT_KNOWN)                     // @E2a
                    {
                        // @E2a
                        int currentRow = totalRows_ + rowNumber;      // @E1a

                        if(highestKnownRow_ < currentRow)            // @E1a
                            highestKnownRow_ = currentRow;             // @E1a

                        positionFromFirst_ = currentRow + 1;          // @E2a
                    }                                                // @E1a
                }                                                   // @E1a
            }

            return positionValid_;
        }
    }



    // JDBC 2.0
    /**
    Positions the cursor after the last row.
    If an InputStream from the current row is open, it is
    implicitly closed.  In addition, all warnings and pending updates
    are cleared.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not scrollable,
                                or an error occurs.
    **/
    public void afterLast ()
    throws SQLException
    {      
        //   @E1: Implementation simplified.  Now do work in other methods 
        //        that have to do the work anyway. 
        //                                       
        //   Old code (v5r1 and older);
        //
        // synchronized(internalLock_)                               // @D1a
        // {                                         
        //     beforePositioning (true);
        //     rowCache_.afterLast ();
        //     positionFromFirst_ = -1;
        //     positionFromLast_ = 0;
        //     positionValid_ = false;
        // }
        //
        //   New code (note we don't do beforePositioning(true) because that is
        //   done in last())
        //   
        synchronized(internalLock_)                             
        {
            last();
            next();
        }
    }



    // JDBC 2.0
    /**
    Positions the cursor before the first row.
    If an InputStream from the current row is open, it is implicitly
    closed.  In addition, all warnings and pending updates are cleared.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not scrollable,
                                or an error occurs.
    **/
    public void beforeFirst ()
    throws SQLException
    {
        //   @E1: Implementation simplified.  Now do work in other methods 
        //        that have to do the work anyway. 
        //                                       
        //   Old code (v5r1 and older);
        //
        // synchronized(internalLock_)                                              // @D1A
        // {
        //     beforePositioning (true);
        //     rowCache_.beforeFirst ();
        //     positionFromFirst_ = 0;
        //     positionFromLast_ = -1;
        //     positionValid_ = false;
        // }
        //
        //   New code (note we don't do beforePositioning(true) because that is
        //   done in last())
        //   
        synchronized(internalLock_)                             
        {
            first();
            previous();
            positionFromLast_ = -1;//@GRA for returning correct value from getRow() after a select and insertRow()
        }
    }



    /**
    Checks necessary conditions before positioning a row.  All
    positioning methods should call this before changing the
    position.
    
    @param scrollable   Indicates if the result set must be
                        scrollable.
    
    @exception  SQLException    If the position cannot be done.
    **/
    private void beforePositioning (boolean scrollable)
    throws SQLException
    {
        // Check to see if saved exception. If so, then create a copy with the 
        // proper stack trace and throw it, referencing the original exception @F3A
        if (savedException_ != null) {
          SQLException nextException = savedException_; 
          savedException_ = null; 
          JDError.throwSQLException(this, nextException); 
        }
        checkOpen ();
        
        if((scrollable) && (getType() == TYPE_FORWARD_ONLY))  //@cur
            JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);

        clearCurrentRow ();

        // Get off of the insert row, if on it.
        positionInsert_ = false;
    }


    // @E3 new method!
    /**                         
    Counts the number of rows in the result set.  That number 
    is the number of rows that meet criteria or maxRows, 
    whichever is smaller.  The result of this method is
    internal variable "totalRows_" is set.
    
    **** Callers of this method must reposition the rowCache
    **** after calling this method!  This method moves the only the 
    **** rowCache cursor.  Since it no longer matches the result set cursor,
    **** the caller must re-sync the two cursors.
    
    @exception  SQLException    If it doesn't work.
    **/
    private void findLastRow ()
    throws SQLException
    {
        checkOpen ();

        // if we already know how many rows are in the result set simply return.
        if(totalRows_ != NOT_KNOWN)
            return;


        if(highestKnownRow_ > 0)
        {
            // If we are already past the maximum number of rows (probably
            // an error condition) simply re-set highestKnownRow (total
            // Rows is reset at the end of this routine).
            if(highestKnownRow_ >= maxRows_)
            {
                highestKnownRow_ = maxRows_;      
            }
            else
            {
                // As a last resort set the cursor to the highest known
                // row then loop through the rows until we hit the end. 
                rowCache_.absolute(highestKnownRow_);
                rowCache_.next();

                while(rowCache_.isValid())
                {
                    highestKnownRow_ ++;    

                    if((maxRows_ > 0) && (highestKnownRow_ == maxRows_))
                        break;

                    rowCache_.next();
                }
            }
        }
        // worst case, we don't have any idea how many rows are in the rs.  
        // Start at the beginning and loop through the rows until we hit the
        // end or maxRows.
        else
        {
            rowCache_.first();

            if(! rowCache_.isValid())
            {
                return;
            }
            else
            {
                highestKnownRow_ = 0;              
                while(rowCache_.isValid())
                {
                    highestKnownRow_ ++;    

                    if((maxRows_ > 0) && (highestKnownRow_ == maxRows_))
                        break;

                    rowCache_.next();
                }
            }
        }
        totalRows_ = highestKnownRow_;
    }



    // JDBC 2.0
    /**
    Positions the cursor to the first row.
    If an InputStream from the current row is open, it is
    implicitly closed.  In addition, all warnings and pending updates
    are cleared.
    
    @return             true if the requested cursor position is
                        valid; false otherwise.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not scrollable,
                                or an error occurs.
    **/
    public boolean first ()
    throws SQLException
    {
        synchronized(internalLock_)                                              // @D1A
        {
            beforePositioning (true);
            rowCache_.first ();

            // If the result set is not empty, then mark the
            // position as being on the first row.
            if(rowCache_.isValid ())
            {
                positionFromFirst_ = 1;               

                if(totalRows_ == NOT_KNOWN)                     // @E1a
                    positionFromLast_ = -1;
                else                                             // @E1a
                    positionFromLast_ = totalRows_;               // @E1a

                positionValid_ = true;                                  

                if(highestKnownRow_ < 1)                        // @E1a
                    highestKnownRow_ = 1;                         // @E1a
            }

            // Otherwise, there is no first row (only true if ResultSet is empty)
            else
            {
                positionFromFirst_ = -1;
                positionFromLast_ = -1;
                positionValid_ = false;
                totalRows_ = 0;                                  // @E1a
                highestKnownRow_ = NOT_KNOWN;                    // @E1a
            }

            return positionValid_;
        }
    }



    // JDBC 2.0 @D2C                                     
    // @E1 entire method re-worked
    /**
    Returns the current row number, or 0.  
    <P>
    0 is returned if the cursor is not on a valid row (such as
    before the first row, after the last row, or on the insert row),
    or if the result set is empty.                              
    <P>
    This method may be slow if cursor movement based on the end
    of the result set is used.  Methods such as last(), afterLast()
    and absolute() with a negative value will move the cursor based
    on the end of the result set.  This method will be slow in these
    cases because internally the method must get every row to determine
    how many rows are in the result set before calculating the current
    row.  The system does not know how many rows are in the result
    set until every row is touched.  That is why this method may
    start at the highest row retrieved so far, then do next() until
    the last row is retrieved.  
    <P>
    Once the maximum number of rows in the result set is determined, 
    it does not change until the result set is closed.  
    
    @return The current row number (1-based), or 0 if the current row
            is not valid.
    
    @exception SQLException If the result set is not open.
    **/
    public int getRow ()
    throws SQLException
    {
        synchronized(internalLock_)                                         // @D1A
        {
            checkOpen ();

            // @E1
            // Old Code:
            // return ((positionFromFirst_ > 0) && (positionInsert_ == false))
            //   ? positionFromFirst_ : 0;
            //
            // Old code in more readable format:
            // if ((positionFromFirst_ > 0) && (positionInsert_ == false))
            //    return positionFromFirst_;
            // else
            //    return 0;
            //          
            // case 1: return 0 if not on a valid row.
            if((positionInsert_ == true)  ||
               (positionValid_  == false) ||
               (isBeforeFirst())          ||
               (isAfterLast()))
                return 0;

            // case 2: we know what the current row is because scrolling has been
            //         from the beginning of the result set, or because previous
            //         method calls calculated the value.
            if(positionFromFirst_ > 0)
                return positionFromFirst_;

            // case 3a: don't know the current row because negative scrolling or
            //          scrolling from end has been used, *** and we are currently
            //          at the end of the rs ***.  If we don't know the number of 
            //          rows in the rs we will move the cursor to the highest
            //          known row then do next() until we get to the end.
            if(isLast())
            {
                if(totalRows_ != NOT_KNOWN)
                {
                    positionFromFirst_ = totalRows_;       
                    return positionFromFirst_;
                }
                else
                {
                    if(highestKnownRow_ == NOT_KNOWN)
                        first();
                    else
                        absolute(highestKnownRow_);

                    while(next())
                    {
                    } 
                    previous();

                    return positionFromFirst_;   
                }
            }

            // case 3b: don't know the current row because negative scrolling or
            //          scrolling from end has been used, *** but we are not currently
            //          at the end of the rs ***.  If we don't know how many rows are 
            //          in the result set we will move the cursor to the highest known
            //          row then do next() until we get back to where we were.
            if(positionFromLast_ > 0)
            {
                if(totalRows_ != NOT_KNOWN)
                {
                    positionFromFirst_ = totalRows_ - positionFromLast_ + 1;
                    return positionFromFirst_;
                }
                else
                {
                    int currentPositionFromLast = positionFromLast_;

                    if(highestKnownRow_ == NOT_KNOWN)
                        first();
                    else
                        absolute(highestKnownRow_);

                    while(next())
                    {
                    }
                    absolute(totalRows_ - currentPositionFromLast + 1);

                    return positionFromFirst_;   
                }   
            }

            // case 4: We don't have a clue how to figure out what the current row is.  Return 0;
            if(JDTrace.isTraceOn ())
                JDTrace.logInformation (this, "Could not determine row number in getRow().");

            return 0;
        }
    }



    // JDBC 2.0
    /**
    Indicates if the cursor is positioned after the last row.
    
    @return true if the cursor is positioned after the last row;
            false if the cursor is not positioned after the last
            row or if the result set contains no rows.
    
    @exception SQLException If the result set is not open.
    **/
    public boolean isAfterLast ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            checkOpen ();
            return((positionFromLast_ == 0)
                   && (positionFromFirst_ != 0)
                   && (positionInsert_ == false)
                   && (! rowCache_.isEmpty ()));
        }
    }



    // JDBC 2.0
    /**
    Indicates if the cursor is positioned before the first row.
    
    @return true if the cursor is positioned before the first row;
            false if the cursor is not positioned before the first
            row or if the result set contains no rows.
    
    @exception SQLException If the result set is not open.
    **/
    public boolean isBeforeFirst ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            checkOpen ();
            return((positionFromFirst_ == 0)
                   && (positionFromLast_ != 0)
                   && (positionInsert_ == false)
                   && (! rowCache_.isEmpty ()));
        }
    }



    // JDBC 2.0
    /**
    Indicates if the cursor is positioned on the first row.
    
    @return true if the cursor is positioned on the first row;
            false if the cursor is not positioned on the first
            row or the row number can not be determined.
    
    @exception SQLException If the result set is not open.
    **/
    public boolean isFirst ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            checkOpen ();              
            return((positionFromFirst_ == 1) && (positionInsert_ == false));
        }
    }



    // JDBC 2.0
    /**
    Indicates if the cursor is positioned on the last row.
    
    @return true if the cursor is positioned on the last row;
            false if the cursor is not positioned on the last
            row or the row number can not be determined.
    
    @exception SQLException If the result set is not open.
    **/
    public boolean isLast ()
    throws SQLException
    {
        synchronized(internalLock_)                                              // @D1A
        {
            checkOpen ();
            // @E2c -- Problem: if scrolling forward we don't know
            //         if we are on the last row until next() is called.
            //         In this case isLast() never returns true because
            //         by the time we figure out we are out of rows we
            //         are afterLast.  The fix is to internally call
            //         next then previous if we don't figure out we
            //         are on the last row some othe way.  This will be
            //         slower but accurate.  
            //  
            //    Old code:
            //
            // return (((positionFromLast_ == 1) || 
            //         ((positionFromFirst_ == maxRows_) && (maxRows_ > 0)))
            //         && (positionInsert_ == false));
            //
            //    New code:
            if((positionInsert_ == true) || (positionFromLast_ > 1) || (positionValid_ == false))
                return false;

            if(( positionFromLast_ == 1) || 
               ((positionFromFirst_ == maxRows_) && (maxRows_ > 0)))
                return true;

            boolean returnValue = ! next();
            previous();     

            return returnValue;                        
        }
    }



    // JDBC 2.0
    /**
    Positions the cursor to the last row.
    If an InputStream from the current row is open, it is
    implicitly closed.  In addition, all warnings and pending updates
    are cleared.
    
    @return             true if the requested cursor position is
                        valid; false otherwise.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not scrollable,
                                or an error occurs.
    **/
    public boolean last ()
    throws SQLException
    {
        synchronized(internalLock_)                                              // @D1A
        {
            beforePositioning (true);         

            if(maxRows_ > 0)                                    // @E3a
            {
                // @E3a
                findLastRow();                                    // @E3a     
                                                                  // @E3a
                if(totalRows_ >= maxRows_)                       // @E3a    
                {
                    rowCache_.absolute(maxRows_);                  // @E3a
                }
                else
                {                                              // @E3a
                    rowCache_.last ();                             // @E3a
                }   
            }                                                    // @E3a
            else
                rowCache_.last();      

            // If the result set is not empty, then mark the
            // position as being on the last row.
            if(rowCache_.isValid ())
            {
                positionFromFirst_ = -1;
                positionFromLast_ = 1;
                positionValid_ = true;     

                if(totalRows_ != NOT_KNOWN)                     // @E1a
                {
                    // @E1a
                    positionFromFirst_ = totalRows_;              // @E1a
                }                                                // @E1a
            }

            // Otherwise, there is no last row (only when result set is empty?)
            else
            {
                positionFromFirst_ = -1;
                positionFromLast_ = -1;
                positionValid_ = false;
                totalRows_ = 0;                                  // @E1a
                highestKnownRow_ = NOT_KNOWN;                    // @E1a
            }

            return positionValid_;
        }
    }



    // JDBC 2.0
    /**
    Positions the cursor to the current row.  This is the row
    where the cursor was positioned before moving it to the insert
    row.  If the cursor is not on the insert row, then this
    has no effect.
    
    <p>If an InputStream from the current row is open, it is
    implicitly closed.  In addition, all warnings and pending updates
    are cleared.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not scrollable,
                                or an error occurs.
    **/
    public void moveToCurrentRow ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            beforePositioning (true);
        }
    }



    // JDBC 2.0
    /**
    Positions the cursor to the insert row.
    If an InputStream from the current row is open, it is
    implicitly closed.  In addition, all warnings and pending updates
    are cleared.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not scrollable,
                                the result set is not updatable,
                                or an error occurs.
    **/
    public void moveToInsertRow ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            beforePositioning (true);
            beforeUpdate ();
            positionInsert_ = true;
        }
    }



    /**
    Positions the cursor to the next row.
    If an InputStream from the current row is open, it is
    implicitly closed.  In addition, all warnings and pending updates
    are cleared.
    
    @return     true if the requested cursor position is valid; false
                if there are no more rows.
    
    @exception  SQLException    If the result set is not open,
                                or an error occurs.
    **/
    public boolean next ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Initialization.
            beforePositioning (false);

            // Handle max rows.
            if((maxRows_ > 0) && (positionFromFirst_ >= maxRows_))
            {
                // @B3D afterLast ();
                // @E3D rowCache_.afterLast ();         // @B3a
                // If the position encounters an error, just ignore it.
                // This may happen in the rare case where the number of 
                // rows is the same as the maxRows setting.
            	// @U3C
                try { 
                  rowCache_.absolute(maxRows_ + 1);  // @E3a
                } catch (Exception e) { 
                  if (JDTrace.isTraceOn()) {
                    JDTrace.logException(this, "Warning: Exception encountered on going to last  ", e); 
                  }
                }
                positionFromFirst_ = -1;           // @B3A
                positionFromLast_ = 0;             // @B3A
                positionValid_ = false;            // @B3A

                totalRows_ = maxRows_;                           // @E1a
                highestKnownRow_ = maxRows_;                     // @E1a

                return false;                   
            }

            // Normal case. If the row is null after a next, then
            // the cursor is positioned after the last row.
            rowCache_.next();

            if(rowCache_.isValid ())
            {
                if(positionFromFirst_ >= 0)
                    ++positionFromFirst_;

                if(positionFromLast_ > 0)
                    --positionFromLast_;

                if(positionFromFirst_ >= 0)                    // @E1a
                    if(highestKnownRow_ < positionFromFirst_)   // @E1a             
                        highestKnownRow_ = positionFromFirst_;    // @E1a

                positionValid_ = true;

            }
            else
            {
                // If this is the first time row has been null,
                // then increment one more time.    
                // @E2a only if there are rows in the rs!
                if(! rowCache_.isEmpty ())                        // @E2a
                {
                    if(positionFromLast_ != 0)
                    {
                        if(positionFromFirst_ >= 0)
                        {
                            totalRows_ = positionFromFirst_;        // @E2a
                            ++positionFromFirst_;
                        }
                    }
                    positionFromLast_ = 0;
                }                                                  // @E2a   
                else
                {                                               // @E1a                                                  // @E1a
                    if(highestKnownRow_ > 0)                       // @E1a
                    {
                        // @E1a
                        totalRows_ = highestKnownRow_;               // @E1a
                        positionFromFirst_ = totalRows_;             // @E1a
                        positionFromLast_ = 0;                       // @E1a
                    }                                               // @E1a
                }                                                  // @E1a
                positionValid_ = false;
            }

            return positionValid_;
        }
    }



    // JDBC 2.0
    /**
    Positions the cursor to the previous row.
    If an InputStream from the current row is open, it is implicitly
    closed.  In addition, all warnings and pending updates
    are cleared.
    
    @return             true if the requested cursor position is
                        valid; false otherwise.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not scrollable,
                                or an error occurs.
    **/
    public boolean previous ()
    throws SQLException
    {
        synchronized(internalLock_)                                              // @D1A
        {
            // Initialization.
            beforePositioning (true);

            // Normal case. If the row is null after a previous, then
            // the cursor is positioned before the first row.
            rowCache_.previous();  

            if(rowCache_.isValid ())
            {
                if(positionFromFirst_ > 0)
                    --positionFromFirst_;

                if(positionFromLast_ >= 0)
                    ++positionFromLast_;

                positionValid_ = true;
            }
            else
            {
                // If this is the first time row has been null,
                // then increment one more time.
                if(positionFromFirst_ != 0)
                    if(positionFromLast_ >= 0)
                        ++positionFromLast_;

                positionFromFirst_ = 0;
                positionValid_ = false;
            }

            return positionValid_;
        }
    }


    // JDBC 2.0
    /**
    Refreshes the current row from the database and cancels all 
    pending updates that have been made since the last call to 
    updateRow().  This method provides a way for an application 
    to explicitly refetch a row from the database.  If an InputStream 
    from the current row is open, it is implicitly closed.  In 
    addition, all warnings and pending updates are cleared.
    
    @exception SQLException If the result set is not open,
                            the result set is not scrollable,
                            the cursor is not positioned on a row,
                            the cursor is positioned on the
                            insert row or an error occurs.
    **/
    public void refreshRow ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            if(positionInsert_ == true)
                JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
            beforePositioning (true);
            if(positionValid_ == false)
                JDError.throwSQLException (JDError.EXC_CURSOR_POSITION_INVALID);

            if(concurrency_ == CONCUR_UPDATABLE)
                for(int i = 0; i < columnCount_; ++i)
                    updateSet_[i] = false;

            rowCache_.refreshRow ();
        }
    }



    // JDBC 2.0
    /**
    Positions the cursor to a relative row number.
    
    <p>Attempting to move beyond the first row positions the
    cursor before the first row. Attempting to move beyond the last
    row positions the cursor after the last row.
    
    <p>If an InputStream from the current row is open, it is
    implicitly closed.  In addition, all warnings and pending updates
    are cleared.
    
    @param  rowNumber   The relative row number.  If the relative row
                        number is positive, this positions the cursor
                        after the current position.  If the relative
                        row number is negative, this positions the
                        cursor before the current position.  If the
                        relative row number is 0, then the cursor
                        position does not change.
    @return             true if the requested cursor position is
                        valid, false otherwise.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not scrollable,
                                the cursor is not positioned on a valid row,
                                or an error occurs.
    */
    public boolean relative (int rowNumber)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Initialization.
            beforePositioning (true);
            //if((positionFromFirst_ == 0) || (positionFromLast_ == 0))  //@rel1 per javadoc, relative(1) <==> next()
                //return false;

            // If before first and scrolling negative, then the position is invalid.
            // return without doing anything.. 
            if (rowNumber < 0 && isBeforeFirst()) {
              return false; 
            }
            
            
            // Handle max rows.
            if((maxRows_ > 0) && (positionFromFirst_ == -1))                // @E3a
                getRow();                                                     // @E3a

            if((positionFromFirst_ >= 0)
               && (positionFromFirst_ + rowNumber > maxRows_)
               && (maxRows_ > 0))
            {                                                  // @E3a
                afterLast();  // should this be absolute(max+1) // @E3a
                return false;                              
            }                                                  // @E3a


            // Normal case.  If the row is null after relative,
            // then we are off the edge of the result set.
            rowCache_.relative (rowNumber);

            if(rowCache_.isValid ())
            {
                if(positionFromFirst_ >= 0)
                    positionFromFirst_ += rowNumber;

                if(positionFromLast_ >= 0)
                    positionFromLast_ -= rowNumber;

                positionValid_ = true;

                if(positionFromFirst_ >= 0)                    // @E1a
                    if(highestKnownRow_ < positionFromFirst_)   // @E1a             
                        highestKnownRow_ = positionFromFirst_;    // @E1a

            }
            else
            {
                if(rowNumber >= 0)
                {
                    positionFromFirst_ = -1;
                    positionFromLast_ = 0;
                }
                else
                {
                    positionFromFirst_ = 0;
                    positionFromLast_ = -1;
                }
                positionValid_ = false;
            }

            return positionValid_;
        }
    }



    /*---------------------------------------------------------*/
    /*                                                         */
    /* GET DATA METHODS.                                       */
    /*                                                         */
    /*---------------------------------------------------------*/



    // JDBC 2.0
    /**
    Returns the value of a column as an Array object.
    DB2 for IBM i does not support arrays.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    Always thrown because DB2 for IBM i does not support arrays.
    **/
    public Array getArray (int columnIndex)
    throws SQLException
    {
        JDError.throwSQLException (JDError.EXC_DATA_TYPE_MISMATCH);
        return null;
    }



    // JDBC 2.0
    /**
    Returns the value of a column as an Array object.
    DB2 for IBM i does not support arrays.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getArray("\"MixedCase\"").
    
    @param  columnName    The column name.
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    Always thrown because DB2 for IBM i does not support arrays.
    **/
    public Array getArray (String columnName)
    throws SQLException
    {
        return getArray (findColumn (columnName));
    }



    /**
    Returns the value of a column as a stream of ASCII
    characters.  This can be used to get values from columns
    with SQL types CHAR, VARCHAR, BINARY, VARBINARY, CLOB, and
    BLOB.  All of the data in the returned stream must be read 
    prior to getting the value of any other column.  The next 
    call to a get method implicitly closes the stream.
    
    @param  columnIndex     The column index (1-based).
    @return                 The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid,
                                or the requested conversion is not valid.
    **/
    public InputStream getAsciiStream (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            InputStream value = (data == null) ? null : data.getAsciiStream ();
            openInputStream_ = value;
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2 
            return value;
        }
    }



    /**
    Returns the value of a column as a stream of ASCII
    characters. This can be used to get values from columns
    with SQL types CHAR, VARCHAR, BINARY, VARBINARY, CLOB, and
    BLOB.  All of the data in the returned stream must be read 
    prior to getting the value of any other column.  The next 
    call to a get method implicitly closes the stream.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getAsciiStream("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public InputStream getAsciiStream (String columnName)
    throws SQLException
    {
        return getAsciiStream (findColumn (columnName));
    }



    // JDBC 2.0
    // @D0C
    /**
    Returns the value of a column as a BigDecimal object.  This
    can be used to get values from columns with SQL types
    SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    
    @param  columnIndex     The column index (1-based).
    @return                 The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid,
                                or the requested conversion is not valid.
    **/
    public BigDecimal getBigDecimal (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            BigDecimal value = (data == null) ? null : data.getBigDecimal (-1);
            testDataTruncation (columnIndex, data, false); //@trunc getBigDecimal(int) can set truncation_!=0, but we should not throw an SQLEception
            return value;
        }
    }



    // JDBC 2.0
    // @D0C    
    /**
    Returns the value of a column as a BigDecimal object. This
    can be used to get values from columns with SQL types
    SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getBigDecimal("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found,
                                or the requested conversion is not valid.
    **/
    public BigDecimal getBigDecimal (String columnName)
    throws SQLException
    {
        return getBigDecimal (findColumn (columnName));
    }



    // @D0C
    /**
    Returns the value of a column as a BigDecimal object.  This
    can be used to get values from columns with SQL types
    SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    
    @param  columnIndex     The column index (1-based).
    @param  scale           The number of digits after the decimal.
    @return                 The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid,
                                the scale is not valid, or the
                                requested conversion is not valid.
    
    @deprecated Use getBigDecimal(int) instead.
    @see #getBigDecimal(int)
    **/
    public BigDecimal getBigDecimal (int columnIndex, int scale)
    throws SQLException
    {
        // Check for negative scale.
        if(scale < 0)
            JDError.throwSQLException (JDError.EXC_SCALE_INVALID,""+scale);

        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            BigDecimal value = (data == null) ? null : data.getBigDecimal (scale);
            testDataTruncation (columnIndex, data, false); //@trunc getBigDecimal(int) can set truncation_!=0, but we should not throw an SQLEception
            return value;
        }
    }



    // @D0C
    /**
    Returns the value of a column as a BigDecimal object. This
    can be used to get values from columns with SQL types
    SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getBigDecimal("\"MixedCase\"", 0).
    
    @param  columnName  The column name.
    @param  scale       The number of digits after the decimal.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found,
                                the scale is not valid, or the
                                requested conversion is not valid.
    
    @deprecated Use getBigDecimal(String) instead.
    @see #getBigDecimal(String)
    **/
    public BigDecimal getBigDecimal (String columnName, int scale)
    throws SQLException
    {
        return getBigDecimal (findColumn (columnName), scale);
    }



    /**
    Returns the value of a column as a stream of uninterpreted
    bytes.  This can be used to get values from columns
    with SQL types BINARY, VARBINARY, and BLOB.  All of the data in
    the returned stream must be read prior to getting the
    value of any other column.  The next call to a get method
    implicitly closes the stream.
    
    @param  columnIndex     The column index (1-based).
    @return                 The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public InputStream getBinaryStream (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            InputStream value = (data == null) ? null : data.getBinaryStream ();
            openInputStream_ = value;
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2
            return value;
        }
    }



    /**
    Returns the value of a column as a stream of uninterpreted
    bytes.  This can be used to get values from columns
    with SQL types BINARY, VARBINARY, and BLOB.  All of the data in
    the returned stream must be read prior to getting the
    value of any other column.  The next call to a get method
    implicitly closes the stream.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getBinaryStream("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public InputStream getBinaryStream (String columnName)
    throws SQLException
    {
        return getBinaryStream (findColumn (columnName));
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a Blob object.
    This can be used to get values from columns with SQL
    types BINARY, VARBINARY, and BLOB.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public Blob getBlob (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            Blob value = (data == null) ? null : data.getBlob ();
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2
            return value;
        }
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a Blob object.
    This can be used to get values from columns with SQL
    types BINARY, VARBINARY, and BLOB.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getBlob("\"MixedCase\"").
    
    @param  columnName    The column name.
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public Blob getBlob (String columnName)
    throws SQLException
    {
        return getBlob (findColumn (columnName));
    }



    // @D0C
    /**
    Returns the value of a column as a Java boolean value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or false if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public boolean getBoolean (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            boolean value = (data == null) ? false : data.getBoolean ();
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2
            return value;
        }
    }



    // @D0C
    /**
    Returns the value of a column as a Java boolean value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getBoolean("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or false if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public boolean getBoolean (String columnName)
    throws SQLException
    {
        return getBoolean (findColumn (columnName));
    }



    // @D0C
    /**
    Returns the value of a column as a Java byte value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    
    @param  columnIndex     The column index (1-based).
    @return                 The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public byte getByte (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            byte value = (data == null) ? 0 : data.getByte ();
            testDataTruncation (columnIndex, data, true); //@trunc
            return value;
        }
    }



    // @D0C
    /**
    Returns the value of a column as a Java byte value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getByte("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public byte getByte (String columnName)
    throws SQLException
    {
        return getByte (findColumn (columnName));
    }



    /**
    Returns the value of a column as a Java byte array.
    This can be used to get values from columns with SQL
    types BINARY and VARBINARY.  
    
    <p>This can also be used to get values from columns 
    with other types.  The values are returned in their
    native IBM i format.  This is not supported for
    result sets returned by a DatabaseMetaData object.
    
    @param  columnIndex     The column index (1-based).
    @return                 The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public byte[] getBytes (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            int sqlType = 0; 
            if (data != null) {
              sqlType = data.getSQLType(); 
            }
            byte[] value;                                                               // @C1C

            // Treat this differently from the other get's.  If the data is not a       // @C1A
            // BINARY, VARBINARY, or BLOB, and we have access to the bytes, then return // @C1A @D4C
            // the bytes directly.                                                      // @C1A
            if((data != null)
               && (!(sqlType == SQLData.BINARY)) 
               && (!(sqlType == SQLData.VARBINARY))
               && (!(sqlType == SQLData.BLOB))                                   // @D4A
               && (!(sqlType == SQLData.BLOB_LOCATOR))                           // @D4A
               && (!(sqlType == SQLData.CHAR_FOR_BIT_DATA))                      // @M0A
               && (!(sqlType == SQLData.LONG_VARCHAR_FOR_BIT_DATA))              // @M0A
               && (!(sqlType == SQLData.VARCHAR_FOR_BIT_DATA))                   // @M0A
               && (!(sqlType == SQLData.ROWID))                                  // @M0A
               && (!(sqlType == SQLData.XML_LOCATOR))                                  //@xml3
               && (row_ instanceof JDServerRow))   {                                    // @C1A
                value = ((JDServerRow)row_).getRawBytes(columnIndex);                   // @C1A
                                                                                        // @C1A
                
                // If the data is a variable length type, we want to strip the encoded
                // length to be consistent with other JDBC drivers
                if (sqlType == SQLData.VARCHAR || 
                    sqlType == SQLData.VARGRAPHIC ||
                    sqlType == SQLData.NVARCHAR || 
                    sqlType == SQLData.DATALINK) {
                  if (value != null) {
                      if (value.length >= 2) {
                        int newLength = 0x100 * (((int)value[0])&0xff) + (((int)value[1])&0xff);
                        if (sqlType == SQLData.VARGRAPHIC ||
                            sqlType == SQLData.NVARCHAR ) {
                          newLength = newLength * 2; 
                        }
                        byte[] newValue = new byte[newLength]; 
                        for (int i = 0; i < newLength; i++) { 
                          newValue[i] = value[i+2]; 
                        }
                        value = newValue; 
                        
                      }
                  }
                } else if (sqlType == SQLData.CLOB_LOCATOR) {
                  String x = data.getString();
                  try { 
                    value = x.getBytes("ISO8859_1");
                  } catch (Exception cpException) {
                    // ignore; 
                  }
                } else if (sqlType == SQLData.DBCLOB_LOCATOR ||
                           sqlType == SQLData.NCLOB_LOCATOR) {
                  String x = data.getString();
                  try { 
                    value = x.getBytes("UTF-16BE");
                  } catch (Exception cpException) {
                    // ignore; 
                  }
                }
               }
            else
            {                                                                      // @C1A
                value = (data == null) ? null : data.getBytes ();                        // @C1C
                testDataTruncation (columnIndex, data, false); //@trunc //@trunc2
            }                                                                           // @C1A
            return value;
        }
    }



    /**
    Returns the value of a column as a Java byte array.
    This can be used to get values from columns with SQL
    types BINARY and VARBINARY.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getBytes("\"MixedCase\"").
    
    <p>This can also be used to get values from columns 
    with other types.  The values are returned in their
    native IBM i format.  This is not supported for
    result sets returned by a DatabaseMetaData object.
    
    @param  columnName  The column name.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public byte[] getBytes (String columnName)
    throws SQLException
    {
        return getBytes (findColumn (columnName));
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a character stream.
    This can be used to to get values from columns with SQL
    types CHAR, VARCHAR, BINARY, VARBINARY, CLOB, and BLOB.  
    All of the data in the returned stream must be read prior to 
    getting the value of any other column.  The next call to a get 
    method implicitly closes the stream.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    */
    public Reader getCharacterStream (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            Reader value = (data == null) ? null : data.getCharacterStream ();
            openReader_ = value;
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2
            return value;
        }
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a character stream.
    This can be used to to get values from columns with SQL
    types CHAR, VARCHAR, BINARY, VARBINARY, CLOB, and BLOB.  
    All of the data in the returned stream must be read prior 
    to getting the value of any other column.  The next call 
    to a get method implicitly closes the stream.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getCharacterStream("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not valid, or the
                                requested conversion is not valid.
    */
    public Reader getCharacterStream (String columnName)
    throws SQLException
    {
        return getCharacterStream (findColumn (columnName));
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a Clob object.
    This can be used to get values from columns with SQL
    types CHAR, VARCHAR, BINARY, VARBINARY, BLOB, and CLOB.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public Clob getClob (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            Clob value = (data == null) ? null : data.getClob ();
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2
            return value;
        }
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a Clob object.
    This can be used to get values from columns with SQL
    types CHAR, VARCHAR, BINARY, VARBINARY, BLOB, and CLOB.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getClob("\"MixedCase\"").
    
    @param  columnName    The column name.
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public Clob getClob (String columnName)
    throws SQLException
    {
        return getClob (findColumn (columnName));
    }



    /**
    Returns the value of a column as a java.sql.Date object using
    the default calendar.  This can be used to get values from columns
    with SQL types CHAR, VARCHAR, DATE, and TIMESTAMP.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public Date getDate (int columnIndex)
    throws SQLException
    {
        //@P0D return getDate (columnIndex, AS400Calendar.getGregorianInstance ());
        return internalGetDate(columnIndex, null); //@P0A
    }



    /**
    Returns the value of a column as a java.sql.Date object using
    the default calendar.  This can be used to get values from columns
    with SQL types CHAR, VARCHAR, DATE, and TIMESTAMP.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getDate("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public Date getDate (String columnName)
    throws SQLException
    {
        //@P0D return getDate (findColumn (columnName), AS400Calendar.getGregorianInstance ());
        return internalGetDate(findColumn(columnName), null); //@P0A
    }


    //@P0A - Moved out of getDate()
    private Date internalGetDate(int columnIndex, Calendar calendar)
    throws SQLException
    {
        synchronized(internalLock_)
        {
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            Date value = (data == null) ? null : data.getDate (calendar);
            testDataTruncation (columnIndex, data, false); //@trunc getDate() can set truncation_!=0, but we should not throw an SQLEception
            return value;
        }
    }

    // JDBC 2.0
    /**
    Returns the value of a column as a java.sql.Date object using
    a calendar other than the default.  This can be used to get values
    from columns with SQL types CHAR, VARCHAR, DATE, and TIMESTAMP.
    
    @param  columnIndex   The column index (1-based).
    @param  calendar      The calendar.
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid,
                                the calendar is null, or the
                                requested conversion is not valid.
    **/
    public Date getDate (int columnIndex, Calendar calendar)
    throws SQLException
    {
        // Check for null calendar.
        if(calendar == null)
            JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);
        return internalGetDate(columnIndex, calendar); //@P0C
        /*@P0M
            synchronized(internalLock_) {                                            // @D1A
                // Get the data and check for SQL NULL.
                SQLData data = getValue (columnIndex);
                Date value = (data == null) ? null : data.toDate (calendar);
                testDataTruncation (columnIndex, data);
                return value;
            }
         */ //@P0M
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a java.sql.Date object using
    a calendar other than the default.  This can be used to get values
    from columns with SQL types CHAR, VARCHAR, DATE, and TIMESTAMP.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getDate("\"MixedCase\"", calendar).
    
    @param  columnName  The column name.
    @param  calendar    The calendar.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found,
                                the calendar is null, or the
                                requested conversion is not valid.
    **/
    public Date getDate (String columnName, Calendar calendar)
    throws SQLException
    {
        return getDate (findColumn (columnName), calendar);
    }



    // @D0C
    /**
    Returns the value of a column as a Java double value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public double getDouble (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            double value = (data == null) ? 0 : data.getDouble ();
            testDataTruncation (columnIndex, data, true); //@trunc
            return value;
        }
    }



    // @D0C
    /**
    Returns the value of a column as a Java double value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getDouble("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public double getDouble (String columnName)
    throws SQLException
    {
        return getDouble (findColumn (columnName));
    }



    // @D0C
    /**
    Returns the value of a column as a Java float value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public float getFloat (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            float value = (data == null) ? 0 : data.getFloat ();
            testDataTruncation (columnIndex, data, true); //@trunc
            return value;
        }
    }



    // @D0C
    /**
    Returns the value of a column as a Java float value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getFloat("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public float getFloat (String columnName)
    throws SQLException
    {
        return getFloat (findColumn (columnName));
    }



    // @D0C
    /**
    Returns the value of a column as a Java int value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public int getInt (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            int value = (data == null) ? 0 : data.getInt ();
            testDataTruncation (columnIndex, data, true); //@trunc
            return value;
        }
    }



    // @D0C
    /**
    Returns the value of a column as a Java int value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getInt("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public int getInt (String columnName)
    throws SQLException
    {
        return getInt (findColumn (columnName));
    }



    // @D0C
    /**
    Returns the value of a column as a Java long value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public long getLong (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            long value = (data == null) ? 0 : data.getLong ();
            testDataTruncation (columnIndex, data, true); //@trunc
            return value;
        }
    }



    // @D0C
    /**
    Returns the value of a column as a Java long value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getLong("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public long getLong (String columnName)
    throws SQLException
    {
        return getLong (findColumn (columnName));
    }



    /**
    Returns the ResultSetMetaData object that describes the
    result set's columns.
    
    @return     The metadata object.
    
    @exception  SQLException    If an error occurs.
    **/
    public ResultSetMetaData getMetaData ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            ConvTable convTable = null;                                                              // @G5A
                // If we have extendedDescriptors, send a ConvTable to convert them, else pass null  // @G5A
                                                                                                     // @P6C
                if(extendedDescriptors_ != null)                                                     // @G5A
                {
                    // @G5A
                    convTable = ((AS400JDBCConnection)connection_).converter_;                       // @G5A
                }                                                                                    // @G5A
            return new AS400JDBCResultSetMetaData (catalog_, concurrency_,
                                                   cursorName_, row_, 
                                                   extendedDescriptors_, convTable, connection_);                  // @G5A@P6C //@in1
        }
    }



    /**
    Returns the value of a column as a Java Object.
    This can be used to get values from columns with all
    SQL types.   If the column is a user-defined type, then the
    connection's type map is used to created the object.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public Object getObject (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            Object value = (data == null) ? null : data.getObject ();
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2
            return value;
        }
    }



    /**
    Returns the value of a column as a Java Object.
    This can be used to get values from columns with all
    SQL types.   If the column is a user-defined type, then the
    connection's type map is used to created the object.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getObject("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public Object getObject (String columnName)
    throws SQLException
    {
        return getObject (findColumn (columnName));
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a Java Object.
    
    @param  columnIndex   The column index (1-based).
    @param  typeMap       The type map.  This is not used.
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid,
                                the type map is null, or the
                                requested conversion is not valid.
    **/
    public Object getObject (int columnIndex, Map typeMap)
    throws SQLException
    {
        // Check for null type map, even though we don't use it.
        if(typeMap == null)
            JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);

        return getObject (columnIndex);
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a Java Object.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getObject("\"MixedCase\"", typeMap).
    
    @param  columnName    The column name.
    @param  typeMap       The type map.  This is not used.
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, 
                                the type map is null, or the
                                requested conversion is not valid.
    **/
    public Object getObject (String columnName, Map typeMap)
    throws SQLException
    {
        // Check for null type map, even though we don't use it.
        if(typeMap == null)
            JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);

        return getObject (findColumn (columnName));
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a Ref object.
    DB2 for IBM i does not support structured types.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    Always thrown because DB2 for IBM i does not support structured types.
    **/
    public Ref getRef (int columnIndex)
    throws SQLException
    {
        JDError.throwSQLException (JDError.EXC_DATA_TYPE_MISMATCH);
        return null;
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a Ref object.
    DB2 for IBM i does not support structured types.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getRef("\"MixedCase\"").
    
    @param  columnName    The column name.
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    Always thrown because DB2 for IBM i does not support structured types.
    **/
    public Ref getRef (String columnName)
    throws SQLException
    {
        return getRef (findColumn (columnName));
    }



    // @D0C
    /**
    Returns the value of a column as a Java short value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public short getShort (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            short value = (data == null) ? 0 : data.getShort ();
            testDataTruncation (columnIndex, data, true); //@trunc
            return value;
        }
    }



    // @D0C
    /**
    Returns the value of a column as a Java short value.
    This can be used to get values from columns with SQL
    types SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, DECIMAL,
    NUMERIC, CHAR, and VARCHAR.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getShort("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or 0 if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public short getShort (String columnName)
    throws SQLException
    {
        return getShort (findColumn (columnName));
    }



    /**
    Returns the value of a column as a String object.
    This can be used to get values from columns with any SQL
    type.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public String getString (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            String value = (data == null) ? null : data.getString ();
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2
            return value;
        }
    }



    /**
    Returns the value of a column as a String object.
    This can be used to get values from columns with any SQL
    type.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getString("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public String getString (String columnName)
    throws SQLException
    {
        return getString (findColumn (columnName));
    }



    /**
    Returns the value of a column as a java.sql.Time object using the
    default calendar.  This can be used to get values from columns
    with SQL types CHAR, VARCHAR, TIME, and TIMESTAMP.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public Time getTime (int columnIndex)
    throws SQLException
    {
        //@P0D return getTime (columnIndex, AS400Calendar.getGregorianInstance ());
        return internalGetTime(columnIndex, null); //@P0A
    }



    /**
    Returns the value of a column as a java.sql.Time object using the
    default calendar.  This can be used to get values from columns
    with SQL types CHAR, VARCHAR, TIME, and TIMESTAMP.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getTime("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public Time getTime (String columnName)
    throws SQLException
    {
        //@P0D return getTime (findColumn (columnName), AS400Calendar.getGregorianInstance ());
        return internalGetTime(findColumn(columnName), null); //@P0A
    }

    //@P0M - Moved out of getTime()
    private Time internalGetTime(int columnIndex, Calendar calendar)
    throws SQLException
    {
        synchronized(internalLock_)
        {
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            Time value = (data == null) ? null : data.getTime (calendar);
            testDataTruncation (columnIndex, data, false); //@trunc getTime() can set truncation_!=0, but we should not throw an SQLEception
            return value;
        }
    }

    // JDBC 2.0
    /**
    Returns the value of a column as a java.sql.Time object using a
    calendar other than the default.  This can be used to get values
    from columns with SQL types CHAR, VARCHAR, TIME, and TIMESTAMP.
    
    @param  columnIndex   The column index (1-based).
    @param  calendar      The calendar.
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid,
                                the calendar is null, or the
                                requested conversion is not valid.
    **/
    public Time getTime (int columnIndex, Calendar calendar)
    throws SQLException
    {
        //@P0D synchronized(internalLock_) {                                            // @D1A
        // Check for null calendar.
        if(calendar == null)
            JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);
        return internalGetTime(columnIndex, calendar); //@P0C
        /*@P0M
              // Get the data and check for SQL NULL.
              SQLData data = getValue (columnIndex);
              Time value = (data == null) ? null : data.toTime (calendar);
              testDataTruncation (columnIndex, data);
              return value;
          }
        */ //@P0M
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a java.sql.Time object using a
    calendar other than the default.  This can be used to get values
    from columns with SQL types CHAR, VARCHAR, TIME, and TIMESTAMP.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getTime("\"MixedCase\"", calendar).
    
    @param  columnName  The column name.
    @param  calendar    The calendar.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found,
                                the calendar is null, or the
                                requested conversion is not valid.
    **/
    public Time getTime (String columnName, Calendar calendar)
    throws SQLException
    {
        return getTime (findColumn (columnName), calendar);
    }



    /**
    Returns the value of a column as a java.sql.Timestamp object
    using the default calendar.  This can be used to get values
    from columns with SQL types CHAR, VARCHAR, DATE, and TIMESTAMP.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public Timestamp getTimestamp (int columnIndex)
    throws SQLException
    {
        //@P0D return getTimestamp (columnIndex, AS400Calendar.getGregorianInstance ());
        return internalGetTimestamp(columnIndex, null); //@P0A
    }



    /**
    Returns the value of a column as a java.sql.Timestamp object
    using the default calendar.  This can be used to get values
    from columns with SQL types CHAR, VARCHAR, DATE, and TIMESTAMP.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getTimestamp("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public Timestamp getTimestamp (String columnName)
    throws SQLException
    {
        //@P0D return getTimestamp (findColumn (columnName), AS400Calendar.getGregorianInstance ());
        return internalGetTimestamp(findColumn(columnName), null); //@P0A
    }

    //@P0M - Moved out of getTimestamp()
    private Timestamp internalGetTimestamp(int columnIndex, Calendar calendar)
    throws SQLException
    {
        synchronized(internalLock_)
        {
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            Timestamp value = (data == null) ? null : data.getTimestamp (calendar);
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2
            return value;
        }
    }

    // JDBC 2.0
    /**
    Returns the value of a column as a java.sql.Timestamp object
    using a calendar other than the default.  This can be used to
    get values from columns with SQL types CHAR, VARCHAR, DATE,
    and TIMESTAMP.
    
    @param  columnIndex   The column index (1-based).
    @param  calendar      The calendar.
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid,
                                the calendar is null, or the
                                requested conversion is not valid.
    **/
    public Timestamp getTimestamp (int columnIndex, Calendar calendar)
    throws SQLException
    {
        // Check for null calendar.
        if(calendar == null)
            JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);
        return internalGetTimestamp(columnIndex, calendar);
        /*@P0M
          synchronized(internalLock_) {                                            // @D1A
              // Get the data and check for SQL NULL.
              SQLData data = getValue (columnIndex);
              Timestamp value = (data == null) ? null : data.toTimestamp (calendar);
              testDataTruncation (columnIndex, data);
              return value;
          }
        */ //@P0M
    }



    // JDBC 2.0
    /**
    Returns the value of a column as a java.sql.Timestamp object
    using a calendar other than the default.  This can be used to
    get values from columns with SQL types CHAR, VARCHAR, DATE,
    and TIMESTAMP.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getTimestamp("\"MixedCase\"", calendar).
    
    @param  columnName  The column name.
    @param  calendar    The calendar.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found,
                                the calendar is null, or the
                                requested conversion is not valid.
    **/
    public Timestamp getTimestamp (String columnName, Calendar calendar)
    throws SQLException
    {
        return getTimestamp (findColumn (columnName), calendar);
    }



    /**
    Returns the value of a column as a stream of Unicode
    characters.  This can be used to get values from columns
    with SQL types CHAR, VARCHAR, BINARY, VARBINARY, CLOB, and
    BLOB.  All of the data in the returned stream must be read 
    prior to getting the value of any other column.  The next 
    call to a get method implicitly closes the stream.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    
    @deprecated Use getCharacterStream(int) instead.
    @see #getCharacterStream(int)
    **/
    public InputStream getUnicodeStream (int columnIndex)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // Get the data and check for SQL NULL.
            SQLData data = getValue (columnIndex);
            InputStream value = (data == null) ? null : data.getUnicodeStream ();
            openInputStream_ = value;
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2
            return value;
        }
    }



    /**
    Returns the value of a column as a stream of Unicode
    characters.  This can be used to get values from columns
    with SQL types CHAR, VARCHAR, BINARY, VARBINARY, CLOB,
    and BLOB.  All of the data in the returned stream must be 
    read prior to getting the value of any other column.  The 
    next call to a get method implicitly closes the stream.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.getUnicodeStream("\"MixedCase\"").
    
    @param  columnName  The column name.
    @return             The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    
    @deprecated Use getCharacterStream(String) instead.
    @see #getCharacterStream(String)
    **/
    public InputStream getUnicodeStream (String columnName)
    throws SQLException
    {
        return getUnicodeStream (findColumn (columnName));
    }



    /**
    Returns a piece of row data for the specified index,
    and perform all appropriate validation.  Also check
    for SQL NULL.
    
    @param  columnIndex   The column index (1-based).
    @return               The column value or null if the value is SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    private SQLData getValue (int columnIndex)
    throws SQLException
    {
        checkOpen ();
        clearCurrentValue ();

        // Check that there is a current row.
        if((positionValid_ == false) && (positionInsert_ == false))
            JDError.throwSQLException (JDError.EXC_CURSOR_POSITION_INVALID);

        // Validate The column index.
        if(columnIndex < 1)
            JDError.throwSQLException (JDError.EXC_DESCRIPTOR_INDEX_INVALID, columnIndex+"<1");
        if (columnIndex > columnCount_)
          JDError.throwSQLException (JDError.EXC_DESCRIPTOR_INDEX_INVALID, columnIndex+">"+columnCount_);
          
        // Check if an update was made or we are on the insert
        // row.
        if(concurrency_ == CONCUR_UPDATABLE)
        {
            if((updateSet_[columnIndex-1] == true)     //@EIC2 changed back to original logic.  For case of after insertrow is inserted, the updateSet[] is reset, but can still have non-null data.
               || (positionInsert_ == true))               
            {
                wasNull_ = updateNulls_[columnIndex-1];
                wasDataMappingError_ = false;
                if(wasNull_)
                    return null;
                else
                    return updateRow_.getSQLData (columnIndex);
            }
        }

        // Get the data and check for SQL NULL.   @A1C
        wasNull_ = row_.isNull (columnIndex);
        wasDataMappingError_ = row_.isDataMappingError(columnIndex);

        //@KBL if a locator is used, tell the statement associated with it
        SQLData sqlData = row_.getSQLType(columnIndex);             //@KBL
        int sqlType = sqlData.getSQLType();  //@xml3
        if((sqlType == SQLData.CLOB_LOCATOR ||          //@KBL
             sqlType == SQLData.BLOB_LOCATOR ||          //@KBL
             sqlType == SQLData.DBCLOB_LOCATOR ||        //@KBL   //@pdc jdbc40
             sqlType == SQLData.NCLOB_LOCATOR ||                 //@pda jdbc40
             sqlType == SQLData.XML_LOCATOR) 
             && statement_ != null) //@mdrs2                  //@xml3
            statement_.setAssociatedWithLocators(true);             //@KBL

        if(wasNull_ || wasDataMappingError_)
            return null;
        else
            return row_.getSQLData (columnIndex);
    }



    /**
    Tests if a DataTruncation occurred on the read of a piece of
    data and posts a DataTruncation warning if so.
    
    @param  columnIndex   The column index (1-based).
    @param  data         The data that was read, or null for SQL NULL.
    @param  exceptionOnTrunc Flag to notify method whether or not to throw an SQLException when there is truncation.
    **/
    private void testDataTruncation (int columnIndex, SQLData data, boolean exceptionOnTrunc) throws SQLException //@trunc
    {
        if(wasDataMappingError_)
        {
            postWarning(new DataTruncation(columnIndex, false, true, -1, -1));
        }

        if(data != null)
        {
            int truncated = data.getTruncated ();
            if(truncated > 0)
            {
                //if 610 and number data type and called on certain getX() methods, then throw SQLException
                //if 610, follow Native driver to thow exc if data is text and getX() is a number type getter method.
                if((((AS400JDBCConnection)connection_).getVRM() >= JDUtilities.vrm610)  && (exceptionOnTrunc == true))   //@trunc //@trunc2 only use exceptionOnTrunc as flag
                {                                                                    //@trunc
                    JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH); //@trunc
                }                                                                    //@trunc
                int actualSize = data.getActualSize ();
                postWarning (new DataTruncation (columnIndex, false, true,
                                                 actualSize, actualSize - truncated));
            }
        }
    }



    /**
    Indicates if the last column read has the value of SQL NULL.
    
    @return     true if the value is SQL NULL;
                false otherwise.
    
    @exception  SQLException    If the result set is not open.
    **/
    public boolean wasNull ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            checkOpen ();
            return wasNull_;
        }
    }



    /*---------------------------------------------------------*/
    /*                                                         */
    /* UPDATE DATA METHODS.                                    */
    /*                                                         */
    /*---------------------------------------------------------*/



    /**
    Checks necessary conditions before updating a row.  All
    update methods should call this before updating.
    
    @exception  SQLException    If the result set is not open
                                or the result set is not updatable.
    **/
    private void beforeUpdate ()
    throws SQLException
    {
        checkOpen ();

        if(concurrency_ != CONCUR_UPDATABLE)
            JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
    }



    // JDBC 2.0
    /**
    Cancels all pending updates that have been made since the last 
    call to updateRow().  If no updates have been made or updateRow() 
    has already been called, then this method has no effect.
    
    @exception  SQLException    If the result set is not open
                                or the result set is not updatable.
    **/                            
    public void cancelRowUpdates ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            beforeUpdate ();

            for(int i = 0; i < columnCount_; ++i)
                updateSet_[i] = false;
        }
    }



    // JDBC 2.0
    /**
    Deletes the current row from the result set and the database.
    After deleting a row, the cursor position is no longer valid,
    so it must be explicitly repositioned.
    
    @exception SQLException If the result set is not open,
                            the result set is not updatable,
                            the cursor is not positioned on a row,
                            the cursor is positioned on the insert row,
                            or an error occurs.
    **/
    public void deleteRow ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            beforeUpdate ();

            if(positionValid_ == false)                                         // @D9a
                JDError.throwSQLException (JDError.EXC_CURSOR_POSITION_INVALID); // @D9a

            if(positionInsert_ == true)
                JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);

            if(JDTrace.isTraceOn ())
                JDTrace.logInformation (this, "Deleting a row.");

            // Prepare the delete statement the first time
            // we need it.
            if(deleteStatement_ == null)
            {                                             // @D3C
                StringBuffer buffer = new StringBuffer();                               // @D3A
                buffer.append("DELETE FROM ");                                          // @D3A
                buffer.append(selectTable_);                                            // @D3A
                buffer.append(" WHERE CURRENT OF \"");                                  // @D3A
                buffer.append(cursorName_);                                             // @D3A
                buffer.append("\"");                                                    // @D3A
                deleteStatement_ = connection_.prepareStatement(buffer.toString());     // @D3C
            }                                                                           // @D3A

            deleteStatement_.execute ();

            // Mark the cursor position not valid.
            positionValid_ = false;
            rowCache_.flush ();
        }
    }



    // JDBC 2.0
    /**
    Inserts the contents of the insert row into the result set
    and the database.
    
    @exception SQLException If the result set is not open,
                            the result set is not updatable,
                            the cursor is not positioned on the insert row,
                            a column that is not nullable was not specified,
                            or an error occurs.
    **/
    //
    // Implementation note:
    //
    // * It seems inefficient to prepare and execute a
    //   new statement each time, but we really have no choice,
    //   since (1.) The combination of columns that we want
    //   to insert could change every time and (2.) We need
    //   to use parameter markers to be able to set columns
    //   not representable using SQL literals.
    //
    public void insertRow ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            beforeUpdate ();

            if(positionInsert_ == false)
                JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);

            // Build up the SQL statement.  Make sure a correlation name
            // is not used.
            StringBuffer buffer = new StringBuffer ();
            buffer.append ("INSERT INTO ");       
            buffer.append (selectTable_);
            buffer.append (" (");
            StringBuffer values = new StringBuffer ();
            int columnsSet = 0;
            for(int i = 0; i < columnCount_; ++i)
            {
                if(updateSet_[i] == true)
                {
                    if(columnsSet++ > 0)
                    {
                        buffer.append (",");
                        values.append (",");
                    }
                    buffer.append ("\"");                       // @D6a
                    buffer.append (prepareQuotes(row_.getFieldName (i+1))); //@DELIMc
                    buffer.append ("\"");                       // @D6a
                    values.append ("?");
                }
            }
            if(columnsSet == 0)
                buffer.append (prepareQuotes(row_.getFieldName (1))); //@DELIMc
            buffer.append (") VALUES (");
            if(columnsSet == 0)
                buffer.append ("NULL");
            else
                buffer.append (values.toString());          // added toString() because 1.4 has a method that appends a string buffer
            buffer.append (")");

            if(JDTrace.isTraceOn ())
                JDTrace.logInformation (this, "Inserting a row: " + buffer);

            // Prepare the statement and set the parameters.
            PreparedStatement insertStatement = connection_.prepareStatement (buffer.toString ());
            for(int i = 0, columnsSet2 = 0; i < columnCount_; ++i)
            {
                if(updateSet_[i] == true)
                {
                    Object columnValue = updateRow_.getSQLData (i+1).getObject ();
                    if(updateNulls_[i])
                        insertStatement.setNull (++columnsSet2, row_.getSQLType (i+1).getType ());
                    else if(updateDefaults_[i])                                                         //@EIA
                        ((AS400JDBCPreparedStatement)insertStatement).setDB2Default(++columnsSet2);     //@EIA
                    else if(updateUnassigned_[i])                                                       //@EIA
                        ((AS400JDBCPreparedStatement)insertStatement).setDB2Unassigned(++columnsSet2);  //@EIA
                    else
                        insertStatement.setObject (++columnsSet2, columnValue);                
                    updateSet_[i] = false;
                }
            }

            // Execute and close the statement.  Dispatch the warnings,
            // if any.
            insertStatement.executeUpdate ();
            SQLWarning warnings = insertStatement.getWarnings ();
            if(warnings != null)
                postWarning (warnings); // The whole link gets added.
            insertStatement.close ();

            rowCache_.flush ();
        }
    }


    //@DELIMa
    // Prepares a name to be double-quoted.
    private final static String prepareQuotes(String name)
    {
      return JDUtilities.prepareForDoubleQuotes(name);
    }


    // JDBC 2.0
    /**
    Indicates if the current row has been deleted. A result set
    of type TYPE_SCROLL_INSENSITIVE may contain rows that have
    been deleted.
    
    @return true if current row has been deleted; false otherwise.
    
    @exception SQLException If an error occurs.
    **/
    public boolean rowDeleted ()
    throws SQLException
    {
        synchronized(internalLock_)
        {                                            // @D1A
            // We almost always return false because we don't allow 
            // updates to scroll insensitive or forward only result 
            // sets, so we never have holes.
            //
            // The only case where this may be true is if they call
            // it immediately after deleting a row and then don't
            // reposition the cursor.
            return((positionValid_ == false) && (positionInsert_ == false)
                   && ((positionFromFirst_ > 0) || (positionFromLast_ > 0)));
        }
    }



    // JDBC 2.0
    /**
    Indicates if the current row has been inserted.  This driver does
    not support this method.
    
    @return Always false.  
    
    @exception SQLException If an error occurs.
    **/
    public boolean rowInserted ()
    throws SQLException
    {
        // For forward only and scroll insensitive result sets, we don't
        // have the ability to detect this.  For scroll sensitive result
        // sets, the inserts are visible, but we don't have access to which
        // were inserted.  So we always return false.
        return false; 
    }



    // JDBC 2.0
    /**
    Indicates if the current row has been updated.   This driver does
    not support this method.
    
    @return Always false.
    
    @exception SQLException If an error occurs.
    **/
    public boolean rowUpdated ()
    throws SQLException
    {
        // For forward only and scroll insensitive result sets, we don't
        // have the ability to detect this.  For scroll sensitive result
        // sets, the inserts are visible, but we don't have access to which
        // were inserted.  So we always return false.
        return false; 
    }



    /**
    Tests if a DataTruncation occurred on the write of a piece of
    data and posts a DataTruncation warning if so.
    
    @param  columnIndex   The column index (1-based).
    @param  data          The data that was written, or null for SQL NULL.
    @since Modification 5
    **/
    private void testDataTruncation2 (int columnIndex, SQLData data)
    throws SQLException                                                               // @D5A //@trunc
    {
        if(data != null)
        {
           connection_.testDataTruncation(null, this, columnIndex, false, data, null);
        }
        
    }



    //@G4A JDBC 3.0
    /**
    Updates the value of a column as an Array object.
    DB2 for IBM i does not support arrays.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null if the value is SQL NULL.
    
    @exception  SQLException    Always thrown because DB2 for IBM i does not support arrays.
    @since Modification 5
    **/
    public void updateArray (int columnIndex, Array columnValue)
    throws SQLException
    {
        JDError.throwSQLException (JDError.EXC_DATA_TYPE_MISMATCH);
    }



    //@G4A JDBC 3.0
    /**
    Updates the value of a column as an Array object.
    DB2 for IBM i does not support arrays.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateArray("\"MixedCase\"", columnValue).
    
    @param  columnName   The column name.
    @param  columnValue  The column value or null if the value is SQL NULL.
    
    @exception  SQLException    Always thrown because DB2 for IBM i does not support arrays.
    **/
    public void updateArray (String columnName, Array columnValue)
    throws SQLException
    {
        JDError.throwSQLException (JDError.EXC_DATA_TYPE_MISMATCH);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using an ASCII stream value.
    The driver reads the data from the stream as needed until no more
    bytes are available.  The driver converts this to an SQL VARCHAR
    value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    @param  length        The length.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, the
                                requested conversion is not valid,
                                the length is not
                                valid, the input stream does not contain
                                ASCII characters, or an error happens
                                while reading the input stream.
    **/
    public void updateAsciiStream (int columnIndex,
                                   InputStream columnValue,
                                   int length)
    throws SQLException
    {
        if(length < 0)
            JDError.throwSQLException (JDError.EXC_BUFFER_LENGTH_INVALID);
        // @B1D if (columnValue == null)
        // @B1D     JDError.throwSQLException (JDError.EXC_PARAMETER_TYPE_INVALID);

        updateValue (columnIndex, 
                     (columnValue == null) ? null : JDUtilities.streamToString (columnValue, length, "ISO8859_1"), // @B1C
                     null, -1); //@P0C
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using an ASCII stream value.
    The driver reads the data from the stream as needed until no more
    bytes are available.  The driver converts this to an SQL VARCHAR
    value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateAsciiStream("\"MixedCase\"", columnValue, length).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    @param  length        The length.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, the
                                requested conversion is not valid,
                                the length is not valid, 
                                the input stream does not contain
                                ASCII characters, or an error happens
                                while reading the input stream.
    **/
    public void updateAsciiStream (String columnName,
                                   InputStream columnValue,
                                   int length)
    throws SQLException
    {
        updateAsciiStream (findColumn (columnName), columnValue, length);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a BigDecimal value.  The
    driver converts this to an SQL NUMERIC value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateBigDecimal (int columnIndex, BigDecimal columnValue)
    throws SQLException
    {
        // @B1D if (columnValue == null)
        // @B1D     JDError.throwSQLException (JDError.EXC_PARAMETER_TYPE_INVALID);

        updateValue (columnIndex, columnValue, null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a BigDecimal value.  The
    driver converts this to an SQL NUMERIC value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateBigDecimal("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public void updateBigDecimal (String columnName, BigDecimal columnValue)
    throws SQLException
    {
        updateBigDecimal (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a binary stream value.
    The driver reads the data from the stream as needed until no more
    bytes are available.  The driver converts this to an SQL
    VARBINARY value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    @param  length        The length.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid,
                                the length is not valid, or an error 
                                happens while reading the input stream.
    **/
    public void updateBinaryStream (int columnIndex,
                                    InputStream columnValue,
                                    int length)
    throws SQLException
    {
        if(length < 0)
            JDError.throwSQLException (JDError.EXC_BUFFER_LENGTH_INVALID);
        // @B1D if (columnValue == null)
        // @B1D     JDError.throwSQLException (JDError.EXC_PARAMETER_TYPE_INVALID);

        updateValue (columnIndex, 
                     (columnValue == null) ? null : JDUtilities.streamToBytes (columnValue, length), // @B1C
                     null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a binary stream value.
    The driver reads the data from the stream as needed until no more
    bytes are available.  The driver converts this to an SQL
    VARBINARY value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateBinaryStream("\"MixedCase\"", columnValue, length).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    @param  length        The length.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid,
                                the length is not valid, or an error 
                                happens while reading the input stream.
    **/
    public void updateBinaryStream (String columnName,
                                    InputStream columnValue,
                                    int length)
    throws SQLException
    {
        updateBinaryStream (findColumn (columnName), columnValue, length);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java boolean value.
    The driver converts this to an SQL SMALLINT value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    //
    // Implementation note:
    //
    // The spec defines this in terms of SQL BIT, but DB2 for IBM i
    // does not support that.
    //
    public void updateBoolean (int columnIndex, boolean columnValue)
    throws SQLException
    {
        updateValue (columnIndex, new Short ((short) (columnValue ? 1 : 0)), null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java boolean value.
    The driver converts this to an SQL SMALLINT value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateBoolean("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    @since Modification 5
    **/
    //
    // Implementation note:
    //
    // The spec defines this in terms of SQL BIT, but DB2 for IBM i
    // does not support that.
    //
    public void updateBoolean (String columnName, boolean columnValue)
    throws SQLException
    {
        updateBoolean (findColumn (columnName), columnValue);
    }



    //@G4A JDBC 3.0
    /**
    Updates a column in the current row using a Java Blob value.
    The driver converts this to an SQL BLOB value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    @since Modification 5
    **/
    public void updateBlob (int columnIndex, Blob columnValue)
    throws SQLException
    {
        updateValue (columnIndex, columnValue, null, -1);
    }



    //@G4A JDBC 3.0
    /**
    Updates a column in the current row using a Java Blob value.
    The driver converts this to an SQL BLOB value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateBlob("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateBlob (String columnName, Blob columnValue)
    throws SQLException
    {
        updateValue (findColumn (columnName), columnValue, null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java byte value.
    The driver converts this to an SQL SMALLINT value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    //
    // Implementation note:
    //
    // The spec defines this in terms of SQL TINYINT, but DB2 for IBM i
    // does not support that.
    //
    public void updateByte (int columnIndex, byte columnValue)
    throws SQLException
    {
        updateValue (columnIndex, new Short (columnValue), null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java byte value.
    The driver converts this to an SQL SMALLINT value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateByte("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    //
    // Implementation note:
    //
    // The spec defines this in terms of SQL TINYINT, but DB2 for IBM i
    // does not support that.
    //
    public void updateByte (String columnName, byte columnValue)
    throws SQLException
    {
        updateByte (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java byte array value.
    The driver converts this to an SQL VARBINARY value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateBytes (int columnIndex, byte[] columnValue)
    throws SQLException
    {
        // @B1D if (columnValue == null)
        // @B1D     JDError.throwSQLException (JDError.EXC_PARAMETER_TYPE_INVALID);

        updateValue (columnIndex, columnValue, null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java byte array value.
    The driver converts this to an SQL VARBINARY value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateBytes("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public void updateBytes (String columnName, byte[] columnValue)
    throws SQLException
    {
        updateBytes (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Reader value.
    The driver reads the data from the Reader as needed until no more
    characters are available.  The driver converts this to an SQL VARCHAR
    value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    @param  length        The length.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid,
                                the length is not valid, or an error 
                                happens while reading the input stream.
    **/
    public void updateCharacterStream (int columnIndex,
                                       Reader columnValue,
                                       int length)
    throws SQLException
    {
        if(length < 0)
            JDError.throwSQLException (JDError.EXC_BUFFER_LENGTH_INVALID);
        // @B1D if (columnValue == null)
        // @B1D     JDError.throwSQLException (JDError.EXC_PARAMETER_TYPE_INVALID);

        updateValue (columnIndex, 
                     (columnValue == null) ? null : JDUtilities.readerToString (columnValue, length), // @B1C
                     null, -1); //@P0C
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Reader value.
    The driver reads the data from the Reader as needed until no more
    characters are available.  The driver converts this to an SQL VARCHAR
    value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateCharacterStream("\"MixedCase\"", columnValue, length).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    @param  length        The length.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid,
                                the length is not valid, or an error 
                                happens while reading the input stream.
    @since Modification 5
    **/
    public void updateCharacterStream (String columnName,
                                       Reader columnValue,
                                       int length)
    throws SQLException
    {
        updateCharacterStream (findColumn (columnName), columnValue, length);
    }



    //@G4A JDBC 3.0
    /**
    Updates a column in the current row using a Java Clob value.
    The driver converts this to an SQL CLOB value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex    The column index (1-based).
    @param  columnValue    The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    @since Modification 5
    **/
    public void updateClob (int columnIndex, Clob columnValue)
    throws SQLException
    {
        updateValue (columnIndex, columnValue, null, -1);
    }



    //@G4A JDBC 3.0
    /**
    Updates a column in the current row using a Java Clob value.
    The driver converts this to an SQL CLOB value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateClob("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateClob (String columnName, Clob columnValue)
    throws SQLException
    {
        updateValue (findColumn (columnName), columnValue, null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a java.sql.Date value.
    The driver converts this to an SQL DATE value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateDate (int columnIndex, Date columnValue)
    throws SQLException
    {
        // @B1D if (columnValue == null)
        // @B1D     JDError.throwSQLException (JDError.EXC_PARAMETER_TYPE_INVALID);

        updateValue (columnIndex, columnValue, null, -1); //@P0C
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a java.sql.Date value.
    The driver converts this to an SQL DATE value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateDate("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public void updateDate (String columnName, Date columnValue)
    throws SQLException
    {
        updateDate (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java double value.
    The driver converts this to an SQL DOUBLE value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateDouble (int columnIndex, double columnValue)
    throws SQLException
    {
        updateValue (columnIndex, new Double (columnValue), null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java double value.
    The driver converts this to an SQL DOUBLE value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateDouble("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public void updateDouble (String columnName, double columnValue)
    throws SQLException
    {
        updateDouble (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java float value.
    The driver converts this to an SQL REAL value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateFloat (int columnIndex, float columnValue)
    throws SQLException
    {
        updateValue (columnIndex, new Float (columnValue), null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java float value.
    The driver converts this to an SQL REAL value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateFloat("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public void updateFloat (String columnName, float columnValue)
    throws SQLException
    {
        updateFloat (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java int value.
    The driver converts this to an SQL INTEGER value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateInt (int columnIndex, int columnValue)
    throws SQLException
    {
        updateValue (columnIndex, new Integer (columnValue), null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java int value.
    The driver converts this to an SQL INTEGER value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateInt("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public void updateInt (String columnName, int columnValue)
    throws SQLException
    {
        updateInt (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    // @D0C
    /**
    Updates a column in the current row using a Java long value.
    If the connected system supports SQL BIGINT data, the driver
    converts this to an SQL BIGINT value.  Otherwise, the driver
    converts this to an SQL INTEGER value.  SQL BIGINT data is
    supported on V4R5 and later.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    //
    // Implementation note:
    //
    // The spec defines this in terms of SQL BIGINT, but DB2 for IBM i
    // does not support that until V4R5.
    //
    public void updateLong (int columnIndex, long columnValue)
    throws SQLException
    {        
        updateValue (columnIndex, new Long(columnValue), null, -1); // @D0C
    }



    // JDBC 2.0
    // @D0C
    /**
    Updates a column in the current row using a Java long value.
    If the connected system supports SQL BIGINT data, the driver
    converts this to an SQL BIGINT value.  Otherwise, the driver
    converts this to an SQL INTEGER value.  SQL BIGINT data is
    supported on V4R5 and later.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateLong("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    //
    // Implementation note:
    //
    // The spec defines this in terms of SQL BIGINT, but DB2 for IBM i
    // does not support that until V4R5.
    //
    public void updateLong (String columnName, long columnValue)
    throws SQLException
    {
        updateLong (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using SQL NULL.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateNull (int columnIndex)
    throws SQLException
    {
        updateValue (columnIndex, null, null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using SQL NULL.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateNull("\"MixedCase\"").
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName  The column name.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public void updateNull (String columnName)
    throws SQLException
    {
        updateNull (findColumn (columnName));
    }



    //@EIA 550 extended indicator defaults
    /**
    Updates a column in the current row to the SQL Default.
    @param  columnIndex  The column index (1-based).
    @exception  SQLException    If the statement is not open,
                                the index is not valid, the parameter
                                is not an input parameter.
    **/
    public void updateDB2Default(int columnIndex) throws SQLException
    {
         updateValueExtendedIndicator (columnIndex, 1);  //1 is default    
    }

    //@EIA 550 extended indicator defaults
    /**
    Updates a column in the current row to the SQL Default.  Same as updateDB2Default.
    @param  columnIndex  The column index (1-based).
    @exception  SQLException    If the statement is not open,
                                the index is not valid, the parameter
                                is not an input parameter.
    **/
    public void updateDBDefault(int columnIndex) throws SQLException
    {
         updateDB2Default(columnIndex);   
    }
    
    //@EIA 550 extended indicator defaults
    /**
    Updates a column in the current row to the SQL Default.
    @param  columnName  The column name.
    @exception  SQLException    If the statement is not open,
                                the index is not valid, the parameter
                                is not an input parameter.
    **/
    public void updateDB2Default(String columnName) throws SQLException
    {
        updateDB2Default (findColumn (columnName));  
    }
    
    //@EIA 550 extended indicator defaults
    /**
    Updates a column in the current row to the SQL Default.  Same as updateDB2Default.
    @param  columnName  The column name.
    @exception  SQLException    If the statement is not open,
                                the index is not valid, the parameter
                                is not an input parameter.
    **/
    public void updateDBDefault(String columnName) throws SQLException
    {
        updateDB2Default (findColumn (columnName));  
    }
   
    
    //@EIA 550 extended indicator defaults
    /**
    Updates a column in the current row to the SQL Unassigned.
    @param  columnIndex  The column index (1-based).
    @exception  SQLException    If the statement is not open,
                                the index is not valid, the parameter
                                is not an input parameter.
    **/
    public void updateDB2Unassigned(int columnIndex) throws SQLException
    {                                          
        updateValueExtendedIndicator (columnIndex, 2);  //2 is unassigned
    }

    //@EIA 550 extended indicator defaults
    /**
    Updates a column in the current row to the SQL Unassigned.  Same as updtaeDB2Unassigned.
    @param  columnIndex  The column index (1-based).
    @exception  SQLException    If the statement is not open,
                                the index is not valid, the parameter
                                is not an input parameter.
    **/
    public void updateDBUnassigned(int columnIndex) throws SQLException
    {                                          
        updateDB2Unassigned(columnIndex);
    }
    

    //@EIA 550 extended indicator defaults
    /**
    Updates a column in the current row to the SQL Unassigned.
    @param  columnName  The column name.
    @exception  SQLException    If the statement is not open,
                                the index is not valid, the parameter
                                is not an input parameter.
    **/
    public void updateDB2Unassigned(String columnName) throws SQLException
    {                                          
        updateDB2Unassigned (findColumn (columnName));  
    }


    //@EIA 550 extended indicator defaults
    /**
    Updates a column in the current row to the SQL Unassigned.  Same as updateDB2Unassigned.
    @param  columnName  The column name.
    @exception  SQLException    If the statement is not open,
                                the index is not valid, the parameter
                                is not an input parameter.
    **/
    public void updateDBUnassigned(String columnName) throws SQLException
    {                                          
        updateDB2Unassigned (findColumn (columnName));  
    }

    
    // JDBC 2.0
    /**
    Updates a column in the current row using an Object value.
    The driver converts this to a value of an SQL type, depending on
    the type of the specified value.  The JDBC specification defines
    a standard mapping from Java types to SQL types.  In the cases
    where an SQL type is not supported by DB2 for IBM i, the 
    <a href="doc-files/SQLTypes.html#unsupported">next closest matching type</a>
    is used.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, 
                                or the requested conversion is not valid.
    **/
    public void updateObject (int columnIndex, Object columnValue)
    throws SQLException
    {
        // @B1D if (columnValue == null)
        // @B1D     JDError.throwSQLException (JDError.EXC_DATA_TYPE_MISMATCH);

        updateValue (columnIndex, columnValue, null, -1); //@P0C
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using an Object value.
    The driver converts this to a value of an SQL type, depending on
    the type of the specified value.  The JDBC specification defines
    a standard mapping from Java types to SQL types.  In the cases
    where an SQL type is not supported by DB2 for IBM i, the 
    <a href="doc-files/SQLTypes.html#unsupported">next closest matching type</a>
    is used.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateObject("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, 
                                or the requested conversion is not valid.
    **/
    public void updateObject (String columnName, Object columnValue)
    throws SQLException
    {
        updateObject (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using an Object value.
    The driver converts this to a value of an SQL type, depending on
    the type of the specified value.  The JDBC specification defines
    a standard mapping from Java types to SQL types.  In the cases
    where an SQL type is not supported by DB2 for IBM i, the 
    <a href="doc-files/SQLTypes.html#unsupported">next closest matching type</a>
    is used.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    @param  scale         The number of digits after the decimal
                          if SQL type is DECIMAL or NUMERIC.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, 
                                the scale is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateObject (int columnIndex,
                              Object columnValue,
                              int scale)
    throws SQLException
    {
        // @B1D if (columnValue == null)
        // @B1D     JDError.throwSQLException (JDError.EXC_DATA_TYPE_MISMATCH);

        if(scale < 0)
            JDError.throwSQLException (JDError.EXC_SCALE_INVALID);

/* ifdef JDBC40 
        if (columnValue instanceof SQLXML)                   //@xmlspec
            updateSQLXML(columnIndex, (SQLXML)columnValue);  //@xmlspec
        else
endif */ 
            updateValue (columnIndex, columnValue, null, scale); //@P0C
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using an Object value.
    The driver converts this to a value of an SQL type, depending on
    the type of the specified value.  The JDBC specification defines
    a standard mapping from Java types to SQL types.  In the cases
    where an SQL type is not supported by DB2 for IBM i, the 
    <a href="doc-files/SQLTypes.html#unsupported">next closest matching type</a>
    is used.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateObject("\"MixedCase\"", columnValue, scale).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    @param  scale         The number of digits after the decimal
                          if SQL type is DECIMAL or NUMERIC.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, 
                                the scale is not valid, or the
                                requested conversion is not valid.
    @since Modification 5
    **/
    public void updateObject (String columnName,
                              Object columnValue,
                              int scale)
    throws SQLException
    {
        updateObject (findColumn (columnName), columnValue, scale);
    }



    //@G4A JDBC 3.0
    /**
    Updates the value of an SQL REF output parameter as a Ref value.
    DB2 for IBM i does not support structured types.
       
    @param  columnIndex     The column index (1-based).
    @param  columnValue     The column value or null to update
                                      the value to SQL NULL.
        
    @exception  SQLException    Always thrown because DB2 for IBM i does not support REFs.
    @since Modification 5
    **/
    public void updateRef (int columnIndex, Ref columnValue)
    throws SQLException
    {
        JDError.throwSQLException (JDError.EXC_DATA_TYPE_MISMATCH);
    }



    //@G4A JDBC 3.0
    /**
    Updates the value of an SQL REF output parameter as a Ref value.
    DB2 for IBM i does not support structured types.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateRef("\"MixedCase\"", columnValue).
       
    @param  columnName      The column name.
    @param  columnValue     The column value or null to update
                            the value to SQL NULL.
        
    @exception  SQLException    Always thrown because DB2 for IBM i does not support REFs.
    **/
    public void updateRef (String columnName, Ref columnValue)
    throws SQLException
    {
        JDError.throwSQLException (JDError.EXC_DATA_TYPE_MISMATCH);
    }



    // JDBC 2.0
    /**
    Updates the database with the new contents of the current
    row.
    
    @exception SQLException If the result set is not open,
                            the result set is not updatable,
                            the cursor is not positioned on a row,
                            the cursor is positioned on the insert row,
                            or an error occurs.
    **/
    //
    // Implementation note:
    //
    // * It seems inefficient to prepare and execute a
    //   new statement each time, but we really have no choice,
    //   since (1.) The combination of columns that we want
    //   to update could change every time and (2.) We need
    //   to use parameter markers to be able to set columns
    //   not representable using SQL literals.
    //
    public void updateRow ()
    throws SQLException
    {
        beforeUpdate ();
        ConvTable convTable = null;                                                 //@K1A             
        
        if((positionInsert_ == true) || (positionValid_ == false))
            JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);

        // Build up the SQL statement.
        StringBuffer buffer = new StringBuffer ();
        buffer.append ("UPDATE ");
        buffer.append (selectTable_);
        if(correlationName_ != null)
        {
            buffer.append (" AS ");
            buffer.append (correlationName_);
        }
        buffer.append (" SET ");
        int columnsSet = 0;
        for(int i = 0; i < columnCount_; ++i)
        {
            if(updateSet_[i] == true)
            {
                if(columnsSet++ > 0)
                    buffer.append (",");
                buffer.append ("\"");                       // @D6a
                // @K1A If we have column descriptors, use them to get the column label.                   //@K1A
                if(statement_ != null)                                                                     //@K1A
                {
                    // If we have extendedDescriptors, send a ConvTable to convert them, else pass null    // @K1A
                    if(extendedDescriptors_ != null)                                                        // @K1A@P6C
                    {
                        // @K1A
                        convTable = ((AS400JDBCConnection)connection_).converter_;                         // @K1A
                        String columnName = extendedDescriptors_.getColumnDescriptors(i+1, convTable, settings_).getBaseColumnName(convTable); //@K1A     //@K2A changed from getColumnLabel //@SS1//@P6C//@Q8C
                        if(columnName != null) {
                            if (((AS400JDBCConnection)connection_).getVRM() < JDUtilities.vrm540) { //@DELIMa
                              buffer.append(JDUtilities.stripOuterDoubleQuotes(columnName));  // if pre-V5R4, just strip outer quotes (no double-up necessary)
                            }
                            else {
                              buffer.append(prepareQuotes(columnName));  // if V5R4+, also need to double-up any embedded quotes @DELIMc
                            }
                        } 
                        else {  // Column name is null, so get it from the row.
                          // We're using extended descriptors,
                          // so we'll need to double-up embedded quotes.
                          buffer.append(prepareQuotes(row_.getFieldName(i+1))); //@DELIMa
                        }
                    }                                                                                      // @K1A
                    else                                                                                   // @K1A
                        buffer.append (prepareQuotes(row_.getFieldName (i+1)));                                           // @K1A @DELIMc
                                                                                                           // @K1A
                }
                else
                    buffer.append(prepareQuotes(row_.getFieldName(i+1)));
                buffer.append ("\"=?");                     // @D6c @DELIMc
            }
        }
        buffer.append (" WHERE CURRENT OF \"");                                 // @D3C
        buffer.append (cursorName_);
        buffer.append ("\"");                                                   // @D3C

        // Only go through with this if columns were set.
        if(columnsSet > 0)
        {

            if(JDTrace.isTraceOn ())
                JDTrace.logInformation (this, "Updating a row: " + buffer);

            // Prepare the statement and set the parameters.
            PreparedStatement updateStatement = connection_.prepareStatement (buffer.toString ());
            try{
                for(int i = 0, columnsSet2 = 0; i < columnCount_; ++i)
                {
                    if(updateSet_[i] == true)
                    {
                        Object columnValue = updateRow_.getSQLData (i+1).getObject ();
                        if(updateNulls_[i] == true)
                            updateStatement.setNull (++columnsSet2, row_.getSQLType (i+1).getType ());
                        else if(updateDefaults_[i])                                                         //@EIA
                            ((AS400JDBCPreparedStatement)updateStatement).setDB2Default(++columnsSet2);     //@EIA
                        else if(updateUnassigned_[i])                                                       //@EIA
                            ((AS400JDBCPreparedStatement)updateStatement).setDB2Unassigned(++columnsSet2);  //@EIA
                        else
                            updateStatement.setObject (++columnsSet2, columnValue);                    
                    }
                }

                // Execute and close the statement.  Dispatch the warnings,
                // if any.
                updateStatement.executeUpdate ();
                SQLWarning warnings = updateStatement.getWarnings ();
                if(warnings != null)
                    postWarning (warnings); // The whole link gets added.
            }
            finally{
                //Always close the statement - Fix for JTOpen Bug 4148
                updateStatement.close ();
            }

            rowCache_.flush ();
        }
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java short value.
    The driver converts this to an SQL SMALLINT value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateShort (int columnIndex, short columnValue)
    throws SQLException
    {
        updateValue (columnIndex, new Short (columnValue), null, -1);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a Java short value.
    The driver converts this to an SQL SMALLINT value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateShort("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public void updateShort (String columnName, short columnValue)
    throws SQLException
    {
        updateShort (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a String value.
    The driver converts this to an SQL VARCHAR value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid,
                                or the requested conversion is not valid.
    **/
    public void updateString (int columnIndex, String columnValue)
    throws SQLException
    {
        // @B1D if (columnValue == null)
        // @B1D     JDError.throwSQLException (JDError.EXC_DATA_TYPE_MISMATCH);
    	
        //if(columnIndex <= columnCount_ && columnIndex > 0) //@pdc
        //    columnValue = AS400BidiTransform.convertDataToHostCCSID(columnValue, (AS400JDBCConnection) connection_,	((JDServerRow) row_).getCCSID(columnIndex));	//Bidi-HCG
    	
        updateValue (columnIndex, columnValue, null, -1); //@P0C
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a String value.
    The driver converts this to an SQL VARCHAR value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateString("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public void updateString (String columnName, String columnValue)
    throws SQLException
    {
        updateString (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a java.sql.Time value.
    The driver converts this to an SQL TIME value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateTime (int columnIndex, Time columnValue)
    throws SQLException
    {
        // @B1D if (columnValue == null)
        // @B1D     JDError.throwSQLException (JDError.EXC_PARAMETER_TYPE_INVALID);

        updateValue (columnIndex, columnValue, null, -1); //@P0C
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a java.sql.Time value.
    The driver converts this to an SQL TIME value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateTime("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public void updateTime (String columnName, Time columnValue)
    throws SQLException
    {
        updateTime (findColumn (columnName), columnValue);
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a java.sql.Timestamp value.
    The driver converts this to an SQL TIMESTAMP value.
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    public void updateTimestamp (int columnIndex, Timestamp columnValue)
    throws SQLException
    {
        // @B1D if (columnValue == null)
        // @B1D     JDError.throwSQLException (JDError.EXC_PARAMETER_TYPE_INVALID);

        updateValue (columnIndex, columnValue, null, -1); //@P0C
    }



    // JDBC 2.0
    /**
    Updates a column in the current row using a java.sql.Timestamp value.
    The driver converts this to an SQL TIMESTAMP value.
    To perform a case-sensitive search use a quoted String
    for columnName as in: ResultSet.updateTimestamp("\"MixedCase\"", columnValue).
    
    <p>This does not update the database directly.  Instead, it updates
    a copy of the data in memory.  Call updateRow() or insertRow() to
    update the database.
    
    @param  columnName    The column name.
    @param  columnValue   The column value or null to update
                                      the value to SQL NULL.
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column name is not found, or the
                                requested conversion is not valid.
    **/
    public void updateTimestamp (String columnName, Timestamp columnValue)
    throws SQLException
    {
        updateTimestamp (findColumn (columnName), columnValue);
    }



    /**
    Updates a column for the specified index, and performs all
    appropriate validation.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The column value or null if the value
                          is SQL NULL.
    @param  calendar      The calendar, or null if not
                          applicable.
    @param  scale         The scale, or -1 if not applicable.                      
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
  private void updateValue(int columnIndex, Object columnValue,
      Calendar calendar, int scale) throws SQLException {
    synchronized (internalLock_) { // @D1A
      beforeUpdate();

      // Check that there is a current row.
      if ((positionValid_ == false) && (positionInsert_ == false))
        JDError.throwSQLException(JDError.EXC_CURSOR_POSITION_INVALID);

      // Validate The column index.
      if (columnIndex < 1)
        JDError.throwSQLException(JDError.EXC_DESCRIPTOR_INDEX_INVALID, columnIndex+"<1");
      if (columnIndex > columnCount_)
        JDError.throwSQLException(JDError.EXC_DESCRIPTOR_INDEX_INVALID, columnIndex+">"+columnCount_);

      // Set the update value. If there is a type mismatch,
      // set() with throw an exception.
      SQLData sqlData = updateRow_.getSQLType(columnIndex); // @P0C
      int columnIndex0 = columnIndex - 1;

      // @G7A If the data is a locator, then set its handle.
      int sqlType = sqlData.getSQLType(); // @xml3
      if (columnValue != null
          && (sqlType == SQLData.CLOB_LOCATOR
              || sqlType == SQLData.BLOB_LOCATOR
              || sqlType == SQLData.DBCLOB_LOCATOR
              || sqlType == SQLData.NCLOB_LOCATOR || // @pda jdbc40
          sqlType == SQLData.XML_LOCATOR)) // @xml3
      { 
    	  // @G8C //@G7A
    	// @J5A  Restructured to use instanceof to avoid ClassCastException
        if (columnValue instanceof AS400JDBCBlobLocator) { // @J5A
          try { // @G7A 
            statement_.setAssociatedWithLocators(true); // @KBL
            SQLLocator sqlDataAsLocator = (SQLLocator) sqlData; // @G7A
            sqlDataAsLocator.setHandle(((AS400JDBCBlobLocator) columnValue)
                .getHandle()); // @G7A
          } // @G7A
          catch (ClassCastException cce) // @G7A
          {
            /* ignore */// @G7A
          } // @G7A
        } else if (columnValue instanceof AS400JDBCClobLocator) { // @J5A
          try { // @G7A
            statement_.setAssociatedWithLocators(true); // @KBL
            SQLLocator sqlDataAsLocator = (SQLLocator) sqlData; // @G7A
            sqlDataAsLocator.setHandle(((AS400JDBCClobLocator) columnValue)
                .getHandle()); // @G7A
          } // @G7A
          catch (ClassCastException cce) // @G7A
          {
            /* ignore */
          } // @G7A
        } else if (columnValue instanceof AS400JDBCNClobLocator) { // @J5A
          try // @PDA jdbc40 - following upon existing design
          { // @PDA jdbc40
            statement_.setAssociatedWithLocators(true); // @KBL
            SQLLocator sqlDataAsLocator = (SQLLocator) sqlData; // @PDA jdbc40
            sqlDataAsLocator.setHandle(((AS400JDBCNClobLocator) columnValue)
                .getHandle()); // @PDA jdbc40
          } // @PDA jdbc40
          catch (ClassCastException cce) // @PDA jdbc40
          {
            // ignore
          }
        } else if (columnValue instanceof AS400JDBCSQLXMLLocator) { // @J5A
          try // @olddesc
          { // @olddesc
            statement_.setAssociatedWithLocators(true); // @KBL
            SQLLocator sqlDataAsLocator = (SQLLocator) sqlData; // @olddesc
            sqlDataAsLocator.setHandle(((AS400JDBCSQLXMLLocator) columnValue)
                .getHandle()); // @olddesc
          } // @olddesc
          catch (ClassCastException cce) // @olddesc
          {
            // ignore
          }
        }
      }

      if (columnValue != null)
        sqlData.set(columnValue, calendar, scale);
      updateNulls_[columnIndex0] = (columnValue == null);
      updateDefaults_[columnIndex0] = false; // @EIA
      updateUnassigned_[columnIndex0] = false; // @EIA
      updateSet_[columnIndex0] = true;

      if (dataTruncation_) // @B2A
        testDataTruncation2(columnIndex, sqlData); // @B2C
    }
  }


    //@PDA jdbc40
    /**
     * Retrieves the holdability of this <code>ResultSet</code> object
     * @return  either <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
     * The holdability is derived in this order of precedence:
       <ul>
       <li>1.  The holdability, if any, that was specified on statement creation using
        the methods createStatement(), prepareCall(), or prepareStatement() on the 
        Connection object.
       <li>2.  The holdability specified using the method setHoldability(int)
        if this method was called on the Connection object.
       <li>3.  If neither of above methods were called, the value of the 
       <code> cursor hold </code> 
       <a href="doc-files/JDBCProperties.html" target="_blank">driver property</a>.</ul>   
       Full functionality of #1 and #2 requires OS/400 v5r2
       or IBM i.  If connecting to OS/400 V5R1 or earlier, 
       the value specified on these two methods will be ignored and the default holdability
       will be the value of #3.
     * @throws SQLException if a database error occurs
     */
    public int getHoldability() throws SQLException
    {
        synchronized(internalLock_)
        {
            checkOpen ();
            
            //@cur return value from cursor attribues if exists else return value as done in pre 550                                                               
            if( statement_ != null )                                                     //@cur
            {                                                                            //@cur
                int vrm = 0;                                                             //@cur3
                if(connection_ != null)                                                  //@cur3
                    vrm = ((AS400JDBCConnection)connection_).getVRM();                   //@cur3
                if(statement_.cursor_.getCursorAttributeHoldable() == 0 
                        &&  (vrm <= JDUtilities.vrm610 
                             || (vrm >= JDUtilities.vrm710 && statement_.cursor_.getCursorIsolationLevel() != 0)))                  //@cur //@cur3 *none is always hold
                    return ResultSet.CLOSE_CURSORS_AT_COMMIT;                            //@cur
                else if(statement_.cursor_.getCursorAttributeHoldable() == 1 
                        || (vrm >= JDUtilities.vrm710 && statement_.cursor_.getCursorIsolationLevel() == 0))            //@cur //@cur3
                    return ResultSet.HOLD_CURSORS_OVER_COMMIT;                           //@cur
                else                                                                     //@cur
                {                                                                        //@cur
                    //not able to get from cursor attrs from hostserver
                    if((statement_.resultSetHoldability_ == AS400JDBCResultSet.HOLD_CURSORS_OVER_COMMIT) ||
                            (statement_.resultSetHoldability_ == AS400JDBCResultSet.CLOSE_CURSORS_AT_COMMIT))
                    {
                        return statement_.resultSetHoldability_;    
                    } 
                }
            }                                                                            //@cur
            
            //if above cannot determine holdability, then do best guess
            if(connection_ instanceof AS400JDBCConnection && connection_ != null)        //@cur
                return ((AS400JDBCConnection) connection_).getHoldability();             //@cur  CAST needed for JDK 1.3 
            else                                                                         //@cur
                return ResultSet.CLOSE_CURSORS_AT_COMMIT;                                //@cur (if no statment exists for this, then safest is to return close at commit to prevent cursor reuse errors)
        }
    }


    //@pda jdbc40
    /**
     * Retrieves the value of the designated column in the current row 
     * of this <code>ResultSet</code> object as a
     * <code>java.io.Reader</code> object.
     * It is intended for use when
     * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
     * and <code>LONGNVARCHAR</code> columns.
     *
     * @return a <code>java.io.Reader</code> object that contains the column
     * value; if the value is SQL <code>NULL</code>, the value returned is
     * <code>null</code> in the Java programming language.
     * @param columnIndex
     * @exception SQLException if a database access error occurs
     */
    public Reader getNCharacterStream(int columnIndex) throws SQLException
    {
        synchronized(internalLock_)
        {                                      
            SQLData data = getValue (columnIndex);
            Reader value = (data == null) ? null : data.getNCharacterStream ();
            openReader_ = value;
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2 
            return value;
        }
    }


    //@pda jdbc40
    /**
     * Retrieves the value of the designated column in the current row 
     * of this <code>ResultSet</code> object as a
     * <code>java.io.Reader</code> object.
     * It is intended for use when
     * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
     * and <code>LONGNVARCHAR</code> columns.
     * 
     * @param columnName the name of the column
     * @return a <code>java.io.Reader</code> object that contains the column
     * value; if the value is SQL <code>NULL</code>, the value returned is
     * <code>null</code> in the Java programming language
     * @exception SQLException if a database access error occurs
     */
    public Reader getNCharacterStream(String columnName) throws SQLException
    {
        return getNCharacterStream (findColumn (columnName));
    }


    //@pda jdbc40
  //JDBC40DOC     /**
  //JDBC40DOC      * Retrieves the value of the designated column in the current row
  //JDBC40DOC      * of this <code>ResultSet</code> object as a <code>NClob</code> object
  //JDBC40DOC      * in the Java programming language.
  //JDBC40DOC      *
  //JDBC40DOC      * @param columnIndex
  //JDBC40DOC      * @return a <code>NClob</code> object representing the SQL 
  //JDBC40DOC      *         <code>NCLOB</code> value in the specified column
  //JDBC40DOC      * @exception SQLException if the driver does not support national
  //JDBC40DOC      *         character sets;  if the driver can detect that a data conversion
  //JDBC40DOC      *  error could occur; or if a database access error occurss
  //JDBC40DOC      */
    /* ifdef JDBC40 
    public NClob getNClob(int columnIndex) throws SQLException
    {
        synchronized(internalLock_)
        {                      
            SQLData data = getValue (columnIndex);
            NClob value = (data == null) ? null : data.getNClob ();
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2 
            return value;
        }
    }
   endif */ 

    //@pda jdbc40
 // JDBC40DOC    /**
 // JDBC40DOC     * Retrieves the value of the designated column in the current row
 // JDBC40DOC     * of this <code>ResultSet</code> object as a <code>NClob</code> object
 // JDBC40DOC     * in the Java programming language.
 // JDBC40DOC     *
 // JDBC40DOC     * @param columnName the name of the column from which to retrieve the value
 // JDBC40DOC     * @return a <code>NClob</code> object representing the SQL <code>NCLOB</code>
 // JDBC40DOC     * value in the specified column
 // JDBC40DOC     * @exception SQLException if the driver does not support national
 // JDBC40DOC     *         character sets;  if the driver can detect that a data conversion
 // JDBC40DOC     *  error could occur; or if a database access error occurs
 // JDBC40DOC     */
    /* ifdef JDBC40 
    public NClob getNClob(String columnName) throws SQLException
    {
        return getNClob (findColumn (columnName));
    }
    endif */ 

    //@pda jdbc40
    /**
     * Retrieves the value of the designated column in the current row
     * of this <code>ResultSet</code> object as
     * a <code>String</code> in the Java programming language.
     * It is intended for use when
     * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
     * and <code>LONGNVARCHAR</code> columns.
     *
     * @param columnIndex
     * @return the column value; if the value is SQL <code>NULL</code>, the
     * value returned is <code>null</code>
     * @exception SQLException if a database access error occurs 
    */
    public String getNString(int columnIndex) throws SQLException
    {
        synchronized(internalLock_)
        {                                          
            SQLData data = getValue (columnIndex);
            String value = (data == null) ? null : data.getNString ();
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2 
            return value;
        }
    }


    //@pda jdbc40
    /**
     * Retrieves the value of the designated column in the current row
     * of this <code>ResultSet</code> object as
     * a <code>String</code> in the Java programming language.
     * It is intended for use when
     * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
     * and <code>LONGNVARCHAR</code> columns.
     *
     * @param columnName the SQL name of the column
     * @return the column value; if the value is SQL <code>NULL</code>, the
     * value returned is <code>null</code>
     * @exception SQLException if a database access error occurs
     */
    public String getNString(String columnName) throws SQLException
    {
        return getNString (findColumn (columnName));
    }


    //@pda jdbc40
 // JDBC40DOC    /**
 // JDBC40DOC     * Retrieves the value of the designated column in the current row of this 
 // JDBC40DOC     * <code>ResultSet</code> object as a <code>java.sql.RowId</code> object in the Java
 // JDBC40DOC     * programming language.
 // JDBC40DOC     *
 // JDBC40DOC     * @param columnIndex the column number
 // JDBC40DOC     * @return the column value ; if the value is a SQL <code>NULL</code> the
 // JDBC40DOC     *     value returned is <code>null</code>
 // JDBC40DOC     * @throws SQLException if a database access error occurs
 // JDBC40DOC     */
    /* ifdef JDBC40 
    public RowId getRowId(int columnIndex) throws SQLException
    {
        synchronized(internalLock_)
        {                                                    
            SQLData data = getValue (columnIndex);
            RowId value = (data == null) ? null : data.getRowId();
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2 
            return value;
        }
    }
    endif */ 
    


    //@pda jdbc40
 // JDBC40DOC    /**
 // JDBC40DOC     * Retrieves the value of the designated column in the current row of this 
 // JDBC40DOC     * <code>ResultSet</code> object as a <code>java.sql.RowId</code> object in the Java
 // JDBC40DOC     * programming language.
 // JDBC40DOC     *
 // JDBC40DOC     * @param columnName the name of the column
 // JDBC40DOC     * @return the column value ; if the value is a SQL <code>NULL</code> the
 // JDBC40DOC     *     value returned is <code>null</code>
 // JDBC40DOC     * @throws SQLException if a database access error occurs
 // JDBC40DOC     */
    /* ifdef JDBC40 
    public RowId getRowId(String columnName) throws SQLException
    {
        return getRowId(findColumn (columnName));
    }
    endif */ 

    //@pda jdbc40
 // JDBC40DOC    /**
 // JDBC40DOC     * Retrieves the value of the designated column in  the current row of
 // JDBC40DOC     *  this <code>ResultSet</code> as a
 // JDBC40DOC     * <code>java.sql.SQLXML</code> object in the Java programming language.
 // JDBC40DOC     * @param columnIndex
 // JDBC40DOC     * @return a <code>SQLXML</code> object that maps an <code>SQL XML</code> value
 // JDBC40DOC     * @throws SQLException if a database access error occurs
 // JDBC40DOC     */
    /* ifdef JDBC40 
    public SQLXML getSQLXML(int columnIndex) throws SQLException
    {
        synchronized(internalLock_)
        {    
            SQLData data = getValue (columnIndex);
            SQLXML value = (data == null) ? null : data.getSQLXML();
            testDataTruncation (columnIndex, data, false); //@trunc //@trunc2 
            return value;
        }
    }
    endif */ 


    //@pda jdbc40
 // JDBC40DOC    /**
 // JDBC40DOC     * Retrieves the value of the designated column in  the current row of
 // JDBC40DOC     *  this <code>ResultSet</code> as a
 // JDBC40DOC     * <code>java.sql.SQLXML</code> object in the Java programming language.
 // JDBC40DOC     * @param columnName the name of the column from which to retrieve the value
 // JDBC40DOC     * @return a <code>SQLXML</code> object that maps an <code>SQL XML</code> value
 // JDBC40DOC     * @throws SQLException if a database access error occurs
 // JDBC40DOC     */
    /* ifdef JDBC40 
    public SQLXML getSQLXML(String columnName) throws SQLException
    {
        return getSQLXML(findColumn (columnName));
    }
    endif */ 
    



    //@PDA jdbc40
 // JDBC40DOC    /**
 // JDBC40DOC     * Updates the designated column with a <code>java.sql.NClob</code> value.
 // JDBC40DOC     * The updater methods are used to update column values in the
 // JDBC40DOC     * current row or the insert row.  The updater methods do not 
 // JDBC40DOC     * update the underlying database; instead the <code>updateRow</code> or
 // JDBC40DOC     * <code>insertRow</code> methods are called to update the database.
 // JDBC40DOC     *
 // JDBC40DOC     * @param columnIndex
 // JDBC40DOC     * @param nClob the value for the column to be updated
 // JDBC40DOC     * @throws SQLException if the driver does not support national
 // JDBC40DOC     *         character sets;  if the driver can detect that a data conversion
 // JDBC40DOC     *  error could occur; or if a database access error occurs
 // JDBC40DOC     */
    /* ifdef JDBC40 
    public void updateNClob(int columnIndex, NClob nClob) throws SQLException
    {
        updateValue (columnIndex, nClob, null, -1);
    }
    endif */ 
    
    //@PDA jdbc40
 // JDBC40DOC    /**
 // JDBC40DOC     * Updates the designated column with a <code>java.sql.NClob</code> value.
 // JDBC40DOC     * The updater methods are used to update column values in the
 // JDBC40DOC     * current row or the insert row.  The updater methods do not 
 // JDBC40DOC     * update the underlying database; instead the <code>updateRow</code> or
 // JDBC40DOC     * <code>insertRow</code> methods are called to update the database.
 // JDBC40DOC     *
 // JDBC40DOC     * @param columnName name of the column
 // JDBC40DOC     * @param nClob the value for the column to be updated
 // JDBC40DOC     * @throws SQLException if the driver does not support national
 // JDBC40DOC     *         character sets;  if the driver can detect that a data conversion
 // JDBC40DOC     *  error could occur; or if a database access error occurs
 // JDBC40DOC     */
    /* ifdef JDBC40 
    public void updateNClob(String columnName, NClob nClob) throws SQLException
    {
        updateNClob (findColumn (columnName), nClob);
        
    }
    endif */ 
    

    //@pda jdbc40
    /**
     * Updates the designated column with a <code>String</code> value.
     * It is intended for use when updating <code>NCHAR</code>,<code>NVARCHAR</code>
     * and <code>LONGNVARCHAR</code> columns.
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnIndex
     * @param nString the value for the column to be updated
     * @throws SQLException if the driver does not support national
     *         character sets;  if the driver can detect that a data conversion
     *  error could occur; or if a database access error occurs
     */
    public void updateNString(int columnIndex, String nString) throws SQLException
    {
        updateValue (columnIndex, nString, null, -1);
    }

    //@PDA jdbc40
    /**
     * Updates the designated column with a <code>String</code> value.
     * It is intended for use when updating <code>NCHAR</code>,<code>NVARCHAR</code>
     * and <code>LONGNVARCHAR</code> columns.
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnName name of the Column
     * @param nString the value for the column to be updated
     * @throws SQLException if the driver does not support national
     *         character sets;  if the driver can detect that a data conversion
     *  error could occur; or if a database access error occurs
     */
    public void updateNString(String columnName, String nString) throws SQLException
    {
        updateNString (findColumn (columnName), nString);
    }

    //@PDA jdbc40
 // JDBC40DOC    /**
 // JDBC40DOC     * Updates the designated column with a <code>RowId</code> value. The updater
 // JDBC40DOC     * methods are used to update column values in the current row or the insert
 // JDBC40DOC     * row. The updater methods do not update the underlying database; instead 
 // JDBC40DOC     * the <code>updateRow</code> or <code>insertRow</code> methods are called 
 // JDBC40DOC     * to update the database.
 // JDBC40DOC     * 
 // JDBC40DOC     * @param columnIndex
 // JDBC40DOC     * @param x the column value
 // JDBC40DOC     * @throws SQLException if a database access occurs 
 // JDBC40DOC     */
    /* ifdef JDBC40 
    public void updateRowId(int columnIndex, RowId x) throws SQLException
    {
        updateValue (columnIndex, x, null, -1);
    }
    endif */ 
    

    //@pda jdbc40
 // JDBC40DOC    /**
 // JDBC40DOC     * Updates the designated column with a <code>RowId</code> value. The updater
 // JDBC40DOC     * methods are used to update column values in the current row or the insert
 // JDBC40DOC     * row. The updater methods do not update the underlying database; instead 
 // JDBC40DOC     * the <code>updateRow</code> or <code>insertRow</code> methods are called 
 // JDBC40DOC     * to update the database.
 // JDBC40DOC     * 
 // JDBC40DOC     * @param columnName the name of the column
 // JDBC40DOC     * @param x the column value
 // JDBC40DOC     * @throws SQLException if a database access occurs 
 // JDBC40DOC     */
    /* ifdef JDBC40 
    public void updateRowId(String columnName, RowId x) throws SQLException
    {
        updateRowId (findColumn (columnName), x);
    }
    endif */

    //@pda jdbc40
 // JDBC40DOC    /**
 // JDBC40DOC     * Updates the designated column with a <code>java.sql.SQLXML</code> value.
 // JDBC40DOC     * The updater
 // JDBC40DOC     * methods are used to update column values in the current row or the insert
 // JDBC40DOC     * row. The updater methods do not update the underlying database; instead 
 // JDBC40DOC     * the <code>updateRow</code> or <code>insertRow</code> methods are called 
 // JDBC40DOC     * to update the database.
 // JDBC40DOC     * @param columnIndex
 // JDBC40DOC     * @param xmlObject the value for the column to be updated
 // JDBC40DOC     * @throws SQLException if a database access error occurs
 // JDBC40DOC     */
    /* ifdef JDBC40 
    public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException
    {
        //@xmlspec special handling of blob/clob column types
        if(xmlObject == null)                                                      //@xmlspec3
        {                                                                          //@xmlspec3
            updateValue (columnIndex, xmlObject, null, -1);                        //@xmlspec3
            return;                                                                //@xmlspec3
        }                                                                          //@xmlspec3
        
        int sqlDataType; 
        if(updateRow_ != null) //@nulltype
            sqlDataType = updateRow_.getSQLData (columnIndex).getType();                     //@xmlspec  //@nulltype
        else  
            sqlDataType = Types.SQLXML;  //@nulltype dummy type so processing continues
        
        
        switch(sqlDataType) {                                                      //@xmlspec
            case Types.CLOB:                                                       //@xmlspec
                updateCharacterStream(columnIndex, xmlObject.getCharacterStream());//@xmlspec
                break;                                                             //@xmlspec
            case Types.BLOB:                                                       //@xmlspec
                updateBinaryStream(columnIndex,  xmlObject.getBinaryStream());     //@xmlspec
                break;                                                             //@xmlspec
            default:                                                               //@xmlspec
                updateValue (columnIndex, xmlObject, null, -1); 
        }
    }
    endif */ 

    //@pda jdbc40
 // JDBC40DOC    /**
 // JDBC40DOC     * Updates the designated column with a <code>java.sql.SQLXML</code> value. 
 // JDBC40DOC     * The updater
 // JDBC40DOC     * methods are used to update column values in the current row or the insert
 // JDBC40DOC     * row. The updater methods do not update the underlying database; instead 
 // JDBC40DOC     * the <code>updateRow</code> or <code>insertRow</code> methods are called 
 // JDBC40DOC     * to update the database.
 // JDBC40DOC     * 
 // JDBC40DOC     * @param columnName the name of the column
 // JDBC40DOC     * @param xmlObject the column value
 // JDBC40DOC     * @throws SQLException if a database access occurs 
 // JDBC40DOC     */
    /* ifdef JDBC40 
    public void updateSQLXML(String columnName, SQLXML xmlObject) throws SQLException
    {
        updateSQLXML(findColumn(columnName), xmlObject);
    }
    endif */ 
    
    //@pda jdbc40
    protected String[] getValidWrappedList()
    {
        return new String[] {  "com.ibm.as400.access.AS400JDBCResultSet",  "java.sql.ResultSet" };
    } 

    //@PDA jdbc40
    /** 
     * Updates the designated column with an ascii stream value, which will have
     * the specified number of bytes.
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnIndex
     * @param x the new column value
     * @param length the length of the stream
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException
    {
        if(length < 0)
            JDError.throwSQLException (JDError.EXC_BUFFER_LENGTH_INVALID);
   
        updateValue (columnIndex, 
                     (x == null) ? null : JDUtilities.streamToString (x, (int)length, "ISO8859_1"), null, -1);        
    }

    
    //@PDA jdbc40
    /** 
     * Updates the designated column with an ascii stream value, which will have
     * the specified number of bytes.
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnLabel the column name
     * @param x the new column value
     * @param length the length of the stream
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException
    {
        updateAsciiStream (findColumn (columnLabel), x, length);
    }


    //@PDA jdbc40
    /** 
     * Updates the designated column with a binary stream value, which will have
     * the specified number of bytes.
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnIndex
     * @param x the new column value     
     * @param length the length of the stream
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException
    {
        if(length < 0)
            JDError.throwSQLException (JDError.EXC_BUFFER_LENGTH_INVALID);

        updateValue (columnIndex, 
                     (x == null) ? null : JDUtilities.streamToBytes (x, (int)length), null, -1);
    }

    //@PDA jdbc40
    /** 
     * Updates the designated column with a binary stream value, which will have
     * the specified number of bytes.
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param x the new column value
     * @param length the length of the stream
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException
    {
        updateBinaryStream (findColumn (columnLabel), x, length);
    }

    //@PDA jdbc40
    /**
     * Updates the designated column using the given input stream, which
     * will have the specified number of bytes.
     * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
     * parameter, it may be more practical to send it via a
     * <code>java.io.InputStream</code>. Data will be read from the stream
     * as needed until end-of-file is reached.  The JDBC driver will
     * do any necessary conversion from ASCII to the database char format.
     * 
     * <P><B>Note:</B> This stream object can either be a standard
     * Java stream object or your own subclass that implements the
     * standard interface.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnIndex
     * @param inputStream An object that contains the data to set the parameter
     * value to.
     * @param length the number of bytes in the parameter data.
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException
    {
        if(length < 0)
            JDError.throwSQLException (JDError.EXC_BUFFER_LENGTH_INVALID);

        updateValue (columnIndex, 
                     (inputStream == null) ? null : JDUtilities.streamToBytes (inputStream, (int)length), null, -1);
    }

    //@PDA jdbc40
    /** 
     * Updates the designated column using the given input stream, which
     * will have the specified number of bytes.
     * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
     * parameter, it may be more practical to send it via a
     * <code>java.io.InputStream</code>. Data will be read from the stream
     * as needed until end-of-file is reached.  The JDBC driver will
     * do any necessary conversion from ASCII to the database char format.
     * 
     * <P><B>Note:</B> This stream object can either be a standard
     * Java stream object or your own subclass that implements the
     * standard interface.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param inputStream An object that contains the data to set the parameter
     * value to.
     * @param length the number of bytes in the parameter data.
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException
    {
        updateBlob (findColumn (columnLabel), inputStream, length);
    }

    //@PDA jdbc40
    /**
     * Updates the designated column with a character stream value, which will have
     * the specified number of bytes.
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnIndex
     * @param x the new column value
     * @param length the length of the stream
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException
    {
        if(length < 0)
            JDError.throwSQLException (JDError.EXC_BUFFER_LENGTH_INVALID);
      
        updateValue (columnIndex, 
                     (x == null) ? null : JDUtilities.readerToString (x, (int)length), null, -1);
    }

    //@PDA jdbc40
    /** 
     * Updates the designated column with a character stream value, which will have
     * the specified number of bytes.
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param reader the new column value
     * @param length the length of the stream
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException
    {
        updateCharacterStream (findColumn (columnLabel), reader, length);
    }

    //@PDA jdbc40
    /**
     * Updates the designated column using the given <code>Reader</code>
     * object, which is the given number of characters long.
     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
     * parameter, it may be more practical to send it via a
     * <code>java.io.Reader</code> object. The data will be read from the stream
     * as needed until end-of-file is reached.  The JDBC driver will
     * do any necessary conversion from UNICODE to the database char format.
     * 
     * <P><B>Note:</B> This stream object can either be a standard
     * Java stream object or your own subclass that implements the
     * standard interface.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnIndex
     * @param reader An object that contains the data to set the parameter value to.
     * @param length the number of characters in the parameter data.
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method 
     */
    public void updateClob(int columnIndex, Reader reader, long length) throws SQLException
    {
        if(length < 0)
            JDError.throwSQLException (JDError.EXC_BUFFER_LENGTH_INVALID);

        updateValue (columnIndex, 
                     (reader == null) ? null : JDUtilities.readerToString (reader, (int)length), null, -1);
    }

    //@PDA jdbc40
    /** 
     * Updates the designated column using the given <code>Reader</code>
     * object, which is the given number of characters long.
     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
     * parameter, it may be more practical to send it via a
     * <code>java.io.Reader</code> object. The data will be read from the stream
     * as needed until end-of-file is reached.  The JDBC driver will
     * do any necessary conversion from UNICODE to the database char format.
     * 
     * <P><B>Note:</B> This stream object can either be a standard
     * Java stream object or your own subclass that implements the
     * standard interface.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param reader An object that contains the data to set the parameter value to.
     * @param length the number of characters in the parameter data.
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateClob(String columnLabel, Reader reader, long length) throws SQLException
    {
        updateClob (findColumn (columnLabel), reader, length);
    }


    //@PDA jdbc40
    /**
     * Updates the designated column with a character stream value, which will have
     * the specified number of bytes.   The
     * driver does the necessary conversion from Java character format to
     * the national character set in the database.
     * It is intended for use when
     * updating  <code>NCHAR</code>,<code>NVARCHAR</code>
     * and <code>LONGNVARCHAR</code> columns.
     * 
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnIndex
     * @param x the new column value
     * @param length the length of the stream
     * @exception SQLException if a database access error occurs, 
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException
    {
        if(length < 0)
            JDError.throwSQLException (JDError.EXC_BUFFER_LENGTH_INVALID);
      
        updateValue (columnIndex, 
                     (x == null) ? null : JDUtilities.readerToString (x, (int)length), null, -1);
    }


    //@PDA jdbc40
    /**
     * Updates the designated column with a character stream value, which will have
     * the specified number of bytes.  The
     * driver does the necessary conversion from Java character format to
     * the national character set in the database.  
     * It is intended for use when
     * updating  <code>NCHAR</code>,<code>NVARCHAR</code>
     * and <code>LONGNVARCHAR</code> columns.
     *     
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param reader the <code>java.io.Reader</code> object containing
     *        the new column value
     * @param length the length of the stream
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException
    {
        updateNCharacterStream (findColumn (columnLabel), reader, length);
    }


    //@PDA jdbc40
    /**
      * Updates the designated column using the given <code>Reader</code>
      * object, which is the given number of characters long.
      * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
      * parameter, it may be more practical to send it via a
      * <code>java.io.Reader</code> object. The data will be read from the stream
      * as needed until end-of-file is reached.  The JDBC driver will
      * do any necessary conversion from UNICODE to the database char format.
      * 
      * <P><B>Note:</B> This stream object can either be a standard
      * Java stream object or your own subclass that implements the
      * standard interface.
      * <p>
      * The updater methods are used to update column values in the
      * current row or the insert row.  The updater methods do not 
      * update the underlying database; instead the <code>updateRow</code> or
      * <code>insertRow</code> methods are called to update the database.
      *
      * @param columnIndex
      * @param reader An object that contains the data to set the parameter value to.
      * @param length the number of characters in the parameter data.
      * @throws SQLException if the driver does not support national
      *         character sets;  if the driver can detect that a data conversion
      *  error could occur; this method is called on a closed result set,  
      * if a database access error occurs or
      * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
      * this method
     */
    public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException
    {
        if(length < 0)
            JDError.throwSQLException (JDError.EXC_BUFFER_LENGTH_INVALID);
      
        updateValue (columnIndex, 
                     (reader == null) ? null : JDUtilities.readerToString (reader, (int)length), null, -1);
    }


    //@PDA jdbc40
    /** 
     * Updates the designated column using the given <code>Reader</code>
     * object, which is the given number of characters long.
     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
     * parameter, it may be more practical to send it via a
     * <code>java.io.Reader</code> object. The data will be read from the stream
     * as needed until end-of-file is reached.  The JDBC driver will
     * do any necessary conversion from UNICODE to the database char format.
     * 
     * <P><B>Note:</B> This stream object can either be a standard
     * Java stream object or your own subclass that implements the
     * standard interface.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param reader An object that contains the data to set the parameter value to.
     * @param length the number of characters in the parameter data.
     * @exception SQLException if a database access error occurs,
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException
    {
        updateNClob (findColumn (columnLabel), reader, length);
    }


    //@pda jdbc40
    /** 
     * Updates the designated column with an ascii stream value.
     * The data will be read from the stream
     * as needed until end-of-stream is reached.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateAsciiStream</code> which takes a length parameter.
     *
     * @param columnIndex
     * @param x the new column value
     * @exception SQLException if the columnIndex is not valid; 
     * if a database access error occurs;
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException
    {
        updateValue (columnIndex, 
                     (x == null) ? null : JDUtilities.streamToBytes (x), null, -1);
    }


    //@pda jdbc40
    /** 
     * Updates the designated column with an ascii stream value.
     * The data will be read from the stream
     * as needed until end-of-stream is reached.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateAsciiStream</code> which takes a length parameter.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param x the new column value
     * @exception SQLException if the columnLabel is not valid; 
     * if a database access error occurs;
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException
    {
        updateAsciiStream (findColumn (columnLabel), x);
    }


    //@pda jdbc40
    /** 
     * Updates the designated column with a binary stream value.
     * The data will be read from the stream
     * as needed until end-of-stream is reached.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateBinaryStream</code> which takes a length parameter.
     *
     * @param columnIndex
     * @param x the new column value     
     * @exception SQLException if the columnIndex is not valid; 
     * if a database access error occurs;
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException
    {
        updateValue (columnIndex, 
                (x == null) ? null : JDUtilities.streamToBytes (x), null, -1);
    }


    //@pda jdbc40
    /** 
     * Updates the designated column with a binary stream value.
     * The data will be read from the stream
     * as needed until end-of-stream is reached.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateBinaryStream</code> which takes a length parameter.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param x the new column value
     * @exception SQLException if the columnLabel is not valid; 
     * if a database access error occurs;
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException
    {
        updateBinaryStream (findColumn (columnLabel), x); 
    }


    //@pda jdbc40
    /**
     * Updates the designated column using the given input stream. The data will be read from the stream
     * as needed until end-of-stream is reached.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database. 
     * 
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateBlob</code> which takes a length parameter.     
     *
     * @param columnIndex
     * @param inputStream An object that contains the data to set the parameter
     * value to.
     * @exception SQLException if the columnIndex is not valid; if a database access error occurs;
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException
    {
        updateValue (columnIndex, 
                (inputStream == null) ? null : JDUtilities.streamToBytes (inputStream), null, -1);
    }


    //@pda jdbc40
    /** 
     * Updates the designated column using the given input stream. The data will be read from the stream
     * as needed until end-of-stream is reached.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     *   <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateBlob</code> which takes a length parameter.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param inputStream An object that contains the data to set the parameter
     * value to.
     * @exception SQLException if the columnLabel is not valid; if a database access error occurs;
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException
    {
        updateBlob (findColumn (columnLabel), inputStream); 
    }


    //@pda jdbc40
    /**
     * Updates the designated column with a character stream value.
     * The data will be read from the stream
     * as needed until end-of-stream is reached.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateCharacterStream</code> which takes a length parameter.
     *
     * @param columnIndex
     * @param x the new column value
     * @exception SQLException if the columnIndex is not valid; 
     * if a database access error occurs;
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateCharacterStream(int columnIndex, Reader x) throws SQLException
    {
        updateValue (columnIndex, 
                (x == null) ? null : JDUtilities.readerToString(x), null, -1);
    }


    //@pda jdbc40
    /**
     * Updates the designated column with a character stream value.
     * The data will be read from the stream
     * as needed until end-of-stream is reached.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateCharacterStream</code> which takes a length parameter.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param reader the <code>java.io.Reader</code> object containing
     *        the new column value
     * @exception SQLException if the columnLabel is not valid; if a database access error occurs;
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException
    {
        updateCharacterStream (findColumn (columnLabel), reader); 
    }


    //@pda jdbc40
    /**
     * Updates the designated column using the given <code>Reader</code>
     * object.
     *  The data will be read from the stream
     * as needed until end-of-stream is reached.  The JDBC driver will
     * do any necessary conversion from UNICODE to the database char format.
     * 
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     *   <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateClob</code> which takes a length parameter.
     *     
     * @param columnIndex
     * @param reader An object that contains the data to set the parameter value to.
     * @exception SQLException if the columnIndex is not valid; 
     * if a database access error occurs;
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method 
     */
    public void updateClob(int columnIndex, Reader reader) throws SQLException
    {
        updateValue (columnIndex, 
                (reader == null) ? null : JDUtilities.readerToString(reader), null, -1);
    }


    //@pda jdbc40
    /** 
     * Updates the designated column using the given <code>Reader</code>
     * object.
     *  The data will be read from the stream
     * as needed until end-of-stream is reached.  The JDBC driver will
     * do any necessary conversion from UNICODE to the database char format.
     * 
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     * 
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateClob</code> which takes a length parameter.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param reader An object that contains the data to set the parameter value to.
     * @exception SQLException if the columnLabel is not valid; if a database access error occurs;
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateClob(String columnLabel, Reader reader) throws SQLException
    {
        updateClob (findColumn (columnLabel), reader); 
    }


    //@pda jdbc40
    /**
     * Updates the designated column with a character stream value.  
     * The data will be read from the stream
     * as needed until end-of-stream is reached.  The
     * driver does the necessary conversion from Java character format to
     * the national character set in the database.
     * It is intended for use when
     * updating  <code>NCHAR</code>,<code>NVARCHAR</code>
     * and <code>LONGNVARCHAR</code> columns.
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateNCharacterStream</code> which takes a length parameter.
     *
     * @param columnIndex
     * @param x the new column value
     * @exception SQLException if the columnIndex is not valid; 
     * if a database access error occurs; 
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException
    {
        updateValue (columnIndex, 
                (x == null) ? null : JDUtilities.readerToString(x), null, -1);
    }


    //@pda jdbc40
    /**
     * Updates the designated column with a character stream value.  
     * The data will be read from the stream
     * as needed until end-of-stream is reached.  The
     * driver does the necessary conversion from Java character format to
     * the national character set in the database.  
     * It is intended for use when
     * updating  <code>NCHAR</code>,<code>NVARCHAR</code>
     * and <code>LONGNVARCHAR</code> columns.
     * <p>    
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateNCharacterStream</code> which takes a length parameter.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param reader the <code>java.io.Reader</code> object containing
     *        the new column value
     * @exception SQLException if the columnLabel is not valid; 
     * if a database access error occurs;
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> or this method is called on a closed result set
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException
    {
        updateNCharacterStream(findColumn (columnLabel), reader); 
    }
    


    //@pda jdbc40
    /**
     * Updates the designated column using the given <code>Reader</code>
     * 
     * <p>
     * The data will be read from the stream
     * as needed until end-of-stream is reached.  The JDBC driver will
     * do any necessary conversion from UNICODE to the database char format.
     * 
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateNClob</code> which takes a length parameter.
     *
     * @param columnIndex
     * @param reader An object that contains the data to set the parameter value to.
     * @throws SQLException if the columnIndex is not valid; 
    * if the driver does not support national
     *         character sets;  if the driver can detect that a data conversion
     *  error could occur; this method is called on a closed result set,  
     * if a database access error occurs or
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */
    public void updateNClob(int columnIndex, Reader reader) throws SQLException
    {
        updateValue (columnIndex, 
                (reader == null) ? null : JDUtilities.readerToString(reader), null, -1);
    }


    //@pda jdbc40
    /**
     * Updates the designated column using the given <code>Reader</code>
     * object.
     * The data will be read from the stream
     * as needed until end-of-stream is reached.  The JDBC driver will
     * do any necessary conversion from UNICODE to the database char format.
     *
     * <p>
     * The updater methods are used to update column values in the
     * current row or the insert row.  The updater methods do not 
     * update the underlying database; instead the <code>updateRow</code> or
     * <code>insertRow</code> methods are called to update the database.
     *
     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if 
     * it might be more efficient to use a version of 
     * <code>updateNClob</code> which takes a length parameter.
     *
     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
     * @param reader An object that contains the data to set the parameter value to.
     * @throws SQLException if the columnLabel is not valid; if the driver does not support national
     *         character sets;  if the driver can detect that a data conversion
     *  error could occur; this method is called on a closed result set;
     *  if a database access error occurs or
     * the result set concurrency is <code>CONCUR_READ_ONLY</code> 
     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
     * this method
     */ 
    public void updateNClob(String columnLabel, Reader reader) throws SQLException
    {
        updateNClob (findColumn (columnLabel), reader); 
    }
    
   
 

    //@EIA new method
    /**
    Updates a column for the specified index, and performs all
    appropriate validation.
    
    Note: this is the same type of method as updateValue() above, but we
    have no way to pass in the special values without hacking some sort
    of flag string for the value, and that seemed to be a messy and slow
    way to do this.
    
    @param  columnIndex   The column index (1-based).
    @param  columnValue   The parameter 1="default" or 2="unassigned".
                      
    
    @exception  SQLException    If the result set is not open,
                                the result set is not updatable,
                                the cursor is not positioned on a row,
                                the column index is not valid, or the
                                requested conversion is not valid.
    **/
    private void updateValueExtendedIndicator (int columnIndex, int columnValue)
    throws SQLException
    {
        synchronized(internalLock_)
        {                                          
            beforeUpdate ();

            // Check that there is a current row.
            if((positionValid_ == false) && (positionInsert_ == false))
                JDError.throwSQLException (JDError.EXC_CURSOR_POSITION_INVALID);

            // Validate The column index.
            if((columnIndex < 1))
                JDError.throwSQLException (JDError.EXC_DESCRIPTOR_INDEX_INVALID, columnIndex+"<1");
            if((columnIndex > columnCount_))
              JDError.throwSQLException (JDError.EXC_DESCRIPTOR_INDEX_INVALID, columnIndex+">"+columnCount_);

            // Set the update value.  If there is a type mismatch,
            // set() with throw an exception.
           
            int columnIndex0 = columnIndex - 1;
            
            updateNulls_[columnIndex0] = false;
            updateDefaults_[columnIndex0] = columnValue == 1 ? true: false;     
            updateUnassigned_[columnIndex0] =  columnValue == 2 ? true: false;   
            updateSet_[columnIndex0] = true;
                 
        }
    }


//JDBC40DOC /**
//JDBC40DOC  * Retrieves the value of the designated column in the current row of this ResultSet object and will convert 
//JDBC40DOC  * from the SQL type of the column to the requested Java data type, if the conversion is supported. 
//JDBC40DOC  * If the conversion is not supported or null is specified for the type, a SQLException is thrown. 
//JDBC40DOC  *
//JDBC40DOC  *    <p>At a minimum, an implementation must support the conversions defined in Appendix B, Table B-3 and 
//JDBC40DOC  *    conversion of appropriate user defined SQL types to a Java type which implements SQLData, 
//JDBC40DOC  *    or Struct. Additional conversions may be supported and are vendor defined.
//JDBC40DOC  *
//JDBC40DOC  *    @param columnIndex - the first column is 1, the second is 2, ...
//JDBC40DOC  *    @param type - Class representing the Java data type to convert the designated column to.
//JDBC40DOC  *    @return  an instance of type holding the column value
//JDBC40DOC  *    @exception  SQLException - if conversion is not supported, type is null or another error occurs. 
//JDBC40DOC  *    The getCause() method of the exception may provide a more detailed exception, for example, if a conversion error occurs
//JDBC40DOC  *    @exception  SQLFeatureNotSupportedException - if the JDBC driver does not support this method
//JDBC40DOC  */
    
/*  
    public <T> T getObject(int columnIndex, Class<T> type) 
 */
    public Object getObject(int columnIndex, Class type) 
   
    throws SQLException {
      // Throw exception if type is null 
      if (type == null) {
        JDError.throwSQLException (JDError.EXC_PARAMETER_TYPE_INVALID);
      }
      if (byteArrayClass_ == null) {
        byte[] byteArray = new byte[1]; 
        byteArrayClass_ = byteArray.getClass(); 
      }
      // Use the appropriate method to get the correct data type.
      // After checking for string, we check for classes in the 
      // order specified in Table B-6 of the JDBC 4.0 specification
      // 
      if (type == java.lang.String.class ) {
        return getString(columnIndex); 
      } else if (type == java.lang.Byte.class){
        byte b = getByte(columnIndex); 
        if (b == 0 && wasNull()) { 
          return null;  
        } else { 
          return new Byte(b);
        }
      } else if (type == java.lang.Short.class){
        short s = getShort(columnIndex); 
        if (s == 0 && wasNull()) { 
          return null;  
        } else { 
          return new Short(s);
        }
      } else if (type == java.lang.Integer.class){
        int i = getInt(columnIndex); 
        if (i == 0 && wasNull()) { 
          return null;  
        } else { 
          return new Integer(i);
        }
      } else if (type == java.lang.Long.class){
        long l = getLong(columnIndex); 
        if (l == 0 && wasNull()) { 
          return null;  
        } else { 
          return new Long(l);
        }
      } else if (type == java.lang.Float.class){
        float f = getFloat(columnIndex);
        if (f == 0 && wasNull()) { 
          return null;  
        } else { 
        return new Float(f);
        }
      } else if (type == java.lang.Double.class){
        double d = getDouble(columnIndex); 
        if (d == 0 && wasNull()) { 
          return null;  
        } else { 
          return new Double(d);
        }
      } else if (type == java.math.BigDecimal.class){
        return getBigDecimal(columnIndex); 
      } else if (type == java.lang.Boolean.class) {
        boolean b = getBoolean(columnIndex);
        if (b == false && wasNull()) { 
          return null;  
        } else { 
          return new Boolean (b);
        }
        
      } else if (type == java.sql.Date.class){
        return getDate(columnIndex); 
      } else if (type == java.sql.Time.class){
        return getTime(columnIndex); 
      } else if (type == java.sql.Timestamp.class){
        return getTimestamp(columnIndex); 
    } else if (type == byteArrayClass_) {
      return getBytes(columnIndex);
    } else if (type == InputStream.class) {
      return getBinaryStream(columnIndex);
    } else if (type == Reader.class) {
      return getCharacterStream(columnIndex);
    } else if (type == Clob.class) {
      return getClob(columnIndex);
    } else if (type == Array.class) {
      return getArray(columnIndex);
    } else if (type == Blob.class) {
      return getBlob(columnIndex);
    } else if (type == Ref.class) {
      return getRef(columnIndex);
      } else if (type == URL.class){
        return getURL(columnIndex);
/* ifdef JDBC40 
      } else if (type == NClob.class){
        return getNClob(columnIndex);
      } else if (type == RowId.class){
        return getRowId(columnIndex);
      } else if (type == SQLXML.class){
        return getSQLXML(columnIndex);
endif */
      } else if (type == Object.class){
        return getObject(columnIndex);
      }

      JDError.throwSQLException (JDError.EXC_DATA_TYPE_INVALID);
      return null; 
    }

/**
 * Retrieves the value of the designated column in the current row of this ResultSet object and will convert from the 
 * SQL type of the column to the requested Java data type, if the conversion is supported. If the conversion is 
 * not supported or null is specified for the type, a SQLException is thrown. 
 * <p> At a minimum, an implementation must support the conversions defined in Appendix B, Table B-3 and conversion of 
 * appropriate user defined SQL types to a Java type which implements SQLData, or Struct. Additional conversions may be 
 * supported and are vendor defined.
 *@param columnLabel - the label for the column specified with the SQL AS clause. If the SQL AS clause was not specified, then the label is the name of the column
 *@param type - Class representing the Java data type to convert the designated column to.
 *@return   an instance of type holding the column value
 *@exception  SQLException - if conversion is not supported, type is null or another error occurs. The getCause() method of the exception may provide a more detailed exception, for example, if a conversion error occurs
 *@exception SQLFeatureNotSupportedException - if the JDBC driver does not support this method
 */
    
/* 
    public <T> T getObject(String columnLabel, Class<T> type)
    
 */
    public Object getObject(String columnLabel, Class type)
    throws SQLException {
      return getObject (findColumn (columnLabel), type); 
 }



 /* Save exception from combined operation @F3A*/   
protected void addSavedException(SQLException savedException) {
  savedException_ = savedException; 
  
}

 

/* Returns the cursor type based on the requested cursor and the cursor sensitivity property 
   The doc says the following about the cursor sensitivity property 
    
   Specifies the cursor sensitivity to request from the database. The behavior depends on the resultSetType:

    ResultSet.TYPE_FORWARD_ONLY or ResultSet.TYPE_SCROLL_SENSITIVE means that the value of this property controls what cursor sensitivity the Java™ program requests from the database.
    ResultSet.TYPE_SCROLL_INSENSITIVE causes this property to be ignored.
    
    Code taken from JDCursor.java and used there and in AS400JDBCStatement.java
    
    @H1A
*/ 

  static int getDBSQLRequestDSCursorType(String cursorSensitivityProperty,
      int resultSetType,
      int resultSetConcurrency ) {
    switch (resultSetType) {
    case ResultSet.TYPE_FORWARD_ONLY: {
      //if ResultSet is updateable, then we cannot have a insensitive cursor
      if (cursorSensitivityProperty
          .equalsIgnoreCase(JDProperties.CURSOR_SENSITIVITY_INSENSITIVE)  && 
          (resultSetConcurrency == ResultSet.CONCUR_READ_ONLY))
        return DBSQLRequestDS.CURSOR_NOT_SCROLLABLE_INSENSITIVE;
      else if(cursorSensitivityProperty.equalsIgnoreCase(JDProperties.CURSOR_SENSITIVITY_SENSITIVE))     //@PDA
        return DBSQLRequestDS.CURSOR_NOT_SCROLLABLE_SENSITIVE;
      else
        return DBSQLRequestDS.CURSOR_NOT_SCROLLABLE_ASENSITIVE;
    }

    case ResultSet.TYPE_SCROLL_SENSITIVE: {
      if(cursorSensitivityProperty.equalsIgnoreCase(JDProperties.CURSOR_SENSITIVITY_SENSITIVE)) 
        return DBSQLRequestDS.CURSOR_SCROLLABLE_SENSITIVE;   
      else if (cursorSensitivityProperty
          .equalsIgnoreCase(JDProperties.CURSOR_SENSITIVITY_ASENSITIVE))
        return DBSQLRequestDS.CURSOR_SCROLLABLE_ASENSITIVE;
      else
        return DBSQLRequestDS.CURSOR_SCROLLABLE_SENSITIVE;
    }
    case ResultSet.TYPE_SCROLL_INSENSITIVE:
    default:
      return DBSQLRequestDS.CURSOR_SCROLLABLE_INSENSITIVE;

    }
  }
    
  
  /**
   * converts an SQLType to its corresponding java.sql.Types value
   */
  
  int mapSQLType(
/* ifdef JDBC42        
      SQLType  
endif*/ 
/* ifndef JDBC42 */
Object
/* endif */
      targetSqlType ) throws SQLException {
     /* ifdef JDBC42 
       
    if (targetSqlType instanceof JDBCType) {
      return targetSqlType.getVendorTypeNumber(); 
    }
      throw new SQLFeatureNotSupportedException("targetSqlType="+targetSqlType);    
 
      endif */
    /* ifndef JDBC42 */
       return 0; 
    /* endif */ 
  }

  /**
   * Updates the designated column with an Object value. The updater methods are 
   * used to update column values in the current row or the insert row. The 
   * updater methods do not update the underlying database; instead the updateRow
   *  or insertRow methods are called to update the database.
   * <p>If the second argument is an InputStream then the stream must contain 
   * the number of bytes specified by scaleOrLength. If the second argument 
   * is a Reader then the reader must contain the number of characters 
   * specified by scaleOrLength. If these conditions are not true the 
   * driver will generate a SQLException when the statement is executed.
   * @param columnIndex - the first column is 1, the second is 2, ...
   * @param x - the new column value
   * @param targetSqlType  the SQL type to be sent to the database
   * @param scaleOrLength  - for an object of java.math.BigDecimal , this is the 
   * number of digits after the decimal point. For Java Object types InputStream 
   * and Reader, this is the length of the data in the stream or reader. For all 
   * other types, this value will be ignored.
   * @throws SQLException - if the columnIndex is not valid; if a database 
   * access error occurs; the result set concurrency is CONCUR_READ_ONLY or 
   * this method is called on a closed result set
   * @throws SQLFeatureNotSupportedException - if the JDBC driver does not 
   * support this method; if the JDBC driver does not support this data type
   */

  public void updateObject(int columnIndex,
                            Object x,
                            /* ifdef JDBC42        
                            SQLType  
                      endif*/ 
                      /* ifndef JDBC42 */
                      Object
                      /* endif */
                            targetSqlType,
                            int scaleOrLength)
                     throws SQLException {
    updateObject(columnIndex, x, scaleOrLength); 
  }

/**
 * Updates the designated column with an Object value. The updater methods are 
 * used to update column values in the current row or the insert row. The updater 
 * methods do not update the underlying database; instead the updateRow or 
 * insertRow methods are called to update the database.
 * <p>If the second argument is an InputStream then the stream must contain 
 * number of bytes specified by scaleOrLength. If the second argument is 
 * a Reader then the reader must contain the number of characters 
 * specified by scaleOrLength. If these conditions are not true the 
 * driver will generate a SQLException when the statement is executed.
 * @param columnLabel - the label for the column specified with the SQL 
 * AS clause. If the SQL AS clause was not specified, then the label is 
 * the name of the column
 * @param x - the new column value
 * @param targetSqlType - the SQL type to be sent to the database
 * @param scaleOrLength - for an object of java.math.BigDecimal, this is 
 * the number of digits after the decimal point. For Java Object types 
 * InputStream and Reader, this is the length of the data in the stream or 
 * reader. For all other types, this value will be ignored.
 * @throws SQLException - if the columnLabel is not valid; if a database access
 *  error occurs; the result set concurrency is CONCUR_READ_ONLY or this 
 *  method is called on a closed result set
 *  @throws SQLFeatureNotSupportedException - if the JDBC driver does not 
 *  support this method; if the JDBC driver does not support this data type
 */
  public  void updateObject(String columnLabel,
                            Object x,
                            /* ifdef JDBC42        
                            SQLType  
                      endif*/ 
                      /* ifndef JDBC42 */
                      Object
                      /* endif */
                            targetSqlType,
                            int scaleOrLength)
                     throws SQLException {
    updateObject(columnLabel, x,scaleOrLength); 
  }

  
/**
 * Updates the designated column with an Object value. The updater methods are 
 * used to update column values in the current row or the insert row. 
 * The updater methods do not update the underlying database; instead the 
 * updateRow or insertRow methods are called to update the database.
 * @param columnIndex  - the first column is 1, the second is 2, ...
 * @param x  - the new column value
 * @param targetSqlType - the SQL type to be sent to the database
 * @throws SQLException  - if the columnIndex is not valid; if a database 
 * access error occurs; the result set concurrency is CONCUR_READ_ONLY or this 
 * method is called on a closed result set
 * @throws SQLFeatureNotSupportedException - if the JDBC driver does not 
 * support this method; if the JDBC driver does not support this data type
 */

  public void updateObject(int columnIndex,
                            Object x,
                            /* ifdef JDBC42        
                            SQLType  
                      endif*/ 
                      /* ifndef JDBC42 */
                      Object
                      /* endif */
                            targetSqlType)
                     throws SQLException
  {
    updateObject(columnIndex, x); 
  }

  /**
   * Updates the designated column with an Object value. The updater methods are
   *  used to update column values in the current row or the insert row. The 
   *  updater methods do not update the underlying database; instead the 
   *  updateRow or insertRow methods are called to update the database.
   * @param columnLabel - the label for the column specified with the SQL AS 
   * clause. If the SQL AS clause was not specified, then the label is the 
   * name of the column
   * @param x - the new column value
   * @param targetSqlType - the SQL type to be sent to the database
   * @throws SQLException - if the columnLabel is not valid; if a database 
   * access error occurs; the result set concurrency is CONCUR_READ_ONLY 
   * or this method is called on a closed result set
   * @throws SQLFeatureNotSupportedException - if the JDBC driver does 
   * not support this method; if the JDBC driver does not support this 
   * data type
   */
  public void updateObject(String columnLabel,
                            Object x,
                            /* ifdef JDBC42        
                            SQLType  
                      endif*/ 
                      /* ifndef JDBC42 */
                      Object
                      /* endif */
                            targetSqlType)
                     throws SQLException
                     {
                       updateObject(columnLabel, x); 
                     }
  
  
  
}



