Logo Search packages:      
Sourcecode: mysql-connector-java version File versions

ResultSet.java

/*
      Copyright (C) 2002-2004 MySQL AB

      This program is free software; you can redistribute it and/or modify
      it under the terms of version 2 of the GNU General Public License as
      published by the Free Software Foundation.

      There are special exceptions to the terms and conditions of the GPL
      as it is applied to this software. View the full text of the
      exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
      software distribution.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA



 */
package com.mysql.jdbc;

import com.mysql.jdbc.profiler.ProfileEventSink;
import com.mysql.jdbc.profiler.ProfilerEvent;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.StringReader;

import java.math.BigDecimal;
import java.math.BigInteger;

import java.net.MalformedURLException;
import java.net.URL;

import java.sql.Array;
import java.sql.DataTruncation;
import java.sql.Date;
import java.sql.Ref;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;


/**
 * A ResultSet provides access to a table of data generated by executing a
 * Statement.  The table rows are retrieved in sequence.  Within a row its
 * column values can be accessed in any order.
 *
 * <P>
 * A ResultSet maintains a cursor pointing to its current row of data.
 * Initially the cursor is positioned before the first row.  The 'next' method
 * moves the cursor to the next row.
 * </p>
 *
 * <P>
 * The getXXX methods retrieve column values for the current row.  You can
 * retrieve values either using the index number of the column, or by using
 * the name of the column.  In general using the column index will be more
 * efficient.  Columns are numbered from 1.
 * </p>
 *
 * <P>
 * For maximum portability, ResultSet columns within each row should be read in
 * left-to-right order and each column should be read only once.
 * </p>
 *
 * <P>
 * For the getXXX methods, the JDBC driver attempts to convert the underlying
 * data to the specified Java type and returns a suitable Java value.  See the
 * JDBC specification for allowable mappings from SQL types to Java types with
 * the ResultSet getXXX methods.
 * </p>
 *
 * <P>
 * Column names used as input to getXXX methods are case insenstive.  When
 * performing a getXXX using a column name, if several columns have the same
 * name, then the value of the first matching column will be returned.  The
 * column name option is designed to be used when column names are used in the
 * SQL Query.  For columns that are NOT explicitly named in the query, it is
 * best to use column numbers.  If column names were used there is no way for
 * the programmer to guarentee that they actually refer to the intended
 * columns.
 * </p>
 *
 * <P>
 * A ResultSet is automatically closed by the Statement that generated it when
 * that Statement is closed, re-executed, or is used to retrieve the next
 * result from a sequence of multiple results.
 * </p>
 *
 * <P>
 * The number, types and properties of a ResultSet's columns are provided by
 * the ResultSetMetaData object returned by the getMetaData method.
 * </p>
 *
 * @author Mark Matthews
 * @version $Id: ResultSet.java,v 1.18.4.87 2005/02/17 21:42:27 mmatthews Exp $
 *
 * @see ResultSetMetaData
 * @see java.sql.ResultSet
 */
00118 public class ResultSet implements java.sql.ResultSet {
    /** Counter used to generate IDs for profiling. */
00120     protected static int resultCounter = 1;

    /** The Connection instance that created us */
00123     protected com.mysql.jdbc.Connection connection; // The connection that created us

    /** Map column names (and all of their permutations) to column indices */
00126     protected Map columnNameToIndex = null;

    /** Map of fully-specified column names to column indices */
00129     protected Map fullColumnNameToIndex = null;
    protected ProfileEventSink eventSink = null;
    protected ResultSet nextResultSet = null;

    /** The actual rows */
00134     protected RowData rowData; // The results

    /** The warning chain */
00137     protected java.sql.SQLWarning warningChain = null;

    /** The statement that created us */
00140     protected com.mysql.jdbc.Statement owningStatement;
    protected java.sql.Statement wrapperStatement;

    /** The catalog that was in use when we were created */
00144     protected String catalog = null;

    /**
     * Any info message from the server that was created while generating this
     * result set (if 'info parsing'  is enabled for the connection).
     */
00150     protected String serverInfo = null;

    /**
     * StackTrace generated where ResultSet was created... used when profiling
     */
00155     protected Throwable pointOfOrigin;

    /** Keep track of columns accessed */
00158     protected boolean[] columnUsed = null;

    /** The fields for this result set */
00161     protected Field[] fields; // The fields

    /** Pointer to current row data */
00164     protected Object[] thisRow = null; // Values for current row

    /** Are we in the middle of doing updates to the current row? */
00167     protected boolean doingUpdates = false;
    protected boolean hasBuiltIndexMapping = false;

    /**
     * Is the data stored as strings (default) or natively (which is the case
     * with results from PrepStmts)
     */
00174     protected boolean isBinaryEncoded = false;
    
    /** Has this result set been closed? */
00177     protected boolean isClosed = false;

    /** Are we on the insert row? */
00180     protected boolean onInsertRow = false;

    /** Are we tracking items for profileSql? */
00183     protected boolean profileSql = false;

    /**
     * Do we actually contain rows, or just information about
     * UPDATE/INSERT/DELETE?
     */
00189     protected boolean reallyResult = false;
    protected boolean useUsageAdvisor = false;

    /** Did the previous value retrieval find a NULL? */
00193     protected boolean wasNullFlag = false;

    /**
     * First character of the query that created this result set...Used to
     * determine whether or not to parse server info messages in certain
     * circumstances.
     */
00200     protected char firstCharOfQuery;

    /** The current row #, -1 == before start of result set */
00203     protected int currentRow = -1; // Cursor to current row;

    /** The direction to fetch rows (always FETCH_FORWARD) */
00206     protected int fetchDirection = FETCH_FORWARD;

    /** The number of rows to fetch in one go... */
00209     protected int fetchSize = 0;

    /** The id (used when profiling) to identify us */
00212     protected int resultId;

    /** Are we read-only or updatable? */
00215     protected int resultSetConcurrency = 0;

    /** Are we scroll-sensitive/insensitive? */
00218     protected int resultSetType = 0;
    
    protected Calendar sessionCalendar;

    // These are longs for
    // recent versions of the MySQL server.
    //
    // They get reduced to ints via the JDBC API,
    // but can be retrieved through a MySQLStatement
    // in their entirety.
    //

    /** How many rows were affected by UPDATE/INSERT/DELETE? */
00231     protected long updateCount;

    /** Value generated for AUTO_INCREMENT columns */
00234     protected long updateId = -1;
    private Calendar fastDateCal = null;
    private TimeZone defaultTimeZone;
    private boolean useStrictFloatingPoint = false;

    /**
     * Create a result set for an executeUpdate statement.
     *
     * @param updateCount the number of rows affected by the update
     * @param updateID the autoincrement value (if any)
     * @param conn DOCUMENT ME!
     * @param creatorStmt DOCUMENT ME!
     */
00247     public ResultSet(long updateCount, long updateID, Connection conn,
        Statement creatorStmt) {
        this.updateCount = updateCount;
        this.updateId = updateID;
        this.reallyResult = false;
        this.fields = new Field[0];

        this.connection = conn;
        this.owningStatement = creatorStmt;
    }

    /**
     * Creates a new ResultSet object.
     *
     * @param catalog the database in use when we were created
     * @param fields an array of Field objects (basically, the ResultSet
     *        MetaData)
     * @param tuples actual row data
     * @param conn the Connection that created us.
     * @param creatorStmt DOCUMENT ME!
     *
     * @throws SQLException if an error occurs
     */
00270     public ResultSet(String catalog, Field[] fields, RowData tuples,
        Connection conn, Statement creatorStmt) throws SQLException {
        this.connection = conn;

        if (this.connection != null) {
            this.useStrictFloatingPoint = this.connection.getStrictFloatingPoint();
            this.setDefaultTimeZone(this.connection.getDefaultTimeZone());
        }

        this.owningStatement = creatorStmt;

        this.catalog = catalog;
        this.profileSql = this.connection.getProfileSql();

        this.fields = fields;
        this.rowData = tuples;
        this.updateCount = this.rowData.size();

        if (Driver.DEBUG) {
            System.out.println(Messages.getString("ResultSet.Retrieved__1") +
                        this.updateCount + " rows"); //$NON-NLS-1$
        }

        this.reallyResult = true;

        // Check for no results
        if (this.rowData.size() > 0) {
            if (this.updateCount == 1) {
                if (this.thisRow == null) {
                    this.rowData.close(); // empty result set
                    this.updateCount = -1;
                }
            }
        } else {
            this.thisRow = null;
        }

        this.rowData.setOwner(this);

        if (this.profileSql || this.connection.getUseUsageAdvisor()) {
            this.columnUsed = new boolean[this.fields.length];
            this.pointOfOrigin = new Throwable();
            this.resultId = resultCounter++;
            this.useUsageAdvisor = this.connection.getUseUsageAdvisor();
            this.eventSink = ProfileEventSink.getInstance(this.connection);
        }
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Determine if the cursor is after the last row in the result set.
     * </p>
     *
     * @return true if after the last row, false otherwise.  Returns false when
     *         the result set contains no rows.
     *
     * @exception SQLException if a database-access error occurs.
     */
00330     public boolean isAfterLast() throws SQLException {
      checkClosed();
      
        boolean b = this.rowData.isAfterLast();

        return b;
    }

    /**
     * JDBC 2.0 Get an array column.
     *
     * @param i the first column is 1, the second is 2, ...
     *
     * @return an object representing an SQL array
     *
     * @throws SQLException if a database error occurs
     * @throws NotImplemented DOCUMENT ME!
     */
00348     public java.sql.Array getArray(int i) throws SQLException {
        throw new NotImplemented();
    }

    /**
     * JDBC 2.0 Get an array column.
     *
     * @param colName the column name
     *
     * @return an object representing an SQL array
     *
     * @throws SQLException if a database error occurs
     * @throws NotImplemented DOCUMENT ME!
     */
00362     public java.sql.Array getArray(String colName) throws SQLException {
        throw new NotImplemented();
    }

    /**
     * A column value can be retrieved as a stream of ASCII characters and then
     * read in chunks from the stream.  This method is particulary suitable
     * for retrieving large LONGVARCHAR values. The JDBC driver will do any
     * necessary conversion from the database format into ASCII.
     *
     * <p>
     * <B>Note:</B> All 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.  Also, a stream may return 0 for
     * available() whether there is data available or not.
     * </p>
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     *
     * @return a Java InputStream that delivers the database column value as a
     *         stream of one byte ASCII characters.  If the value is SQL NULL
     *         then the result is null
     *
     * @exception SQLException if a database access error occurs
     *
     * @see getBinaryStream
     */
00389     public InputStream getAsciiStream(int columnIndex)
        throws SQLException {
        checkRowPos();

        if (!this.isBinaryEncoded) {
            return getBinaryStream(columnIndex);
        }

        return getNativeBinaryStream(columnIndex);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     */
00409     public InputStream getAsciiStream(String columnName)
        throws SQLException {
        return getAsciiStream(findColumn(columnName));
    }

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

    /**
     * JDBC 2.0
     *
     * <p>
     * Determine if the cursor is before the first row in the result set.
     * </p>
     *
     * @return true if before the first row, false otherwise. Returns false
     *         when the result set contains no rows.
     *
     * @exception SQLException if a database-access error occurs.
     */
00430     public boolean isBeforeFirst() throws SQLException {
      checkClosed();
      
        return this.rowData.isBeforeFirst();
    }

    /**
     * Get the value of a column in the current row as a java.math.BigDecimal
     * object
     *
     * @param columnIndex the first column is 1, the second is 2...
     * @param scale the number of digits to the right of the decimal
     *
     * @return the column value; if the value is SQL NULL, null
     *
     * @exception SQLException if a database access error occurs
     *
     * @deprecated
     */
00449     public BigDecimal getBigDecimal(int columnIndex, int scale)
        throws SQLException {
        if (!this.isBinaryEncoded) {
            String stringVal = getString(columnIndex);
            BigDecimal val;

            if (stringVal != null) {
                if (stringVal.length() == 0) {
                    val = new BigDecimal(0);

                    try {
                        return val.setScale(scale);
                    } catch (ArithmeticException ex) {
                        try {
                              return val.setScale(scale, BigDecimal.ROUND_HALF_UP);
                        } catch (ArithmeticException arEx) {
                              throw new SQLException(Messages.getString(
                                "ResultSet.Bad_format_for_BigDecimal____124") //$NON-NLS-1$
                                +stringVal +
                                Messages.getString("ResultSet.___in_column__125") +
                                columnIndex + "(" //$NON-NLS-1$
                                + this.fields[columnIndex - 1] + ").",
                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                        }
                    }
                }

                try {
                    val = new BigDecimal(stringVal);
                } catch (NumberFormatException ex) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Bad_format_for_BigDecimal",
                            new Object[] { new Integer(columnIndex), stringVal }),
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
                }

                try {
                    return val.setScale(scale);
                } catch (ArithmeticException ex) {
                  try {
                        return val.setScale(scale, BigDecimal.ROUND_HALF_UP);
                  } catch (ArithmeticException arithEx) {
                        throw new SQLException(Messages.getString(
                            "ResultSet.Bad_format_for_BigDecimal",
                            new Object[] { new Integer(columnIndex), stringVal }),
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
                  }
                }
            }

            return null;
        }

        return getNativeBigDecimal(columnIndex, scale);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     * @param scale DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     *
     * @deprecated
     */
00517     public BigDecimal getBigDecimal(String columnName, int scale)
        throws SQLException {
        return getBigDecimal(findColumn(columnName), scale);
    }

    /**
     * JDBC 2.0 Get the value of a column in the current row as a
     * java.math.BigDecimal object.
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     *
     * @return the column value (full precision); if the value is SQL NULL, the
     *         result is null
     *
     * @exception SQLException if a database-access error occurs.
     */
00533     public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
        if (!this.isBinaryEncoded) {
            String stringVal = getString(columnIndex);
            BigDecimal val;

            if (stringVal != null) {
                if (stringVal.length() == 0) {
                    val = new BigDecimal(0);

                    return val;
                }

                try {
                    val = new BigDecimal(stringVal);

                    return val;
                } catch (NumberFormatException ex) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Bad_format_for_BigDecimal",
                            new Object[] { new Integer(columnIndex), stringVal }),
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
                }
            }

            return null;
        }

        return getNativeBigDecimal(columnIndex);
    }

    /**
     * JDBC 2.0 Get the value of a column in the current row as a
     * java.math.BigDecimal object.
     *
     * @param columnName the name of the column to retrieve the value from
     *
     * @return the BigDecimal value in the column
     *
     * @throws SQLException if an error occurs
     */
00573     public BigDecimal getBigDecimal(String columnName)
        throws SQLException {
        return getBigDecimal(findColumn(columnName));
    }

    /**
     * A column value can also be retrieved as a binary strea.  This method is
     * suitable for retrieving LONGVARBINARY values.
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return a Java InputStream that delivers the database column value as a
     *         stream of bytes.  If the value is SQL NULL, then the result is
     *         null
     *
     * @exception SQLException if a database access error occurs
     *
     * @see getAsciiStream
     * @see getUnicodeStream
     */
00593     public InputStream getBinaryStream(int columnIndex)
        throws SQLException {
        checkRowPos();

        if (!this.isBinaryEncoded) {
            byte[] b = getBytes(columnIndex);

            if (b != null) {
                return new ByteArrayInputStream(b);
            }

            return null;
        }

        return getNativeBinaryStream(columnIndex);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     */
00619     public InputStream getBinaryStream(String columnName)
        throws SQLException {
        return getBinaryStream(findColumn(columnName));
    }

    /**
     * JDBC 2.0 Get a BLOB column.
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     *
     * @return an object representing a BLOB
     *
     * @throws SQLException if an error occurs.
     */
00633     public java.sql.Blob getBlob(int columnIndex) throws SQLException {
        if (!this.isBinaryEncoded) {
            checkRowPos();

            if ((columnIndex < 1) || (columnIndex > this.fields.length)) {
                throw new SQLException(Messages.getString(
                        "ResultSet.Column_Index_out_of_range",
                        new Object[] {
                            new Integer(columnIndex),
                            new Integer(this.fields.length)
                        }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
            }

            try {
                if (this.thisRow[columnIndex - 1] == null) {
                  this.wasNullFlag = true;
                } else {
                  this.wasNullFlag = false;
                }
            } catch (NullPointerException ex) {
                  this.wasNullFlag = true;
            }

            if (this.wasNullFlag) {
                return null;
            }

            if (!this.connection.getEmulateLocators()) {
                return new Blob((byte[]) this.thisRow[columnIndex - 1]);
            }

            return new BlobFromLocator(this, columnIndex);
        }

        return getNativeBlob(columnIndex);
    }

    /**
     * JDBC 2.0 Get a BLOB column.
     *
     * @param colName the column name
     *
     * @return an object representing a BLOB
     *
     * @throws SQLException if an error occurs.
     */
00679     public java.sql.Blob getBlob(String colName) throws SQLException {
        return getBlob(findColumn(colName));
    }

    /**
     * Get the value of a column in the current row as a Java boolean
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return the column value, false for SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
00692     public boolean getBoolean(int columnIndex) throws SQLException {
        if (!this.isBinaryEncoded) {
            checkColumnBounds(columnIndex);
            
            //
            // MySQL 5.0 and newer have an actual BIT type,
            // so we need to check for that here...
            //
            
            int columnIndexMinusOne = columnIndex - 1;
            
            Field field = this.fields[columnIndexMinusOne];
            
            if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) {
                  if (this.thisRow[columnIndexMinusOne] == null) {
                        this.wasNullFlag = true;
                        
                        return false;
                  }
                  
                  this.wasNullFlag = false;
                  
                  if (((byte[])this.thisRow[columnIndexMinusOne]).length == 0) {
                        return false;
                  }
                  
                  return (((byte[])this.thisRow[columnIndexMinusOne])[0] > (byte)0);
                  
            }
            
            String stringVal = getString(columnIndex);

            if ((stringVal != null) && (stringVal.length() > 0)) {
                int c = Character.toLowerCase(stringVal.charAt(0));

                return ((c == 't') || (c == 'y') || (c == '1') ||
                stringVal.equals("-1"));
            }

            return false;
        }

        return getNativeBoolean(columnIndex);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     */
00746     public boolean getBoolean(String columnName) throws SQLException {
        return getBoolean(findColumn(columnName));
    }

    /**
     * Get the value of a column in the current row as a Java byte.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
00759     public byte getByte(int columnIndex) throws SQLException {
        if (!this.isBinaryEncoded) {
            String stringVal = getString(columnIndex);

            if (this.wasNullFlag || (stringVal == null)) {
                return 0;
            }

            return getByteFromString(stringVal, columnIndex);
        }

        return getNativeByte(columnIndex);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     */
00782     public byte getByte(String columnName) throws SQLException {
        return getByte(findColumn(columnName));
    }

    /**
     * Get the value of a column in the current row as a Java byte array.
     *
     * <p>
     * <b>Be warned</b> If the blob is huge, then you may run out of memory.
     * </p>
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     *
     * @return the column value; if the value is SQL NULL, the result is null
     *
     * @exception SQLException if a database access error occurs
     */
00799     public byte[] getBytes(int columnIndex) throws SQLException {
      return getBytes(columnIndex, false);
    }
    
    protected byte[] getBytes(int columnIndex, boolean noConversion) throws SQLException {
        if (!this.isBinaryEncoded) {
            checkRowPos();

            try {
                if (this.thisRow[columnIndex - 1] == null) {
                  this.wasNullFlag = true;
                } else {
                  this.wasNullFlag = false;
                }
            } catch (NullPointerException E) {
                  this.wasNullFlag = true;
            } catch (ArrayIndexOutOfBoundsException aioobEx) {
                throw new SQLException(Messages.getString(
                        "ResultSet.Column_Index_out_of_range",
                        new Object[] {
                            new Integer(columnIndex),
                            new Integer(this.fields.length)
                        }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
            }

            if (this.wasNullFlag) {
                return null;
            }

            return (byte[]) this.thisRow[columnIndex - 1];
        }

        return getNativeBytes(columnIndex, noConversion);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     */
00843     public byte[] getBytes(String columnName) throws SQLException {
        return getBytes(findColumn(columnName));
    }

    //--------------------------JDBC 2.0-----------------------------------
    //---------------------------------------------------------------------
    // Getter's and Setter's
    //---------------------------------------------------------------------

    /**
     * JDBC 2.0
     *
     * <p>
     * Get the value of a column in the current row as a java.io.Reader.
     * </p>
     *
     * @param columnIndex the column to get the value from
     *
     * @return the value in the column as a java.io.Reader.
     *
     * @throws SQLException if an error occurs
     */
00865     public java.io.Reader getCharacterStream(int columnIndex)
        throws SQLException {
        if (!this.isBinaryEncoded) {
            String stringVal = getString(columnIndex);

            if (stringVal != null) {
                return new StringReader(stringVal);
            }

            return null;
        }

        return getNativeCharacterStream(columnIndex);
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Get the value of a column in the current row as a java.io.Reader.
     * </p>
     *
     * @param columnName the column name to retrieve the value from
     *
     * @return the value as a java.io.Reader
     *
     * @throws SQLException if an error occurs
     */
00893     public java.io.Reader getCharacterStream(String columnName)
        throws SQLException {
        return getCharacterStream(findColumn(columnName));
    }

    /**
     * JDBC 2.0 Get a CLOB column.
     *
     * @param i the first column is 1, the second is 2, ...
     *
     * @return an object representing a CLOB
     *
     * @throws SQLException if an error occurs
     */
00907     public java.sql.Clob getClob(int i) throws SQLException {
        if (!this.isBinaryEncoded) {
            return new com.mysql.jdbc.Clob(getString(i));
        }

        return getNativeClob(i);
    }

    /**
     * JDBC 2.0 Get a CLOB column.
     *
     * @param colName the column name
     *
     * @return an object representing a CLOB
     *
     * @throws SQLException if an error occurs
     */
00924     public java.sql.Clob getClob(String colName) throws SQLException {
        return getClob(findColumn(colName));
    }

    /**
     * JDBC 2.0 Return the concurrency of this result set.  The concurrency
     * used is determined by the statement that created the result set.
     *
     * @return the concurrency type, CONCUR_READ_ONLY, etc.
     *
     * @throws SQLException if a database-access error occurs
     */
00936     public int getConcurrency() throws SQLException {
        return (CONCUR_READ_ONLY);
    }

    /**
     * Get the name of the SQL cursor used by this ResultSet
     *
     * <p>
     * In SQL, a result table is retrieved though a cursor that is named.  The
     * current row of a result can be updated or deleted using a positioned
     * update/delete statement that references the cursor name.
     * </p>
     *
     * <p>
     * JDBC supports this SQL feature by providing the name of the SQL cursor
     * used by a ResultSet.  The current row of a ResulSet is also the current
     * row of this SQL cursor.
     * </p>
     *
     * <p>
     * <B>Note:</B> If positioned update is not supported, a SQLException is
     * thrown.
     * </p>
     *
     * @return the ResultSet's SQL cursor name.
     *
     * @exception SQLException if a database access error occurs
     */
00964     public String getCursorName() throws SQLException {
        throw new SQLException(Messages.getString(
                "ResultSet.Positioned_Update_not_supported"),
            SQLError.SQL_STATE_DRIVER_NOT_CAPABLE); //$NON-NLS-1$
    }

    /**
     * Get the value of a column in the current row as a java.sql.Date object
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return the column value; null if SQL NULL
     *
     * @exception java.sql.SQLException if a database access error occurs
     */
00979     public java.sql.Date getDate(int columnIndex) throws java.sql.SQLException {
        return getDate(columnIndex, null);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws java.sql.SQLException DOCUMENT ME!
     */
00992     public java.sql.Date getDate(String columnName)
        throws java.sql.SQLException {
        return getDate(findColumn(columnName));
    }

    /**
     * JDBC 2.0 Get the value of a column in the current row as a java.sql.Date
     * object.  Use the calendar to construct an appropriate millisecond value
     * for the Date, if the underlying database doesn't store timezone
     * information.
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     * @param cal the calendar to use in constructing the date
     *
     * @return the column value; if the value is SQL NULL, the result is null
     *
     * @exception SQLException if a database-access error occurs.
     */
01010     public java.sql.Date getDate(int columnIndex, Calendar cal)
        throws SQLException {
        if (this.isBinaryEncoded) {
            return getNativeDate(columnIndex,
                (cal != null) ? cal.getTimeZone() : this.getDefaultTimeZone());
        }

        String stringVal = getStringInternal(columnIndex, false);

        if (stringVal == null) {
            return null;
        }

        return getDateFromString(stringVal, columnIndex);
    }

    /**
     * Get the value of a column in the current row as a java.sql.Date object.
     * Use the calendar to construct an appropriate millisecond value for the
     * Date, if the underlying database doesn't store timezone information.
     *
     * @param columnName is the SQL name of the column
     * @param cal the calendar to use in constructing the date
     *
     * @return the column value; if the value is SQL NULL, the result is null
     *
     * @exception SQLException if a database-access error occurs.
     */
01038     public java.sql.Date getDate(String columnName, Calendar cal)
        throws SQLException {
        return getDate(findColumn(columnName), cal);
    }

    /**
     * Get the value of a column in the current row as a Java double.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
01052     public double getDouble(int columnIndex) throws SQLException {
        if (!this.isBinaryEncoded) {
            return getDoubleInternal(columnIndex);
        }

        return getNativeDouble(columnIndex);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     */
01069     public double getDouble(String columnName) throws SQLException {
        return getDouble(findColumn(columnName));
    }

    /**
     * JDBC 2.0 Give a hint as to the direction in which the rows in this
     * result set will be processed.  The initial value is determined by the
     * statement that produced the result set.  The fetch direction may be
     * changed at any time.
     *
     * @param direction the direction to fetch rows in.
     *
     * @exception SQLException if a database-access error occurs, or the result
     *            set type is TYPE_FORWARD_ONLY and direction is not
     *            FETCH_FORWARD. MM.MySQL actually ignores this, because it
     *            has the whole result set anyway, so the direction is
     *            immaterial.
     */
01087     public void setFetchDirection(int direction) throws SQLException {
        if ((direction != FETCH_FORWARD) && (direction != FETCH_REVERSE) &&
                (direction != FETCH_UNKNOWN)) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Illegal_value_for_fetch_direction_64"),
                SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }

        this.fetchDirection = direction;
    }

    /**
     * JDBC 2.0 Returns the fetch direction for this result set.
     *
     * @return the fetch direction for this result set.
     *
     * @exception SQLException if a database-access error occurs
     */
01105     public int getFetchDirection() throws SQLException {
        return this.fetchDirection;
    }

    /**
     * JDBC 2.0 Give the JDBC driver a hint as to the number of rows that
     * should be fetched from the database when more rows are needed for this
     * result set.  If the fetch size specified is zero, then the JDBC driver
     * ignores the value, and is free to make its own best guess as to what
     * the fetch size should be.  The default value is set by the statement
     * that creates the result set.  The fetch size may be changed at any
     * time.
     *
     * @param rows the number of rows to fetch
     *
     * @exception SQLException if a database-access error occurs, or the
     *            condition 0 lteq rows lteq this.getMaxRows() is not
     *            satisfied. Currently ignored by this driver.
     */
01124     public void setFetchSize(int rows) throws SQLException {
        if (rows < 0) { /* || rows > getMaxRows()*/
            throw new SQLException(Messages.getString(
                    "ResultSet.Value_must_be_between_0_and_getMaxRows()_66"), //$NON-NLS-1$
                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
        }

        this.fetchSize = rows;
    }

    /**
     * JDBC 2.0 Return the fetch size for this result set.
     *
     * @return the fetch size for this result set.
     *
     * @exception SQLException if a database-access error occurs
     */
01141     public int getFetchSize() throws SQLException {
        return this.fetchSize;
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Determine if the cursor is on the first row of the result set.
     * </p>
     *
     * @return true if on the first row, false otherwise.
     *
     * @exception SQLException if a database-access error occurs.
     */
01156     public boolean isFirst() throws SQLException {
      checkClosed();
      
        return this.rowData.isFirst();
    }

    /**
     * Get the value of a column in the current row as a Java float.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
01171     public float getFloat(int columnIndex) throws SQLException {
        if (!this.isBinaryEncoded) {
            String val = null;

            val = getString(columnIndex);
            
            return getFloatFromString(val, columnIndex);
        }

        return getNativeFloat(columnIndex);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     */
01192     public float getFloat(String columnName) throws SQLException {
        return getFloat(findColumn(columnName));
    }

    /**
     * Get the value of a column in the current row as a Java int.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
01205     public int getInt(int columnIndex) throws SQLException {
        if (!this.isBinaryEncoded) {
            if (this.connection.getUseFastIntParsing()) {
                checkRowPos();

                try {
                    if (this.thisRow[columnIndex - 1] == null) {
                        this.wasNullFlag = true;
                    } else {
                        this.wasNullFlag = false;
                    }
                } catch (NullPointerException E) {
                    this.wasNullFlag = true;
                } catch (ArrayIndexOutOfBoundsException aioobEx) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Column_Index_out_of_range",
                            new Object[] {
                                new Integer(columnIndex),
                                new Integer(this.fields.length)
                            }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
                }

                if (this.wasNullFlag) {
                    return 0;
                }

                byte[] intAsBytes = (byte[]) this.thisRow[columnIndex - 1];

                boolean needsFullParse = false;

                for (int i = 0; i < intAsBytes.length; i++) {
                    if (((char) intAsBytes[i] == 'e') ||
                            ((char) intAsBytes[i] == 'E')) {
                        needsFullParse = true;

                        break;
                    }
                }

                if (!needsFullParse) {
                    try {
                        return parseIntWithOverflowCheck(columnIndex, intAsBytes, null);
                    } catch (NumberFormatException nfe) {
                        try {
                            
                            return parseIntAsDouble(columnIndex, new String(
                                    intAsBytes));
                        } catch (NumberFormatException newNfe) {
                            ; // ignore, it's not a number
                        }

                        throw new SQLException(Messages.getString(
                                "ResultSet.Invalid_value_for_getInt()_-____74") +
                            new String(intAsBytes) //$NON-NLS-1$
                             +"'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                    }
                }
            }

            String val = null;

            try {
                val = getString(columnIndex);

                if ((val != null) && (val.length() != 0)) {
                    if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1) &&
                            (val.indexOf(".") == -1)) {
                        return Integer.parseInt(val);
                    }

                    // Convert floating point
                    return parseIntAsDouble(columnIndex, val);
                }

                return 0;
            } catch (NumberFormatException nfe) {
                try {
                    return parseIntAsDouble(columnIndex, val);
                } catch (NumberFormatException newNfe) {
                    ; // ignore, it's not a number
                }

                throw new SQLException(Messages.getString(
                        "ResultSet.Invalid_value_for_getInt()_-____74") +
                    val //$NON-NLS-1$
                     +"'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
            }
        }

        return getNativeInt(columnIndex);
    }

    private short parseShortWithOverflowCheck(int columnIndex, 
            byte[] valueAsBytes, 
                  String valueAsString) throws NumberFormatException, SQLException {
      
      short shortValue = 0;
      
      if (valueAsBytes == null && valueAsString == null) {
            return 0;
      }
      
      if (valueAsBytes != null) {
            shortValue = StringUtils.getShort(valueAsBytes);
      } else {
            shortValue = Short.parseShort(valueAsString);
      }
      
      if (this.connection.getJdbcCompliantTruncation()) {
            if (shortValue == Short.MIN_VALUE || shortValue == Short.MAX_VALUE) {
                  long valueAsLong = Long.parseLong(valueAsString == null ? new String(valueAsBytes) : valueAsString);
                  
                  if (valueAsLong < Short.MIN_VALUE || valueAsLong > Short.MAX_VALUE) {
                        throwRangeException(valueAsString == null ? new String(valueAsBytes) : valueAsString, columnIndex, Types.SMALLINT);
                  }
            }
      }
      
      return shortValue;      
    }
    
    private short parseShortAsDouble(int columnIndex, String val) throws NumberFormatException, SQLException {
      if (val == null) {
            return 0;
      }
      
      double valueAsDouble = Double.parseDouble(val);
      
      if (this.connection.getJdbcCompliantTruncation()) {
            if (valueAsDouble < Short.MIN_VALUE || 
                        valueAsDouble > Short.MAX_VALUE) {
                  throwRangeException(String.valueOf(valueAsDouble), columnIndex, Types.SMALLINT);
            }
      }
      
      return (short) valueAsDouble;
    }
    
    private int parseIntWithOverflowCheck(int columnIndex, 
            byte[] valueAsBytes, 
                  String valueAsString) throws NumberFormatException, SQLException {
      
      int intValue = 0;
      
      if (valueAsBytes == null && valueAsString == null) {
            return 0;
      }
      
      if (valueAsBytes != null) {
            intValue = StringUtils.getInt(valueAsBytes);
      } else {
            intValue = Integer.parseInt(valueAsString);
      }
      
      if (this.connection.getJdbcCompliantTruncation()) {
            if (intValue == Integer.MIN_VALUE || intValue == Integer.MAX_VALUE) {
                  long valueAsLong = Long.parseLong(valueAsString == null ? new String(valueAsBytes) : valueAsString);
                  
                  if (valueAsLong < Integer.MIN_VALUE || valueAsLong > Integer.MAX_VALUE) {
                        throwRangeException(valueAsString == null ? new String(valueAsBytes) : valueAsString, columnIndex, Types.INTEGER);
                  }
            }
      }
      
      return intValue;  
    }
    
    private int parseIntAsDouble(int columnIndex, String val) throws NumberFormatException, SQLException {
      if (val == null) {
            return 0;
      }
      
      double valueAsDouble = Double.parseDouble(val);
      
      if (this.connection.getJdbcCompliantTruncation()) {
            if (valueAsDouble < Integer.MIN_VALUE || 
                        valueAsDouble > Integer.MAX_VALUE) {
                  throwRangeException(String.valueOf(valueAsDouble), columnIndex, Types.INTEGER);
            }
      }
      
      return (int) valueAsDouble;
    }
    
    private long parseLongWithOverflowCheck(int columnIndex, 
            byte[] valueAsBytes, 
                  String valueAsString) throws NumberFormatException, SQLException {
      
      long longValue = 0;
      
      if (valueAsBytes == null && valueAsString == null) {
            return 0;
      }
      
      if (valueAsBytes != null) {
            longValue = StringUtils.getLong(valueAsBytes);
      } else {
            longValue = Long.parseLong(valueAsString);
      }
      
      if (this.connection.getJdbcCompliantTruncation()) {
            if (longValue == Integer.MIN_VALUE || longValue == Integer.MAX_VALUE) {
                  double valueAsDouble = Double.parseDouble(valueAsString == null ? new String(valueAsBytes) : valueAsString);
                  
                  if (valueAsDouble < Long.MIN_VALUE || valueAsDouble > Long.MAX_VALUE) {
                        throwRangeException(valueAsString == null ? new String(valueAsBytes) : valueAsString, columnIndex, Types.BIGINT);
                  }
            }
      }
      
      return longValue; 
    }
    
    private long parseLongAsDouble(int columnIndex, String val) throws NumberFormatException, SQLException {
      if (val == null) {
            return 0;
      }
      
      double valueAsDouble = Double.parseDouble(val);
      
      if (this.connection.getJdbcCompliantTruncation()) {
            if (valueAsDouble < Long.MIN_VALUE || 
                        valueAsDouble > Long.MAX_VALUE) {
                  throwRangeException(val, columnIndex, Types.BIGINT);
            }
      }
      
      return (long) valueAsDouble;
    }
    
      /**
       * @param truncation
       */
01438       private synchronized void addAWarning(SQLWarning warning) {
            if (this.warningChain == null) {
                  this.warningChain = warning;
            } else {
                  SQLWarning warningToAppendTo = this.warningChain;
                  
                  while (warningToAppendTo.getNextWarning() != null) {
                        warningToAppendTo = warningToAppendTo.getNextWarning();
                  }
                  
                  warningToAppendTo.setNextWarning(warning);
            }
            
      }
      
      private void throwRangeException(String valueAsString, int columnIndex, int jdbcType) throws SQLException {
            String datatype = null;
            
            switch (jdbcType) {
                  case Types.TINYINT:
                        datatype = "TINYINT";
                        break;
                  case Types.SMALLINT:
                        datatype = "SMALLINT";
                        break;
                  case Types.INTEGER:
                        datatype = "INTEGER";
                        break;
                  case Types.BIGINT:
                        datatype = "BIGINT";
                        break;
                  case Types.REAL:
                        datatype = "REAL";
                        break;
                  case Types.FLOAT:
                        datatype = "FLOAT";
                        break;
                  case Types.DOUBLE:
                        datatype = "DOUBLE";
                        break;
                  case Types.DECIMAL:
                        datatype = "DECIMAL";
                        break;
                  default:
                        datatype = " (JDBC type '" + jdbcType + "')";
            }
            
            throw new SQLException("'" + valueAsString + "' in column '" + columnIndex + "' is outside valid range for the datatype " + datatype + ".", SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE);
      }
      
    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     */
01497     public int getInt(String columnName) throws SQLException {
        return getInt(findColumn(columnName));
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Determine if the cursor is on the last row of the result set. Note:
     * Calling isLast() may be expensive since the JDBC driver might need to
     * fetch ahead one row in order to determine whether the current row is
     * the last row in the result set.
     * </p>
     *
     * @return true if on the last row, false otherwise.
     *
     * @exception SQLException if a database-access error occurs.
     */
01515     public boolean isLast() throws SQLException {
      checkClosed();
      
        return this.rowData.isLast();
    }

    /**
     * Get the value of a column in the current row as a Java long.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
01530     public long getLong(int columnIndex) throws SQLException {
        if (!this.isBinaryEncoded) {
            if (this.connection.getUseFastIntParsing()) {
                checkRowPos();

                try {
                    if (this.thisRow[columnIndex - 1] == null) {
                        this.wasNullFlag = true;
                    } else {
                        this.wasNullFlag = false;
                    }
                } catch (NullPointerException E) {
                    this.wasNullFlag = true;
                } catch (ArrayIndexOutOfBoundsException aioobEx) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Column_Index_out_of_range",
                            new Object[] {
                                new Integer(columnIndex),
                                new Integer(this.fields.length)
                            }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
                }

                if (this.wasNullFlag) {
                    return 0;
                }

                byte[] longAsBytes = (byte[]) this.thisRow[columnIndex - 1];

                boolean needsFullParse = false;

                for (int i = 0; i < longAsBytes.length; i++) {
                    if (((char) longAsBytes[i] == 'e') ||
                            ((char) longAsBytes[i] == 'E')) {
                        needsFullParse = true;

                        break;
                    }
                }

                if (!needsFullParse) {
                    try {
                        return parseLongWithOverflowCheck(columnIndex, longAsBytes, null);
                    } catch (NumberFormatException nfe) {
                        try {
                            // To do: Warn of over/underflow???
                            return parseLongAsDouble(columnIndex, new String(longAsBytes));
                        } catch (NumberFormatException newNfe) {
                            // ; // ignore, it's not a number
                        }

                        throw new SQLException(Messages.getString(
                                "ResultSet.Invalid_value_for_getLong()_-____79") +
                            new String(longAsBytes) //$NON-NLS-1$
                             +"'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                    }
                }
            }

            String val = null;

            try {
                val = getString(columnIndex);

                if ((val != null) && (val.length() != 0)) {
                    if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1)) {
                        return parseLongWithOverflowCheck(columnIndex, null, val);
                    }

                    //Convert floating point
                    return parseLongAsDouble(columnIndex, val);
                }

                return 0;
            } catch (NumberFormatException nfe) {
                try {
                    return parseLongAsDouble(columnIndex, val);
                } catch (NumberFormatException newNfe) {
                    // ; // ignore, it's not a number
                }

                throw new SQLException(Messages.getString(
                        "ResultSet.Invalid_value_for_getLong()_-____79") +
                    val //$NON-NLS-1$
                     +"'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
            }
        }

        return getNativeLong(columnIndex);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     */
01629     public long getLong(String columnName) throws SQLException {
        return getLong(findColumn(columnName));
    }

    /**
     * The numbers, types and properties of a ResultSet's columns are provided
     * by the getMetaData method
     *
     * @return a description of the ResultSet's columns
     *
     * @exception SQLException if a database access error occurs
     */
01641     public java.sql.ResultSetMetaData getMetaData() throws SQLException {
      checkClosed();
      
        return new com.mysql.jdbc.ResultSetMetaData(this.fields);
    }

    /**
     * Get the value of a column in the current row as a Java object
     *
     * <p>
     * This method will return the value of the given column as a Java object.
     * The type of the Java object will be the default Java Object type
     * corresponding to the column's SQL type, following the mapping specified
     * in the JDBC specification.
     * </p>
     *
     * <p>
     * This method may also be used to read database specific abstract data
     * types.
     * </p>
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return a Object holding the column value
     *
     * @exception SQLException if a database access error occurs
     */
01668     public Object getObject(int columnIndex) throws SQLException {
        checkRowPos();

        try {
            if (this.thisRow[columnIndex - 1] == null) {
                  this.wasNullFlag = true;

                return null;
            }
        } catch (ArrayIndexOutOfBoundsException aioobEx) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Column_Index_out_of_range",
                    new Object[] {
                        new Integer(columnIndex),
                        new Integer(this.fields.length)
                    }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }

        this.wasNullFlag = false;

        Field field;
        field = this.fields[columnIndex - 1];

        //
        // If they come from a binary-encode result set,
        // no need to create another new object to represent
        // the value, just return it directly, unless it's
        // a byte[], which means it could be a string or blob.
        //
        if (this.isBinaryEncoded &&
                !(this.thisRow[columnIndex - 1] instanceof byte[])) {
            
            
            //
            // Special case here...If this is a 'bit' type, it will actually have 
            // been returned as an Integer by the server...
            //
            if (field.getSQLType() == Types.BIT) {
                  // valueOf would be nicer here, but it isn't
                  // present in JDK-1.3.1, which is what the CTS
                  // uses.
                  return new Boolean(getBoolean(columnIndex));
            }
            
            Object columnValue = this.thisRow[columnIndex - 1];

            if (columnValue == null) {
                this.wasNullFlag = true;

                return null;
            }

            return columnValue;
        }

        switch (field.getSQLType()) {
        case Types.BIT:
            if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT 
                        && field.getLength() > 0) {
                  return getBytes(columnIndex);
            }
            
            // valueOf would be nicer here, but it isn't
            // present in JDK-1.3.1, which is what the CTS
            // uses.
            return new Boolean(getBoolean(columnIndex));

        case Types.TINYINT:
            return new Integer(getByte(columnIndex));

        case Types.SMALLINT:
            return new Integer(getInt(columnIndex));

        case Types.INTEGER:

            if (!field.isUnsigned()) {
                return new Integer(getInt(columnIndex));
            }

            return new Long(getLong(columnIndex));

        case Types.BIGINT:

            if (!field.isUnsigned()) {
                return new Long(getLong(columnIndex));
            }

            String stringVal = getString(columnIndex);

            if (stringVal == null) {
                return null;
            }

            try {
                return new BigInteger(stringVal);
            } catch (NumberFormatException nfe) {
                throw new SQLException(Messages.getString(
                        "ResultSet.Bad_format_for_BigInteger",
                        new Object[] { new Integer(columnIndex), stringVal }),
                    SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
            }

        case Types.DECIMAL:
        case Types.NUMERIC:
            stringVal = getString(columnIndex);

            BigDecimal val;

            if (stringVal != null) {
                if (stringVal.length() == 0) {
                    val = new BigDecimal(0);

                    return val;
                }

                try {
                    val = new BigDecimal(stringVal);
                } catch (NumberFormatException ex) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Bad_format_for_BigDecimal____86") //$NON-NLS-1$
                         +stringVal +
                        Messages.getString("ResultSet.___in_column__87") +
                        columnIndex + "(" //$NON-NLS-1$
                         + this.fields[columnIndex - 1] + ").",
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                }

                return val;
            }

            return null;

        case Types.REAL:
            return new Float(getFloat(columnIndex));

        case Types.FLOAT:
        case Types.DOUBLE:
            return new Double(getDouble(columnIndex));

        case Types.CHAR:
        case Types.VARCHAR:
        case Types.LONGVARCHAR:
            if (!field.isOpaqueBinary()) {
                  return getString(columnIndex);
            }
                  
            return getBytes(columnIndex);

        case Types.BINARY:
        case Types.VARBINARY:
        case Types.LONGVARBINARY:

            if (!field.isBlob()) {
                return getString(columnIndex);
            } else if (!field.isBinary()) {
                return getString(columnIndex);
            } else {
                byte[] data = getBytes(columnIndex);
                
                if (this.connection.getAutoDeserialize()) {
                  Object obj = data;

                      if ((data != null) && (data.length >= 2)) {
                          if ((data[0] == -84) && (data[1] == -19)) {
                              // Serialized object?
                              try {
                                  ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);
                                  ObjectInputStream objIn = new ObjectInputStream(bytesIn);
                                  obj = objIn.readObject();
                                  objIn.close();
                                  bytesIn.close();
                              } catch (ClassNotFoundException cnfe) {
                                  throw new SQLException(Messages.getString(
                                          "ResultSet.Class_not_found___91") //$NON-NLS-1$
                                       +cnfe.toString() +
                                      Messages.getString(
                                          "ResultSet._while_reading_serialized_object_92")); //$NON-NLS-1$
                              } catch (IOException ex) {
                                  obj = data; // not serialized?
                              }
                          }
                      }
      
                      return obj;
                }
                
                return data;
            }

        case Types.DATE:
            return getDate(columnIndex);

        case Types.TIME:
            return getTime(columnIndex);

        case Types.TIMESTAMP:
            return getTimestamp(columnIndex);

        default:
            return getString(columnIndex);
        }
    }

    /**
     * Get the value of a column in the current row as a Java object
     *
     * <p>
     * This method will return the value of the given column as a Java object.
     * The type of the Java object will be the default Java Object type
     * corresponding to the column's SQL type, following the mapping specified
     * in the JDBC specification.
     * </p>
     *
     * <p>
     * This method may also be used to read database specific abstract data
     * types.
     * </p>
     *
     * @param columnName is the SQL name of the column
     *
     * @return a Object holding the column value
     *
     * @exception SQLException if a database access error occurs
     */
01892     public Object getObject(String columnName) throws SQLException {
        return getObject(findColumn(columnName));
    }

    /**
     * JDBC 2.0 Returns the value of column i as a Java object.  Use the map to
     * determine the class from which to construct data of SQL structured and
     * distinct types.
     *
     * @param i the first column is 1, the second is 2, ...
     * @param map the mapping from SQL type names to Java classes
     *
     * @return an object representing the SQL value
     *
     * @throws SQLException because this is not implemented
     */
01908     public Object getObject(int i, java.util.Map map) throws SQLException {
        return getObject(i);
    }

    /**
     * JDBC 2.0 Returns the value of column i as a Java object.  Use the map to
     * determine the class from which to construct data of SQL structured and
     * distinct types.
     *
     * @param colName the column name
     * @param map the mapping from SQL type names to Java classes
     *
     * @return an object representing the SQL value
     *
     * @throws SQLException as this is not implemented
     */
01924     public Object getObject(String colName, java.util.Map map)
        throws SQLException {
        return getObject(findColumn(colName), map);
    }

    /**
     * JDBC 2.0 Get a REF(&lt;structured-type&gt;) column.
     *
     * @param i the first column is 1, the second is 2, ...
     *
     * @return an object representing data of an SQL REF type
     *
     * @throws SQLException as this is not implemented
     * @throws NotImplemented DOCUMENT ME!
     */
01939     public java.sql.Ref getRef(int i) throws SQLException {
        throw new NotImplemented();
    }

    /**
     * JDBC 2.0 Get a REF(&lt;structured-type&gt;) column.
     *
     * @param colName the column name
     *
     * @return an object representing data of an SQL REF type
     *
     * @throws SQLException as this method is not implemented.
     * @throws NotImplemented DOCUMENT ME!
     */
01953     public java.sql.Ref getRef(String colName) throws SQLException {
        throw new NotImplemented();
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Determine the current row number.  The first row is number 1, the second
     * number 2, etc.
     * </p>
     *
     * @return the current row number, else return 0 if there is no current row
     *
     * @exception SQLException if a database-access error occurs.
     */
01969     public int getRow() throws SQLException {
      checkClosed();
      
        int currentRowNumber = this.rowData.getCurrentRowNumber();
        int row = 0;

        // Non-dynamic result sets can be interrogated
        // for this information
        if (!this.rowData.isDynamic()) {
            if ((currentRowNumber < 0) || this.rowData.isAfterLast() ||
                        this.rowData.isEmpty()) {
                row = 0;
            } else {
                row = currentRowNumber + 1;
            }
        } else {
            // dynamic (streaming) can not
            row = currentRowNumber + 1;
        }

        return row;
    }

    /**
     * Get the value of a column in the current row as a Java short.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
02001     public short getShort(int columnIndex) throws SQLException {
        if (!this.isBinaryEncoded) {
            if (this.connection.getUseFastIntParsing()) {
                checkRowPos();

                try {
                    if (this.thisRow[columnIndex - 1] == null) {
                        this.wasNullFlag = true;
                    } else {
                        this.wasNullFlag = false;
                    }
                } catch (NullPointerException E) {
                    this.wasNullFlag = true;
                } catch (ArrayIndexOutOfBoundsException aioobEx) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Column_Index_out_of_range",
                            new Object[] {
                                new Integer(columnIndex),
                                new Integer(this.fields.length)
                            }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
                }

                if (this.wasNullFlag) {
                    return 0;
                }

                byte[] shortAsBytes = (byte[]) this.thisRow[columnIndex - 1];

                boolean needsFullParse = false;

                for (int i = 0; i < shortAsBytes.length; i++) {
                    if (((char) shortAsBytes[i] == 'e') ||
                            ((char) shortAsBytes[i] == 'E')) {
                        needsFullParse = true;

                        break;
                    }
                }

                if (!needsFullParse) {
                    try {
                        return parseShortWithOverflowCheck(columnIndex, shortAsBytes, null);
                    } catch (NumberFormatException nfe) {
                        try {
                            // To do: Warn of over/underflow???
                            return parseShortAsDouble(columnIndex, new String(
                                    shortAsBytes));
                        } catch (NumberFormatException newNfe) {
                            ; // ignore, it's not a number
                        }

                        throw new SQLException(Messages.getString(
                                "ResultSet.Invalid_value_for_getShort()_-____96") +
                            new String(shortAsBytes) //$NON-NLS-1$
                             +"'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                    }
                }
            }

            String val = null;

            try {
                val = getString(columnIndex);

                if ((val != null) && (val.length() != 0)) {
                    if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1) &&
                            (val.indexOf(".") == -1)) {
                        return parseShortWithOverflowCheck(columnIndex, null, val);
                    }

                    // Convert floating point
                    return parseShortAsDouble(columnIndex, val);
                }

                return 0;
            } catch (NumberFormatException nfe) {
                try {
                    return parseShortAsDouble(columnIndex, val);
                } catch (NumberFormatException newNfe) {
                    ; // ignore, it's not a number
                }

                throw new SQLException(Messages.getString(
                        "ResultSet.Invalid_value_for_getShort()_-____96") +
                    val //$NON-NLS-1$
                     +"'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
            }
        }

        return getNativeShort(columnIndex);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     */
02102     public short getShort(String columnName) throws SQLException {
        return getShort(findColumn(columnName));
    }

    /**
     * JDBC 2.0 Return the Statement that produced the ResultSet.
     *
     * @return the Statment that produced the result set, or null if the result
     *         was produced some other way.
     *
     * @exception SQLException if a database-access error occurs
     */
02114     public java.sql.Statement getStatement() throws SQLException {
      if (this.wrapperStatement != null) {
            return this.wrapperStatement;
      }
      
        return this.owningStatement;
    }

    /**
     * Get the value of a column in the current row as a Java String
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return the column value, null for SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
02131     public String getString(int columnIndex) throws SQLException {
      return getStringInternal(columnIndex, true);
    }
    
    protected String getStringInternal(int columnIndex, boolean checkDateTypes) throws SQLException {
        if (!this.isBinaryEncoded) {
            checkRowPos();
            checkColumnBounds(columnIndex);

            if (this.fields == null) {
                throw new SQLException(Messages.getString(
                        "ResultSet.Query_generated_no_fields_for_ResultSet_99"), //$NON-NLS-1$
                    SQLError.SQL_STATE_INVALID_COLUMN_NUMBER);
            }

            try {
                if (this.thisRow[columnIndex - 1] == null) {
                  this.wasNullFlag = true;

                    return null;
                }

                this.wasNullFlag = false;
            } catch (NullPointerException E) {
                  this.wasNullFlag = true;

                return null;
            }

            String stringVal = null;
            columnIndex--; // JDBC is 1-based, Java is not !?

            if ((this.connection != null) && this.connection.getUseUnicode()) {
                try {
                    String encoding = this.fields[columnIndex].getCharacterSet();

                    if (encoding == null) {
                        stringVal = new String((byte[]) this.thisRow[columnIndex]);
                    } else {
                        SingleByteCharsetConverter converter = this.connection.getCharsetConverter(encoding);

                        if (converter != null) {
                            stringVal = converter.toString((byte[]) this.thisRow[columnIndex]);
                        } else {
                            stringVal = new String((byte[]) this.thisRow[columnIndex],
                                    encoding);
                        }
                    }
                } catch (java.io.UnsupportedEncodingException E) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Unsupported_character_encoding____101") //$NON-NLS-1$
                         + this.connection.getEncoding() + "'.", "0S100");
                }
            } else {
                stringVal = StringUtils.toAsciiString((byte[]) this.thisRow[columnIndex]);
            }

            // Handles timezone conversion and zero-date behavior
            
            if (checkDateTypes && !this.connection.getNoDatetimeStringSync()) {
                  switch (this.fields[columnIndex].getSQLType()) {
                        case Types.TIME:
                              Time tm = getTimeFromString(stringVal, columnIndex + 1, this.getDefaultTimeZone(), false);
                        
                              if (tm == null) {
                                    this.wasNullFlag = true;
                                    
                                    return null;
                              }
                              
                              this.wasNullFlag = false;
                              
                              return tm.toString();
                        case Types.DATE:
                              Date dt = getDateFromString(stringVal, columnIndex + 1);
                        
                              if (dt == null) {
                                    this.wasNullFlag = true;
                                    
                                    return null;
                              }
                              
                              this.wasNullFlag = false;
                              
                              return dt.toString();
                        case Types.TIMESTAMP:
                              Timestamp ts = getTimestampFromString(columnIndex + 1, stringVal, this.getDefaultTimeZone(), false);
                        
                              if (ts == null) {
                                    this.wasNullFlag = true;
                                    
                                    return null;
                              }
                              
                              this.wasNullFlag = false;
                              
                              return ts.toString();
                        default:
                              break;
                  }
            }
            
            return stringVal;
        }

        return getNativeString(columnIndex);
    }

    /**
     * The following routines simply convert the columnName into a columnIndex
     * and then call the appropriate routine above.
     *
     * @param columnName is the SQL name of the column
     *
     * @return the column value
     *
     * @exception SQLException if a database access error occurs
     */
02249     public String getString(String columnName) throws SQLException {
        return getString(findColumn(columnName));
    }

    /**
     * Get the value of a column in the current row as a java.sql.Time object
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return the column value; null if SQL NULL
     *
     * @throws java.sql.SQLException if a database access error occurs
     */
02262     public Time getTime(int columnIndex) throws java.sql.SQLException {
        return getTimeInternal(columnIndex, this.getDefaultTimeZone(), false);
    }

    /**
     * Get the value of a column in the current row as a java.sql.Time object.
     *
     * @param columnName is the SQL name of the column
     *
     * @return the column value; if the value is SQL NULL, the result is null
     *
     * @throws java.sql.SQLException if a database-access error occurs.
     */
02275     public Time getTime(String columnName) throws java.sql.SQLException {
        return getTime(findColumn(columnName));
    }

    /**
     * Get the value of a column in the current row as a java.sql.Time object.
     * Use the calendar to construct an appropriate millisecond value for the
     * Time, if the underlying database doesn't store timezone information.
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     * @param cal the calendar to use in constructing the time
     *
     * @return the column value; if the value is SQL NULL, the result is null
     *
     * @exception SQLException if a database-access error occurs.
     */
02291     public java.sql.Time getTime(int columnIndex, Calendar cal)
        throws SQLException {
        return getTimeInternal(columnIndex, cal.getTimeZone(), true);
    }

    /**
     * Get the value of a column in the current row as a java.sql.Time object.
     * Use the calendar to construct an appropriate millisecond value for the
     * Time, if the underlying database doesn't store timezone information.
     *
     * @param columnName is the SQL name of the column
     * @param cal the calendar to use in constructing the time
     *
     * @return the column value; if the value is SQL NULL, the result is null
     *
     * @exception SQLException if a database-access error occurs.
     */
02308     public java.sql.Time getTime(String columnName, Calendar cal)
        throws SQLException {
        return getTime(findColumn(columnName), cal);
    }

    /**
     * Get the value of a column in the current row as a java.sql.Timestamp
     * object
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return the column value; null if SQL NULL
     *
     * @exception java.sql.SQLException if a database access error occurs
     */
02323     public Timestamp getTimestamp(int columnIndex) throws java.sql.SQLException {
        return getTimestampInternal(columnIndex, this.getDefaultTimeZone(), false);
    }

    /**
     * Get the value of a column in the current row as a java.sql.Timestamp
     * object. Use the calendar to construct an appropriate millisecond value
     * for the Timestamp, if the underlying database doesn't store timezone
     * information.
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     * @param cal the calendar to use in constructing the timestamp
     *
     * @return the column value; if the value is SQL NULL, the result is null
     *
     * @exception SQLException if a database-access error occurs.
     */
02340     public java.sql.Timestamp getTimestamp(int columnIndex, Calendar cal)
        throws SQLException {
        return getTimestampInternal(columnIndex, cal.getTimeZone(), true);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws java.sql.SQLException DOCUMENT ME!
     */
02354     public Timestamp getTimestamp(String columnName)
        throws java.sql.SQLException {
        return getTimestamp(findColumn(columnName));
    }

    /**
     * Get the value of a column in the current row as a java.sql.Timestamp
     * object. Use the calendar to construct an appropriate millisecond value
     * for the Timestamp, if the underlying database doesn't store timezone
     * information.
     *
     * @param columnName is the SQL name of the column
     * @param cal the calendar to use in constructing the timestamp
     *
     * @return the column value; if the value is SQL NULL, the result is null
     *
     * @exception SQLException if a database-access error occurs.
     */
02372     public java.sql.Timestamp getTimestamp(String columnName, Calendar cal)
        throws SQLException {
        return getTimestamp(findColumn(columnName), cal);
    }

    /**
     * JDBC 2.0 Return the type of this result set.  The type is determined
     * based on the statement that created the result set.
     *
     * @return TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE, or
     *         TYPE_SCROLL_SENSITIVE
     *
     * @exception SQLException if a database-access error occurs
     */
02386     public int getType() throws SQLException {
        return this.resultSetType;
    }

    /**
     * @see ResultSet#getURL(int)
     */
02393     public URL getURL(int colIndex) throws SQLException {
        String val = getString(colIndex);

        if (val == null) {
            return null;
        }

        try {
            return new URL(val);
        } catch (MalformedURLException mfe) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Malformed_URL____104") + val + "'",
                SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }
    }

    /**
     * @see ResultSet#getURL(String)
     */
02412     public URL getURL(String colName) throws SQLException {
        String val = getString(colName);

        if (val == null) {
            return null;
        }

        try {
            return new URL(val);
        } catch (MalformedURLException mfe) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Malformed_URL____107") + val + "'",
                SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }
    }

    /**
     * A column value can also be retrieved as a stream of Unicode characters.
     * We implement this as a binary stream.
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return a Java InputStream that delivers the database column value as a
     *         stream of two byte Unicode characters.  If the value is SQL
     *         NULL, then the result is null
     *
     * @exception SQLException if a database access error occurs
     *
     * @see getAsciiStream
     * @see getBinaryStream
     * @deprecated
     */
02444     public InputStream getUnicodeStream(int columnIndex)
        throws SQLException {
        if (!this.isBinaryEncoded) {
            checkRowPos();

            return getBinaryStream(columnIndex);
        }

        return getNativeBinaryStream(columnIndex);
    }

    /**
     * DOCUMENT ME!
     *
     * @param columnName DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws SQLException DOCUMENT ME!
     *
     * @deprecated
     */
02466     public InputStream getUnicodeStream(String columnName)
        throws SQLException {
        return getUnicodeStream(findColumn(columnName));
    }

    /**
     * The first warning reported by calls on this ResultSet is returned.
     * Subsequent ResultSet warnings will be chained to this
     * java.sql.SQLWarning.
     *
     * <p>
     * The warning chain is automatically cleared each time a new row is read.
     * </p>
     *
     * <p>
     * <B>Note:</B> This warning chain only covers warnings caused by ResultSet
     * methods.  Any warnings caused by statement methods (such as reading OUT
     * parameters) will be chained on the Statement object.
     * </p>
     *
     * @return the first java.sql.SQLWarning or null;
     *
     * @exception SQLException if a database access error occurs.
     */
02490     public java.sql.SQLWarning getWarnings() throws SQLException {
        return this.warningChain;
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Move to an absolute row number in the result set.
     * </p>
     *
     * <p>
     * If row is positive, moves to an absolute row with respect to the
     * beginning of the result set.  The first row is row 1, the second is row
     * 2, etc.
     * </p>
     *
     * <p>
     * If row is negative, moves to an absolute row position with respect to
     * the end of result set.  For example, calling absolute(-1) positions the
     * cursor on the last row, absolute(-2) indicates the next-to-last row,
     * etc.
     * </p>
     *
     * <p>
     * An attempt to position the cursor beyond the first/last row in the
     * result set, leaves the cursor before/after the first/last row,
     * respectively.
     * </p>
     *
     * <p>
     * Note: Calling absolute(1) is the same as calling first(). Calling
     * absolute(-1) is the same as calling last().
     * </p>
     *
     * @param row the row number to move to
     *
     * @return true if on the result set, false if off.
     *
     * @exception SQLException if a database-access error occurs, or row is 0,
     *            or result set type is TYPE_FORWARD_ONLY.
     */
02532     public boolean absolute(int row) throws SQLException {
        checkClosed();

        boolean b;

        if (this.rowData.size() == 0) {
            b = false;
        } else {
            if (row == 0) {
                throw new SQLException(Messages.getString(
                        "ResultSet.Cannot_absolute_position_to_row_0_110"), //$NON-NLS-1$
                    SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
            }

            if (this.onInsertRow) {
                  this.onInsertRow = false;
            }

            if (this.doingUpdates) {
                  this.doingUpdates = false;
            }

            if (row == 1) {
                b = first();
            } else if (row == -1) {
                b = last();
            } else if (row > this.rowData.size()) {
                afterLast();
                b = false;
            } else {
                if (row < 0) {
                    // adjust to reflect after end of result set
                    int newRowPosition = this.rowData.size() + row + 1;

                    if (newRowPosition <= 0) {
                        beforeFirst();
                        b = false;
                    } else {
                        b = absolute(newRowPosition);
                    }
                } else {
                    row--; // adjust for index difference
                    this.rowData.setCurrentRow(row);
                    this.thisRow = this.rowData.getAt(row);
                    b = true;
                }
            }
        }

        return b;
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Moves to the end of the result set, just after the last row.  Has no
     * effect if the result set contains no rows.
     * </p>
     *
     * @exception SQLException if a database-access error occurs, or result set
     *            type is TYPE_FORWARD_ONLY.
     */
02595     public void afterLast() throws SQLException {
        checkClosed();

        if (this.onInsertRow) {
            this.onInsertRow = false;
        }

        if (this.doingUpdates) {
            this.doingUpdates = false;
        }

        if (this.rowData.size() != 0) {
            this.rowData.afterLast();
            this.thisRow = null;
        }
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Moves to the front of the result set, just before the first row. Has no
     * effect if the result set contains no rows.
     * </p>
     *
     * @exception SQLException if a database-access error occurs, or result set
     *            type is TYPE_FORWARD_ONLY
     */
02623     public void beforeFirst() throws SQLException {
        checkClosed();

        if (this.onInsertRow) {
            this.onInsertRow = false;
        }

        if (this.doingUpdates) {
            this.doingUpdates = false;
        }

        if (this.rowData.size() == 0) {
            return;
        }

        this.rowData.beforeFirst();
        this.thisRow = null;
    }

    /**
     * JDBC 2.0 The cancelRowUpdates() method may be called after calling an
     * updateXXX() method(s) and before calling updateRow() to rollback the
     * updates made to a row.  If no updates have been made or updateRow() has
     * already been called, then this method has no effect.
     *
     * @exception SQLException if a database-access error occurs, or if called
     *            when on the insert row.
     * @throws NotUpdatable DOCUMENT ME!
     */
02652     public void cancelRowUpdates() throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * After this call, getWarnings returns null until a new warning is
     * reported for this ResultSet
     *
     * @exception SQLException if a database access error occurs
     */
02662     public void clearWarnings() throws SQLException {
        this.warningChain = null;
    }

    /**
     * In some cases, it is desirable to immediately release a ResultSet
     * database and JDBC resources instead of waiting for this to happen when
     * it is automatically closed.  The close method provides this immediate
     * release.
     *
     * <p>
     * <B>Note:</B> A ResultSet is automatically closed by the Statement the
     * Statement that generated it when that Statement is closed, re-executed,
     * or is used to retrieve the next result from a sequence of multiple
     * results.  A ResultSet is also automatically closed when it is garbage
     * collected.
     * </p>
     *
     * @exception SQLException if a database access error occurs
     */
02682     public void close() throws SQLException {
        realClose(true);
    }

    /**
     * JDBC 2.0 Delete the current row from the result set and the underlying
     * database.  Cannot be called when on the insert row.
     *
     * @exception SQLException if a database-access error occurs, or if called
     *            when on the insert row.
     * @throws NotUpdatable DOCUMENT ME!
     */
02694     public void deleteRow() throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * Map a ResultSet column name to a ResultSet column index
     *
     * @param columnName the name of the column
     *
     * @return the column index
     *
     * @exception SQLException if a database access error occurs
     */
02707     public synchronized int findColumn(String columnName)
        throws SQLException {
        Integer index;

        if (!this.hasBuiltIndexMapping) {
            buildIndexMapping();
        }

        index = (Integer) this.columnNameToIndex.get(columnName);

        if (index == null) {
            index = (Integer) this.fullColumnNameToIndex.get(columnName);
        }

        if (index != null) {
            return index.intValue() + 1;
        }

        // Try this inefficient way, now
     
        for (int i = 0; i < this.fields.length; i++) {
            if (this.fields[i].getName().equalsIgnoreCase(columnName)) {
                return i + 1;
            } else if (this.fields[i].getFullName().equalsIgnoreCase(columnName)) {
                return i + 1;
            }
        }

        throw new SQLException(Messages.getString("ResultSet.Column____112") +
            columnName + Messages.getString("ResultSet.___not_found._113"), //$NON-NLS-1$ //$NON-NLS-2$
            SQLError.SQL_STATE_COLUMN_NOT_FOUND);
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Moves to the first row in the result set.
     * </p>
     *
     * @return true if on a valid row, false if no rows in the result set.
     *
     * @exception SQLException if a database-access error occurs, or result set
     *            type is TYPE_FORWARD_ONLY.
     */
02752     public boolean first() throws SQLException {
        checkClosed();

        if (this.rowData.isEmpty()) {
            return false;
        }
        
        if (this.onInsertRow) {
            this.onInsertRow = false;
        }

        if (this.doingUpdates) {
            this.doingUpdates = false;
        }
        
        this.rowData.beforeFirst();
        this.thisRow = this.rowData.next();

        return true;
    }

    /**
     * JDBC 2.0 Insert the contents of the insert row into the result set and
     * the database.  Must be on the insert row when this method is called.
     *
     * @exception SQLException if a database-access error occurs, if called
     *            when not on the insert row, or if all non-nullable columns
     *            in the insert row have not been given a value
     * @throws NotUpdatable DOCUMENT ME!
     */
02782     public void insertRow() throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Moves to the last row in the result set.
     * </p>
     *
     * @return true if on a valid row, false if no rows in the result set.
     *
     * @exception SQLException if a database-access error occurs, or result set
     *            type is TYPE_FORWARD_ONLY.
     */
02798     public boolean last() throws SQLException {
        checkClosed();

        if (this.rowData.size() == 0) {
            return false;
        }

        if (this.onInsertRow) {
            this.onInsertRow = false;
        }

        if (this.doingUpdates) {
            this.doingUpdates = false;
        }

        this.rowData.beforeLast();
        this.thisRow = this.rowData.next();

        return true;
    }

    /**
     * JDBC 2.0 Move the cursor to the remembered cursor position, usually the
     * current row.  Has no effect unless the cursor is on the insert row.
     *
     * @exception SQLException if a database-access error occurs, or the result
     *            set is not updatable
     * @throws NotUpdatable DOCUMENT ME!
     */
02827     public void moveToCurrentRow() throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Move to the insert row.  The current cursor position is
     * remembered while the cursor is positioned on the insert row. The insert
     * row is a special row associated with an updatable result set.  It is
     * essentially a buffer where a new row may be constructed by calling the
     * updateXXX() methods prior to inserting the row into the result set.
     * Only the updateXXX(), getXXX(), and insertRow() methods may be called
     * when the cursor is on the insert row.  All of the columns in a result
     * set must be given a value each time this method is called before
     * calling insertRow().  UpdateXXX()must be called before getXXX() on a
     * column.
     *
     * @exception SQLException if a database-access error occurs, or the result
     *            set is not updatable
     * @throws NotUpdatable DOCUMENT ME!
     */
02847     public void moveToInsertRow() throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * A ResultSet is initially positioned before its first row, the first call
     * to next makes the first row the current row; the second call makes the
     * second row the current row, etc.
     *
     * <p>
     * If an input stream from the previous row is open, it is implicitly
     * closed.  The ResultSet's warning chain is cleared when a new row is
     * read
     * </p>
     *
     * @return true if the new current is valid; false if there are no more
     *         rows
     *
     * @exception SQLException if a database access error occurs
     */
02867     public boolean next() throws SQLException {
        checkClosed();

        if (this.onInsertRow) {
            this.onInsertRow = false;
        }

        if (this.doingUpdates) {
            this.doingUpdates = false;
        }

        boolean b;

        if (!reallyResult()) {
            throw new SQLException(Messages.getString(
                    "ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
                SQLError.SQL_STATE_GENERAL_ERROR); //$NON-NLS-1$
        }

        if (this.rowData.size() == 0) {
            b = false;
        } else {
            if (!this.rowData.hasNext()) {
                // force scroll past end
                this.rowData.next();
                b = false;
            } else {
                clearWarnings();
                this.thisRow = this.rowData.next();
                b = true;
            }
        }

        return b;
    }

    /**
     * The prev method is not part of JDBC, but because of the architecture of
     * this driver it is possible to move both forward and backward within the
     * result set.
     *
     * <p>
     * If an input stream from the previous row is open, it is implicitly
     * closed.  The ResultSet's warning chain is cleared when a new row is
     * read
     * </p>
     *
     * @return true if the new current is valid; false if there are no more
     *         rows
     *
     * @exception java.sql.SQLException if a database access error occurs
     */
02919     public boolean prev() throws java.sql.SQLException {
        checkClosed();

        int rowIndex = this.rowData.getCurrentRowNumber();

        if ((rowIndex - 1) >= 0) {
            rowIndex--;
            this.rowData.setCurrentRow(rowIndex);
            this.thisRow = this.rowData.getAt(rowIndex);

            return true;
        } else if ((rowIndex - 1) == -1) {
            rowIndex--;
            this.rowData.setCurrentRow(rowIndex);
            this.thisRow = null;

            return false;
        } else {
            return false;
        }
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Moves to the previous row in the result set.
     * </p>
     *
     * <p>
     * Note: previous() is not the same as relative(-1) since it makes sense to
     * call previous() when there is no current row.
     * </p>
     *
     * @return true if on a valid row, false if off the result set.
     *
     * @exception SQLException if a database-access error occurs, or result set
     *            type is TYPE_FORWAR_DONLY.
     */
02958     public boolean previous() throws SQLException {
        if (this.onInsertRow) {
            this.onInsertRow = false;
        }

        if (this.doingUpdates) {
            this.doingUpdates = false;
        }

        return prev();
    }

    /**
     * JDBC 2.0 Refresh the value of the current row with its current value in
     * the database.  Cannot be called when on the insert row. The
     * refreshRow() method provides a way for an application to explicitly
     * tell the JDBC driver to refetch a row(s) from the database.  An
     * application may want to call refreshRow() when caching or prefetching
     * is being done by the JDBC driver to fetch the latest value of a row
     * from the database.  The JDBC driver may actually refresh multiple rows
     * at once if the fetch size is greater than one. All values are refetched
     * subject to the transaction isolation level and cursor sensitivity.  If
     * refreshRow() is called after calling updateXXX(), but before calling
     * updateRow() then the updates made to the row are lost.  Calling
     * refreshRow() frequently will likely slow performance.
     *
     * @exception SQLException if a database-access error occurs, or if called
     *            when on the insert row.
     * @throws NotUpdatable DOCUMENT ME!
     */
02988     public void refreshRow() throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0
     *
     * <p>
     * Moves a relative number of rows, either positive or negative. Attempting
     * to move beyond the first/last row in the result set positions the
     * cursor before/after the the first/last row. Calling relative(0) is
     * valid, but does not change the cursor position.
     * </p>
     *
     * <p>
     * Note: Calling relative(1) is different than calling next() since is
     * makes sense to call next() when there is no current row, for example,
     * when the cursor is positioned before the first row or after the last
     * row of the result set.
     * </p>
     *
     * @param rows the number of relative rows to move the cursor.
     *
     * @return true if on a row, false otherwise.
     *
     * @throws SQLException if a database-access error occurs, or there is no
     *         current row, or result set type is TYPE_FORWARD_ONLY.
     */
03016     public boolean relative(int rows) throws SQLException {
        checkClosed();

        if (this.rowData.size() == 0) {
            return false;
        }

        this.rowData.moveRowRelative(rows);
        this.thisRow = this.rowData.getAt(this.rowData.getCurrentRowNumber());

        return (!this.rowData.isAfterLast() && !this.rowData.isBeforeFirst());
    }

    /**
     * JDBC 2.0 Determine if this row has been deleted.  A deleted row may
     * leave a visible "hole" in a result set.  This method can be used to
     * detect holes in a result set.  The value returned depends on whether or
     * not the result set can detect deletions.
     *
     * @return true if deleted and deletes are detected
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotImplemented DOCUMENT ME!
     *
     * @see DatabaseMetaData#deletesAreDetected
     */
03042     public boolean rowDeleted() throws SQLException {
        throw new NotImplemented();
    }

    /**
     * JDBC 2.0 Determine if the current row has been inserted.  The value
     * returned depends on whether or not the result set can detect visible
     * inserts.
     *
     * @return true if inserted and inserts are detected
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotImplemented DOCUMENT ME!
     *
     * @see DatabaseMetaData#insertsAreDetected
     */
03058     public boolean rowInserted() throws SQLException {
        throw new NotImplemented();
    }

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

    /**
     * JDBC 2.0 Determine if the current row has been updated.  The value
     * returned depends on whether or not the result set can detect updates.
     *
     * @return true if the row has been visibly updated by the owner or
     *         another, and updates are detected
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotImplemented DOCUMENT ME!
     *
     * @see DatabaseMetaData#updatesAreDetected
     */
03078     public boolean rowUpdated() throws SQLException {
        throw new NotImplemented();
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
03087     public String toString() {
        if (this.reallyResult) {
            return super.toString();
        }

        return "Result set representing update count of " + this.updateCount;
    }

    /**
     * @see ResultSet#updateArray(int, Array)
     */
03098     public void updateArray(int arg0, Array arg1) throws SQLException {
        throw new NotImplemented();
    }

    /**
     * @see ResultSet#updateArray(String, Array)
     */
03105     public void updateArray(String arg0, Array arg1) throws SQLException {
        throw new NotImplemented();
    }

    /**
     * JDBC 2.0 Update a column with an ascii stream value. The updateXXX()
     * methods are used to update column values in the current row, or the
     * insert row.  The updateXXX() 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 length the length of the stream
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03123     public void updateAsciiStream(int columnIndex, java.io.InputStream x,
        int length) throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with an ascii stream value. The updateXXX()
     * methods are used to update column values in the current row, or the
     * insert row.  The updateXXX() methods do not update the underlying
     * database, instead the updateRow() or insertRow() methods are called to
     * update the database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     * @param length of the stream
     *
     * @exception SQLException if a database-access error occurs
     */
03141     public void updateAsciiStream(String columnName, java.io.InputStream x,
        int length) throws SQLException {
        updateAsciiStream(findColumn(columnName), x, length);
    }

    /**
     * JDBC 2.0 Update a column with a BigDecimal value. The updateXXX()
     * methods are used to update column values in the current row, or the
     * insert row.  The updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03159     public void updateBigDecimal(int columnIndex, BigDecimal x)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a BigDecimal value. The updateXXX()
     * methods are used to update column values in the current row, or the
     * insert row.  The updateXXX() methods do not update the underlying
     * database, instead the updateRow() or insertRow() methods are called to
     * update the database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03176     public void updateBigDecimal(String columnName, BigDecimal x)
        throws SQLException {
        updateBigDecimal(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with a binary stream value. The updateXXX()
     * methods are used to update column values in the current row, or the
     * insert row.  The updateXXX() 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 length the length of the stream
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03195     public void updateBinaryStream(int columnIndex, java.io.InputStream x,
        int length) throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a binary stream value. The updateXXX()
     * methods are used to update column values in the current row, or the
     * insert row.  The updateXXX() methods do not update the underlying
     * database, instead the updateRow() or insertRow() methods are called to
     * update the database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     * @param length of the stream
     *
     * @exception SQLException if a database-access error occurs
     */
03213     public void updateBinaryStream(String columnName, java.io.InputStream x,
        int length) throws SQLException {
        updateBinaryStream(findColumn(columnName), x, length);
    }

    /**
     * @see ResultSet#updateBlob(int, Blob)
     */
03221     public void updateBlob(int arg0, java.sql.Blob arg1)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * @see ResultSet#updateBlob(String, Blob)
     */
03229     public void updateBlob(String arg0, java.sql.Blob arg1)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a boolean value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03247     public void updateBoolean(int columnIndex, boolean x)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a boolean value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() methods do not update the underlying database, instead
     * the updateRow() or insertRow() methods are called to update the
     * database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03264     public void updateBoolean(String columnName, boolean x)
        throws SQLException {
        updateBoolean(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with a byte value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03281     public void updateByte(int columnIndex, byte x) throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a byte value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() methods do not update the underlying database, instead the
     * updateRow() or insertRow() methods are called to update the database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03296     public void updateByte(String columnName, byte x) throws SQLException {
        updateByte(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with a byte array value. The updateXXX()
     * methods are used to update column values in the current row, or the
     * insert row.  The updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03313     public void updateBytes(int columnIndex, byte[] x)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a byte array value. The updateXXX()
     * methods are used to update column values in the current row, or the
     * insert row.  The updateXXX() methods do not update the underlying
     * database, instead the updateRow() or insertRow() methods are called to
     * update the database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03330     public void updateBytes(String columnName, byte[] x)
        throws SQLException {
        updateBytes(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with a character stream value. The updateXXX()
     * methods are used to update column values in the current row, or the
     * insert row.  The updateXXX() 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 length the length of the stream
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03349     public void updateCharacterStream(int columnIndex, java.io.Reader x,
        int length) throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a character stream value. The updateXXX()
     * methods are used to update column values in the current row, or the
     * insert row.  The updateXXX() methods do not update the underlying
     * database, instead the updateRow() or insertRow() methods are called to
     * update the database.
     *
     * @param columnName the name of the column
     * @param reader the stream to update the column with
     * @param length of the stream
     *
     * @throws SQLException if a database-access error occurs
     */
03367     public void updateCharacterStream(String columnName, java.io.Reader reader,
        int length) throws SQLException {
        updateCharacterStream(findColumn(columnName), reader, length);
    }

    /**
     * @see ResultSet#updateClob(int, Clob)
     */
03375     public void updateClob(int arg0, java.sql.Clob arg1)
        throws SQLException {
        throw new NotImplemented();
    }

    /**
     * @see ResultSet#updateClob(String, Clob)
     */
03383     public void updateClob(String columnName, java.sql.Clob clob)
        throws SQLException {
        updateClob(findColumn(columnName), clob);
    }

    /**
     * JDBC 2.0 Update a column with a Date value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03400     public void updateDate(int columnIndex, java.sql.Date x)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a Date value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() methods do not update the underlying database, instead the
     * updateRow() or insertRow() methods are called to update the database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03416     public void updateDate(String columnName, java.sql.Date x)
        throws SQLException {
        updateDate(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with a Double value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03434     public void updateDouble(int columnIndex, double x)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a double value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() methods do not update the underlying database, instead
     * the updateRow() or insertRow() methods are called to update the
     * database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03451     public void updateDouble(String columnName, double x)
        throws SQLException {
        updateDouble(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with a float value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03468     public void updateFloat(int columnIndex, float x) throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a float value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() methods do not update the underlying database, instead the
     * updateRow() or insertRow() methods are called to update the database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03483     public void updateFloat(String columnName, float x)
        throws SQLException {
        updateFloat(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with an integer value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03501     public void updateInt(int columnIndex, int x) throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with an integer value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() methods do not update the underlying database, instead
     * the updateRow() or insertRow() methods are called to update the
     * database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03517     public void updateInt(String columnName, int x) throws SQLException {
        updateInt(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with a long value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03533     public void updateLong(int columnIndex, long x) throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a long value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() methods do not update the underlying database, instead the
     * updateRow() or insertRow() methods are called to update the database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03548     public void updateLong(String columnName, long x) throws SQLException {
        updateLong(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Give a nullable column a null value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() 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, ...
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03564     public void updateNull(int columnIndex) throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a null value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() methods do not update the underlying database, instead the
     * updateRow() or insertRow() methods are called to update the database.
     *
     * @param columnName the name of the column
     *
     * @exception SQLException if a database-access error occurs
     */
03578     public void updateNull(String columnName) throws SQLException {
        updateNull(findColumn(columnName));
    }

    /**
     * JDBC 2.0 Update a column with an Object value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() 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 scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
     *        this is the number of digits after the decimal.  For all other
     *        types this value will be ignored.
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03598     public void updateObject(int columnIndex, Object x, int scale)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with an Object value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03616     public void updateObject(int columnIndex, Object x)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with an Object value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() methods do not update the underlying database, instead
     * the updateRow() or insertRow() methods are called to update the
     * database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
     *        this is the number of digits after the decimal.  For all other
     *        types this value will be ignored.
     *
     * @exception SQLException if a database-access error occurs
     */
03636     public void updateObject(String columnName, Object x, int scale)
        throws SQLException {
        updateObject(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with an Object value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() methods do not update the underlying database, instead
     * the updateRow() or insertRow() methods are called to update the
     * database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03653     public void updateObject(String columnName, Object x)
        throws SQLException {
        updateObject(findColumn(columnName), x);
    }

    /**
     * @see ResultSet#updateRef(int, Ref)
     */
03661     public void updateRef(int arg0, Ref arg1) throws SQLException {
        throw new NotImplemented();
    }

    /**
     * @see ResultSet#updateRef(String, Ref)
     */
03668     public void updateRef(String arg0, Ref arg1) throws SQLException {
        throw new NotImplemented();
    }

    /**
     * JDBC 2.0 Update the underlying database with the new contents of the
     * current row.  Cannot be called when on the insert row.
     *
     * @exception SQLException if a database-access error occurs, or if called
     *            when on the insert row
     * @throws NotUpdatable DOCUMENT ME!
     */
03680     public void updateRow() throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a short value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03696     public void updateShort(int columnIndex, short x) throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a short value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() methods do not update the underlying database, instead the
     * updateRow() or insertRow() methods are called to update the database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03711     public void updateShort(String columnName, short x)
        throws SQLException {
        updateShort(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with a String value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03729     public void updateString(int columnIndex, String x)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a String value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() methods do not update the underlying database, instead
     * the updateRow() or insertRow() methods are called to update the
     * database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03746     public void updateString(String columnName, String x)
        throws SQLException {
        updateString(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with a Time value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03763     public void updateTime(int columnIndex, java.sql.Time x)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a Time value. The updateXXX() methods are
     * used to update column values in the current row, or the insert row. The
     * updateXXX() methods do not update the underlying database, instead the
     * updateRow() or insertRow() methods are called to update the database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03779     public void updateTime(String columnName, java.sql.Time x)
        throws SQLException {
        updateTime(findColumn(columnName), x);
    }

    /**
     * JDBC 2.0 Update a column with a Timestamp value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() 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
     *
     * @exception SQLException if a database-access error occurs
     * @throws NotUpdatable DOCUMENT ME!
     */
03797     public void updateTimestamp(int columnIndex, java.sql.Timestamp x)
        throws SQLException {
        throw new NotUpdatable();
    }

    /**
     * JDBC 2.0 Update a column with a Timestamp value. The updateXXX() methods
     * are used to update column values in the current row, or the insert row.
     * The updateXXX() methods do not update the underlying database, instead
     * the updateRow() or insertRow() methods are called to update the
     * database.
     *
     * @param columnName the name of the column
     * @param x the new column value
     *
     * @exception SQLException if a database-access error occurs
     */
03814     public void updateTimestamp(String columnName, java.sql.Timestamp x)
        throws SQLException {
        updateTimestamp(findColumn(columnName), x);
    }

    /**
     * A column may have the value of SQL NULL; wasNull() reports whether the
     * last column read had this special value.  Note that you must first call
     * getXXX on a column to try to read its value and then call wasNull() to
     * find if the value was SQL NULL
     *
     * @return true if the last column read was SQL NULL
     *
     * @exception SQLException if a database access error occurred
     */
03829     public boolean wasNull() throws SQLException {
        return this.wasNullFlag;
    }

    /**
     * Flag that this result set is 'binary' encoded (from a
     * PreparedStatement), not stored as strings.
     */
03837     protected void setBinaryEncoded() {
        this.isBinaryEncoded = true;
    }
    
    ///////////////////////////////////////////
    //
    // These number conversion routines save
    // a ton of "new()s", especially for the heavily
    // used getInt() and getDouble() methods
    //
    ///////////////////////////////////////////

    /**
     * Converts a string representation of a number to a double. Need a faster
     * way to do this.
     *
     * @param colIndex the 1-based index of the column to retrieve a double
     *        from.
     *
     * @return the double value represented by the string in buf
     *
     * @throws SQLException if an error occurs
     */
03860     protected double getDoubleInternal(int colIndex) throws SQLException {
        return getDoubleInternal(getString(colIndex), colIndex);
    }

    /**
     * Converts a string representation of a number to a double. Need a faster
     * way to do this.
     *
     * @param stringVal the double as a String
     * @param colIndex the 1-based index of the column to retrieve a double
     *        from.
     *
     * @return the double value represented by the string in buf
     *
     * @throws SQLException if an error occurs
     */
03876     protected double getDoubleInternal(String stringVal, int colIndex)
        throws SQLException {
        try {
            if ((stringVal == null) || (stringVal.length() == 0)) {
                return 0;
            }

            double d = Double.parseDouble(stringVal);

            if (this.useStrictFloatingPoint) {
                // Fix endpoint rounding precision loss in MySQL server
                if (d == 2.147483648E9) {
                    // Fix Odd end-point rounding on MySQL
                    d = 2.147483647E9;
                } else if (d == 1.0000000036275E-15) {
                    // Fix odd end-point rounding on MySQL
                    d = 1.0E-15;
                } else if (d == 9.999999869911E14) {
                    d = 9.99999999999999E14;
                } else if (d == 1.4012984643248E-45) {
                    d = 1.4E-45;
                } else if (d == 1.4013E-45) {
                    d = 1.4E-45;
                } else if (d == 3.4028234663853E37) {
                    d = 3.4028235E37;
                } else if (d == -2.14748E9) {
                    d = -2.147483648E9;
                } else if (d == 3.40282E37) {
                    d = 3.4028235E37;
                }
            }

            return d;
        } catch (NumberFormatException e) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Bad_format_for_number",
                    new Object[] { stringVal, new Integer(colIndex) }),
                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
        }
    }

    /**
     * Sets the first character of the query that this result set was created
     * from.
     *
     * @param c the first character of the query...uppercased
     */
03923     protected void setFirstCharOfQuery(char c) {
        this.firstCharOfQuery = c;
    }

    /**
     * Returns the first character of the query that this result set was
     * created from.
     *
     * @return the first character of the query...uppercased
     */
03933     protected char getFirstCharOfQuery() {
        return this.firstCharOfQuery;
    }

    protected Object getObjectStoredProc(String columnName, int desiredSqlType)
        throws SQLException {
        return getObjectStoredProc(findColumn(columnName), desiredSqlType);
    }

    protected Object getObjectStoredProc(String colName, java.util.Map map,
        int desiredSqlType) throws SQLException {
        return getObjectStoredProc(findColumn(colName), map, desiredSqlType);
    }

    protected Object getObjectStoredProc(int i, java.util.Map map,
        int desiredSqlType) throws SQLException {
        return getObjectStoredProc(i, desiredSqlType);
    }

    protected Object getObjectStoredProc(int columnIndex, int desiredSqlType)
        throws SQLException {
        checkRowPos();

        try {
            if (this.thisRow[columnIndex - 1] == null) {
                  this.wasNullFlag = true;

                return null;
            }
        } catch (ArrayIndexOutOfBoundsException aioobEx) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Column_Index_out_of_range",
                    new Object[] {
                        new Integer(columnIndex),
                        new Integer(this.fields.length)
                    }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }

        this.wasNullFlag = false;

        Field field;
        field = this.fields[columnIndex - 1];

        switch (desiredSqlType) {
        case Types.BIT:
            // valueOf would be nicer here, but it isn't
            // present in JDK-1.3.1, which is what the CTS
            // uses.
            return new Boolean(getBoolean(columnIndex));

        case Types.TINYINT:
            return new Integer(getInt(columnIndex));

        case Types.SMALLINT:
            return new Integer(getInt(columnIndex));

        case Types.INTEGER:

            if (field.isUnsigned()) {
                return new Long(getLong(columnIndex));
            }

            return new Integer(getInt(columnIndex));

        case Types.BIGINT:

            if (field.isUnsigned()) {
                return getBigDecimal(columnIndex);
            }

            return new Long(getLong(columnIndex));

        case Types.DECIMAL:
        case Types.NUMERIC:

            String stringVal = getString(columnIndex);
            BigDecimal val;

            if (stringVal != null) {
                if (stringVal.length() == 0) {
                    val = new BigDecimal(0);

                    return val;
                }

                try {
                    val = new BigDecimal(stringVal);
                } catch (NumberFormatException ex) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Bad_format_for_BigDecimal____86") //$NON-NLS-1$
                         +stringVal +
                        Messages.getString("ResultSet.___in_column__87") +
                        columnIndex + "(" //$NON-NLS-1$
                         + this.fields[columnIndex - 1] + ").",
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                }

                return val;
            }

            return null;

        case Types.REAL:
            return new Float(getFloat(columnIndex));

        case Types.FLOAT:
            
            if (!this.connection.getRunningCTS13()) {
                  return new Double(getFloat(columnIndex));
            } else {
                  return new Float(getFloat(columnIndex)); // NB - bug in JDBC compliance test, according
                                                                                     // to JDBC spec, FLOAT type should return DOUBLE
                                                                                     // but causes ClassCastException in CTS :(
            }
        case Types.DOUBLE:
            return new Double(getDouble(columnIndex));

        case Types.CHAR:
        case Types.VARCHAR:
        case Types.LONGVARCHAR:
            return getString(columnIndex);

        case Types.BINARY:
        case Types.VARBINARY:
        case Types.LONGVARBINARY:
            return getBytes(columnIndex);

        case Types.DATE:
            return getDate(columnIndex);

        case Types.TIME:
            return getTime(columnIndex);

        case Types.TIMESTAMP:
            return getTimestamp(columnIndex);

        default:
            return getString(columnIndex);
        }
    }

    /**
     * Checks if columnIndex is within the number of columns in this result
     * set.
     *
     * @param columnIndex the index to check
     *
     * @throws SQLException if the index is out of bounds
     */
04082     protected final void checkColumnBounds(int columnIndex)
        throws SQLException {
        if ((columnIndex < 1) || (columnIndex > this.fields.length)) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Column_Index_out_of_range",
                    new Object[] {
                        new Integer(columnIndex),
                        new Integer(this.fields.length)
                    }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }

        if (this.profileSql || this.useUsageAdvisor) {
            this.columnUsed[columnIndex - 1] = true;
        }
    }

    //--------------------------JDBC 2.0-----------------------------------
    //---------------------------------------------------------------------
    // Getter's and Setter's
    //---------------------------------------------------------------------

    /**
       * @param string
       * @param mysqlType
       * @param s
       */
04108       private void issueConversionViaParsingWarning(String methodName, int columnIndex, Object value, Field fieldInfo, int[] typesWithNoParseConversion) {
            StringBuffer message = new StringBuffer();
            message.append("ResultSet type conversion via parsing detected when calling ");
            message.append(methodName);
            message.append(" for column ");
            message.append((columnIndex + 1));
            message.append(", (column named '");
            message.append(fieldInfo.getOriginalName());
            message.append("' in table '");
            message.append(fieldInfo.getOriginalTableName());
            if (this.owningStatement != null 
                        && this.owningStatement instanceof com.mysql.jdbc.PreparedStatement) {
            message.append("' created from query:\n\n");
            message.append(((com.mysql.jdbc.PreparedStatement)this.owningStatement).originalSql);
            message.append("\n\n");
            } else {
                  message.append(". ");
            }
            
            message.append("Java of column type is '");
            message.append(value.getClass().getName());
            message.append("', MySQL field type is ");
            message.append(MysqlDefs.typeToName(fieldInfo.getMysqlType()));
            message.append(".\n\nTypes that could be converted directly without parsing are:\n");
            
            for (int i = 0; i < typesWithNoParseConversion.length; i++) {
                  message.append(MysqlDefs.typeToName(typesWithNoParseConversion[i]));
                  message.append("\n");
            }
            
            this.eventSink.consumeEvent(new ProfilerEvent(
        ProfilerEvent.TYPE_WARN, "",
        (this.owningStatement == null) ? "N/A"
                                       : this.owningStatement.currentCatalog,
        this.connection.getId(),
        (this.owningStatement == null) ? (-1)
                                       : this.owningStatement.getId(),
        this.resultId, System.currentTimeMillis(), 0, null,
        this.pointOfOrigin, message.toString()));
            
      }

      /**
       * @param columnIndex
       * @param stringVal
       * @param mysqlType
       * @return
       * @throws SQLException
       */
04157       private String extractStringFromNativeColumn(int columnIndex, int mysqlType) throws SQLException {
            if (this.thisRow[columnIndex - 1] instanceof String) {
                return (String) this.thisRow[columnIndex - 1];
            }

            String stringVal = null;
            
            if ((this.connection != null) && this.connection.getUseUnicode()) {
                try {
                    String encoding = this.fields[columnIndex - 1].getCharacterSet();

                    if (encoding == null) {
                        stringVal = new String((byte[]) this.thisRow[columnIndex -
                                1]);
                    } else {
                        SingleByteCharsetConverter converter = this.connection.getCharsetConverter(encoding);

                        if (converter != null) {
                            stringVal = converter.toString((byte[]) this.thisRow[columnIndex -
                                    1]);
                        } else {
                            stringVal = new String((byte[]) this.thisRow[columnIndex -
                                    1], encoding);
                        }
                    }
                } catch (java.io.UnsupportedEncodingException E) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Unsupported_character_encoding____138") //$NON-NLS-1$
                         + this.connection.getEncoding() + "'.", "0S100");
                }
            } else {
                stringVal = StringUtils.toAsciiString((byte[]) this.thisRow[columnIndex -
                        1]);
            }

            // Cache this conversion if the type is a MySQL string type
            if ((mysqlType == MysqlDefs.FIELD_TYPE_STRING) ||
                    (mysqlType == MysqlDefs.FIELD_TYPE_VAR_STRING) ||
                        (mysqlType == MysqlDefs.FIELD_TYPE_VARCHAR)) {
                this.thisRow[columnIndex - 1] = stringVal;
            }

            return stringVal;
      }

      /**
     * Converts the given value as a java long, to an 'unsigned' long,
     * using the java.math.BigInteger class.
     */
04206     protected static BigInteger convertLongToUlong(long longVal) {
        byte[] asBytes = new byte[8];
        asBytes[7] = (byte) (longVal & 0xff);
        asBytes[6] = (byte) (longVal >>> 8);
        asBytes[5] = (byte) (longVal >>> 16);
        asBytes[4] = (byte) (longVal >>> 24);
        asBytes[3] = (byte) (longVal >>> 32);
        asBytes[2] = (byte) (longVal >>> 40);
        asBytes[1] = (byte) (longVal >>> 48);
        asBytes[0] = (byte) (longVal >>> 56);

        return new BigInteger(1, asBytes);
    }

    /**
     * DOCUMENT ME!
     *
     * @param nextResultSet Sets the next result set in the result set chain
     *        for multiple result sets.
     */
04226     protected void setNextResultSet(ResultSet nextResultSet) {
        this.nextResultSet = nextResultSet;
    }

    /**
     * DOCUMENT ME!
     *
     * @return Returns the nextResultSet, if any, null if none exists.
     */
04235     protected ResultSet getNextResultSet() {
        return this.nextResultSet;
    }

    /**
     * Sets the concurrency (JDBC2)
     *
     * @param concurrencyFlag CONCUR_UPDATABLE or CONCUR_READONLY
     */
04244     protected void setResultSetConcurrency(int concurrencyFlag) {
      this.resultSetConcurrency = concurrencyFlag;
    }

    /**
     * Sets the result set type for (JDBC2)
     *
     * @param typeFlag SCROLL_SENSITIVE or SCROLL_INSENSITIVE (we only support
     *        SCROLL_INSENSITIVE)
     */
04254     protected void setResultSetType(int typeFlag) {
      this.resultSetType = typeFlag;
    }

    /**
     * Sets server info (if any)
     *
     * @param info the server info message
     */
04263     protected void setServerInfo(String info) {
        this.serverInfo = info;
    }

    /**
     * Returns the server info (if any), or null if none.
     *
     * @return server info created for this ResultSet
     */
04272     protected String getServerInfo() {
        return this.serverInfo;
    }

    /**
     * Builds a hash between column names and their indices for fast retrieval.
     */
04279     protected void buildIndexMapping() {
        int numFields = this.fields.length;
        this.columnNameToIndex = new HashMap(numFields);
        this.fullColumnNameToIndex = new HashMap(numFields);

        //        We do this in reverse order, so that the 'first' column
        // with a given name ends up as the final mapping in the
        // hashtable...
        //
        // Quoting the JDBC Spec:
        //
        // "Column names used as input to getter
        // methods are case insensitive. When a getter method is called with a column
        // name and several columns have the same name, the value of the first
        // matching column will be returned. "
        //
        for (int i = numFields - 1; i >= 0; i--) {
            Integer index = new Integer(i);
            String columnName = this.fields[i].getName();
            String fullColumnName = this.fields[i].getFullName();

            if (columnName != null) {
                  this.columnNameToIndex.put(columnName, index);
                  this.columnNameToIndex.put(columnName.toUpperCase(), index);
                  this.columnNameToIndex.put(columnName.toLowerCase(), index);
            }

            if (fullColumnName != null) {
                  this.fullColumnNameToIndex.put(fullColumnName, index);
                  this.fullColumnNameToIndex.put(fullColumnName.toUpperCase(), index);
                  this.fullColumnNameToIndex.put(fullColumnName.toLowerCase(), index);
            }
        }

        // set the flag to prevent rebuilding...
        this.hasBuiltIndexMapping = true;
    }

    /**
     * Ensures that the result set is not closed
     *
     * @throws SQLException if the result set is closed
     */
04322     protected final synchronized void checkClosed() throws SQLException {
        if (this.isClosed) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Operation_not_allowed_after_ResultSet_closed_144"), //$NON-NLS-1$
                SQLError.SQL_STATE_GENERAL_ERROR);
        }
    }

    /**
     * Ensures that the cursor is positioned on a valid row and that the result
     * set is not closed
     *
     * @throws SQLException if the result set is not in a valid state for
     *         traversal
     */
04337     protected void checkRowPos() throws SQLException {
        checkClosed();

        if (!this.rowData.isDynamic() && (this.rowData.size() == 0)) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Illegal_operation_on_empty_result_set"),
                SQLError.SQL_STATE_GENERAL_ERROR);
        }

        if (this.rowData.isBeforeFirst()) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Before_start_of_result_set_146"),
                SQLError.SQL_STATE_GENERAL_ERROR); //$NON-NLS-1$
        }

        if (this.rowData.isAfterLast()) {
            throw new SQLException(Messages.getString(
                    "ResultSet.After_end_of_result_set_148"),
                SQLError.SQL_STATE_GENERAL_ERROR); //$NON-NLS-1$
        }
    }

    //
    // Note, row data is linked between these two result sets
    //
    protected final ResultSet copy() throws SQLException {
        ResultSet rs = new ResultSet(this.catalog, this.fields, this.rowData,
                this.connection, this.owningStatement);

        return rs;
    }

    /**
     * Closes this ResultSet and releases resources.
     *
     * @param calledExplicitly was this called by close()?
     *
     * @throws SQLException if an error occurs
     */
04376     protected void realClose(boolean calledExplicitly)
        throws SQLException {
        try {
            if (this.useUsageAdvisor && !this.isClosed) {
                if (!calledExplicitly) {
                    String message = Messages.getString(
                            "ResultSet.ResultSet_implicitly_closed_by_driver._150") //$NON-NLS-1$
                         +Messages.getString(
                            "ResultSet._n_nYou_should_close_ResultSets_explicitly_from_your_code_to_free_up_resources_in_a_more_efficient_manner._151"); //$NON-NLS-1$

                    this.eventSink.consumeEvent(new ProfilerEvent(
                            ProfilerEvent.TYPE_WARN, "",
                            (this.owningStatement == null) ? "N/A"
                                                           : this.owningStatement.currentCatalog,
                            this.connection.getId(),
                            (this.owningStatement == null) ? (-1)
                                                           : this.owningStatement.getId(),
                            this.resultId, System.currentTimeMillis(), 0, null,
                            this.pointOfOrigin, message));
                }

                if (this.rowData instanceof RowDataStatic && !isLast() &&
                        !isAfterLast() && (this.rowData.size() != 0)) {
                    StringBuffer messageBuf = new StringBuffer(Messages.getString(
                                "ResultSet.Possible_incomplete_traversal_of_result_set._Cursor_was_left_on_row__154")); //$NON-NLS-1$
                    messageBuf.append(getRow());
                    messageBuf.append(Messages.getString("ResultSet._of__155")); //$NON-NLS-1$
                    messageBuf.append(this.rowData.size());
                    messageBuf.append(Messages.getString(
                            "ResultSet._rows_when_it_was_closed._156")); //$NON-NLS-1$
                    messageBuf.append(Messages.getString(
                            "ResultSet._n_nYou_should_consider_re-formulating_your_query_to_return_only_the_rows_you_are_interested_in_using._157")); //$NON-NLS-1$

                    this.eventSink.consumeEvent(new ProfilerEvent(
                            ProfilerEvent.TYPE_WARN, "",
                            (this.owningStatement == null)
                            ? Messages.getString("ResultSet.N/A_159")
                            : this.owningStatement.currentCatalog, //$NON-NLS-1$
                            this.connection.getId(),
                            (this.owningStatement == null) ? (-1)
                                                           : this.owningStatement.getId(),
                            this.resultId, System.currentTimeMillis(), 0, null,
                            this.pointOfOrigin, messageBuf.toString()));
                }

                //
                // Report on any columns that were selected but
                // not referenced
                //
                if (this.columnUsed.length > 0) {
                    StringBuffer buf = new StringBuffer(Messages.getString(
                                "ResultSet.The_following_columns_were__160")); //$NON-NLS-1$
                    buf.append(Messages.getString(
                            "ResultSet._part_of_the_SELECT_statement_for_this_result_set,_but_were_161")); //$NON-NLS-1$
                    buf.append(Messages.getString(
                            "ResultSet._never_referenced___162")); //$NON-NLS-1$

                    boolean issueWarn = false;

                    for (int i = 0; i < this.columnUsed.length; i++) {
                        if (!this.columnUsed[i]) {
                            if (!issueWarn) {
                                issueWarn = true;
                            } else {
                                buf.append(", ");
                            }

                            buf.append(this.fields[i].getFullName());
                        }
                    }

                    if (issueWarn) {
                        this.eventSink.consumeEvent(new ProfilerEvent(
                                ProfilerEvent.TYPE_WARN, "",
                                (this.owningStatement == null) ? "N/A"
                                                               : this.owningStatement.currentCatalog,
                                this.connection.getId(),
                                (this.owningStatement == null) ? (-1)
                                                               : this.owningStatement.getId(),
                                0, System.currentTimeMillis(), 0, null,
                                this.pointOfOrigin, buf.toString()));
                    }
                }
            }
        } finally {
            SQLException exceptionDuringClose = null;

            if (this.rowData != null) {
                try {
                    this.rowData.close();
                } catch (SQLException sqlEx) {
                    exceptionDuringClose = sqlEx;
                }
            }

            this.rowData = null;
            this.defaultTimeZone = null;
            this.fields = null;
            this.columnNameToIndex = null;
            this.fullColumnNameToIndex = null;
            this.eventSink = null;
            this.nextResultSet = null;
            this.warningChain = null;
            this.owningStatement = null;
            this.catalog = null;
            this.serverInfo = null;
            this.thisRow = null;
            this.fastDateCal = null;
            
            this.isClosed = true;
            
            if (exceptionDuringClose != null) {
                throw exceptionDuringClose;
            }
        }
    }

    long getUpdateCount() {
        return this.updateCount;
    }

    long getUpdateID() {
        return this.updateId;
    }

    boolean reallyResult() {
        if (this.rowData != null) {
            return true;
        }

        return this.reallyResult;
    }

    private final BigDecimal getBigDecimalFromString(String stringVal,
        int columnIndex, int scale) throws SQLException {
        BigDecimal bdVal;

        if (stringVal != null) {
            if (stringVal.length() == 0) {
                bdVal = new BigDecimal(0);

                return bdVal;
            }

            try {
                  try {
                        return new BigDecimal(stringVal).setScale(scale);
                  } catch (ArithmeticException ex) {
                        try {
                              return new BigDecimal(stringVal).setScale(scale, BigDecimal.ROUND_HALF_UP);
                        } catch (ArithmeticException arEx) {
                              throw new SQLException(Messages.getString(
                        "ResultSet.Bad_format_for_BigDecimal____166") //$NON-NLS-1$
                        +stringVal +
                        Messages.getString("ResultSet.___in_column__167") +
                        columnIndex + "(" //$NON-NLS-1$
                        + this.fields[columnIndex - 1] + ").",
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                        }
                  }
            } catch (NumberFormatException ex) {
                throw new SQLException(Messages.getString(
                        "ResultSet.Bad_format_for_BigDecimal____166") //$NON-NLS-1$
                     +stringVal +
                    Messages.getString("ResultSet.___in_column__167") +
                    columnIndex + "(" //$NON-NLS-1$
                     + this.fields[columnIndex - 1] + ").",
                    SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
            }
        }

        return null;
    }

    private final boolean getBooleanFromString(String stringVal, int columnIndex)
        throws SQLException {
        if ((stringVal != null) && (stringVal.length() > 0)) {
            int c = Character.toLowerCase(stringVal.charAt(0));

            return ((c == 't') || (c == 'y') || (c == '1') ||
            stringVal.equals("-1"));
        }

        return false;
    }

    private final byte getByteFromString(String stringVal, int columnIndex)
        throws SQLException {
        try {
            int decimalIndex = stringVal.indexOf(".");

            
            if (decimalIndex != -1) {
                  double valueAsDouble = Double.parseDouble(stringVal);
                  
                  if (this.connection.getJdbcCompliantTruncation()) {
                        if (valueAsDouble < Byte.MIN_VALUE || valueAsDouble > Byte.MAX_VALUE) {
                              throwRangeException(stringVal, columnIndex, Types.TINYINT);
                        }
                  }
                  
                return (byte) valueAsDouble;
            }

            long valueAsLong = Long.parseLong(stringVal);
            
            if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsLong < Byte.MIN_VALUE || valueAsLong > Byte.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsLong), columnIndex, Types.TINYINT);
                  }
            }
            
            return (byte) valueAsLong;
        } catch (NumberFormatException NFE) {
            throw new SQLException(Messages.getString("ResultSet.Value____173") +
                stringVal //$NON-NLS-1$
                 +Messages.getString(
                    "ResultSet.___is_out_of_range_[-127,127]_174"),
                SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }
    }

    private final byte[] getBytesFromString(String stringVal, int columnIndex)
        throws SQLException {
        if (stringVal != null) {
            return StringUtils.getBytes(stringVal,
                this.connection.getEncoding(),
                this.connection.getServerCharacterEncoding(),
                this.connection.parserKnowsUnicode());
        }

        return null;
    }

    private final java.io.Reader getCharacterStreamFromString(
        String stringVal, int columnIndex) throws SQLException {
        if (stringVal != null) {
            return new StringReader(stringVal);
        }

        return null;
    }

    private final java.sql.Clob getClobFromString(String stringVal,
        int columnIndex) throws SQLException {
        return new com.mysql.jdbc.Clob(stringVal);
    }

    private final java.sql.Date getDateFromString(String stringVal,
        int columnIndex) throws SQLException {
        int year = 0;
        int month = 0;
        int day = 0;

        try {
            this.wasNullFlag = false;

            if (stringVal == null) {
                this.wasNullFlag = true;

                return null;
            } else if (stringVal.equals("0000-00-00") ||
                    stringVal.equals("0000-00-00 00:00:00") ||
                    stringVal.equals("00000000000000") ||
                    stringVal.equals("0")) {
                

                if (ConnectionProperties.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL.equals(this.connection.getZeroDateTimeBehavior())) {
                  this.wasNullFlag = true;
                  
                  return null;      
                } else if (ConnectionProperties.ZERO_DATETIME_BEHAVIOR_EXCEPTION.equals(this.connection.getZeroDateTimeBehavior())) {
                  throw new SQLException("Value '" + stringVal + "' can not be represented as java.sql.Date", 
                              SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                }
                
                // We're left with the case of 'round' to a date Java _can_
                // represent, which is '0001-01-01'.
                return fastDateCreate(null, 1, 1, 1);
                
            } else if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_TIMESTAMP) {
                // Convert from TIMESTAMP
                switch (stringVal.length()) {
                case 21:
                case 19: { // java.sql.Timestamp format
                    year = Integer.parseInt(stringVal.substring(0, 4));
                    month = Integer.parseInt(stringVal.substring(5, 7));
                    day = Integer.parseInt(stringVal.substring(8, 10));

                    return fastDateCreate(null, year, month, day);
                }

                case 14:
                case 8: {
                    year = Integer.parseInt(stringVal.substring(0, 4));
                    month = Integer.parseInt(stringVal.substring(4, 6));
                    day = Integer.parseInt(stringVal.substring(6, 8));

                    return fastDateCreate(null, year, month, day);
                }

                case 12:
                case 10:
                case 6: {
                    year = Integer.parseInt(stringVal.substring(0, 2));

                    if (year <= 69) {
                        year = year + 100;
                    }

                    month = Integer.parseInt(stringVal.substring(2, 4));
                    day = Integer.parseInt(stringVal.substring(4, 6));

                    return fastDateCreate(null, year + 1900, month, day);
                }

                case 4: {
                    year = Integer.parseInt(stringVal.substring(0, 4));

                    if (year <= 69) {
                        year = year + 100;
                    }

                    month = Integer.parseInt(stringVal.substring(2, 4));

                    return fastDateCreate(null, year + 1900, month, 1);
                }

                case 2: {
                    year = Integer.parseInt(stringVal.substring(0, 2));

                    if (year <= 69) {
                        year = year + 100;
                    }

                    return fastDateCreate(null, year + 1900, 1, 1);
                }

                default:
                    throw new SQLException(Messages.getString(
                            "ResultSet.Bad_format_for_Date",
                            new Object[] { stringVal, new Integer(columnIndex) }),
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
                } /* endswitch */
            } else if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR) {
                year = Integer.parseInt(stringVal.substring(0, 4));

                return fastDateCreate(null, year, 1, 1);
            } else {
                if (stringVal.length() < 10) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Bad_format_for_Date",
                            new Object[] { stringVal, new Integer(columnIndex) }),
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
                }

                year = Integer.parseInt(stringVal.substring(0, 4));
                month = Integer.parseInt(stringVal.substring(5, 7));
                day = Integer.parseInt(stringVal.substring(8, 10));
            }

            return fastDateCreate(null, year, month, day);
        } catch (SQLException sqlEx) {
            throw sqlEx; // don't re-wrap
        } catch (Exception e) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Bad_format_for_Date",
                    new Object[] { stringVal, new Integer(columnIndex) }),
                SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }
    }

    private final double getDoubleFromString(String stringVal, int columnIndex)
        throws SQLException {
        return getDoubleInternal(stringVal, columnIndex);
    }

    private final float getFloatFromString(String val, int columnIndex)
        throws SQLException {
        try {
            if ((val != null) && (val.length() != 0)) {
                  float f = Float.parseFloat(val);
                  
                  if (this.connection.getJdbcCompliantTruncation()) {
                        if (f == Float.MIN_VALUE || f == Float.MAX_VALUE) {
                              double valAsDouble = Double.parseDouble(val);
                              
                              if (valAsDouble < Float.MIN_VALUE || 
                                          valAsDouble > Float.MAX_VALUE) {
                                    throwRangeException(String.valueOf(valAsDouble), columnIndex, Types.FLOAT);
                              }
                        }
                  }
                  
                  return f;
            }
     
            return 0;
        } catch (NumberFormatException nfe) {
            try {
                double valAsDouble = Double.parseDouble(val);
                
                if (this.connection.getJdbcCompliantTruncation()) {
                  if (valAsDouble < Float.MIN_VALUE || 
                              valAsDouble > Float.MAX_VALUE) {
                        throwRangeException(String.valueOf(valAsDouble), columnIndex, Types.FLOAT);
                  }
                }
                
            
                return (float) valAsDouble;
            } catch (NumberFormatException newNfe) {
                ; // ignore, it's not a number
            }

            throw new SQLException(Messages.getString(
                    "ResultSet.Invalid_value_for_getFloat()_-____200") +
                val //$NON-NLS-1$
                 +Messages.getString("ResultSet.___in_column__201") +
                columnIndex, SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }
    }

    private final int getIntFromString(String val, int columnIndex)
        throws SQLException {
        try {
            if ((val != null) && (val.length() != 0)) {
                if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1) &&
                        (val.indexOf(".") == -1)) {
                  int valueAsInt = Integer.parseInt(val);
                  
                  if (this.connection.getJdbcCompliantTruncation()) {
                        if (valueAsInt == Integer.MIN_VALUE || valueAsInt == Integer.MAX_VALUE) {
                              long valueAsLong = Long.parseLong(val);
                              
                              if (valueAsLong < Integer.MIN_VALUE || valueAsLong > Integer.MAX_VALUE) {
                                    throwRangeException(String.valueOf(valueAsLong), columnIndex, Types.INTEGER);
                              }
                        }
                  }
                  
                    return valueAsInt;
                }

                // Convert floating point
                
                double valueAsDouble = Double.parseDouble(val);
                
                if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsDouble), columnIndex, Types.INTEGER);
                        }
                }
                
                
                return (int) valueAsDouble;
            }

            return 0;
        } catch (NumberFormatException nfe) {
            try {
                  double valueAsDouble = Double.parseDouble(val);
                
                if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsDouble), columnIndex, Types.INTEGER);
                        }
                }
                
                
                return (int) valueAsDouble;
            } catch (NumberFormatException newNfe) {
                ; // ignore, it's not a number
            }

            throw new SQLException(Messages.getString(
                    "ResultSet.Invalid_value_for_getInt()_-____206") +
                val //$NON-NLS-1$
                 +Messages.getString("ResultSet.___in_column__207") +
                columnIndex, SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }
    }

    private final long getLongFromString(String val, int columnIndex)
        throws SQLException {
        try {
            if ((val != null) && (val.length() != 0)) {
                if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1)) {
                    return parseLongWithOverflowCheck(columnIndex, null, val);
                }

                // Convert floating point
                return parseLongAsDouble(columnIndex, val);
            }

            return 0;
        } catch (NumberFormatException nfe) {
            try {
                // To do: Warn of over/underflow???
                return parseLongAsDouble(columnIndex, val);
            } catch (NumberFormatException newNfe) {
                ; // ignore, it's not a number
            }

            throw new SQLException(Messages.getString(
                    "ResultSet.Invalid_value_for_getLong()_-____211") +
                val //$NON-NLS-1$
                 +Messages.getString("ResultSet.___in_column__212") +
                columnIndex, SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }
    }

    private void setDefaultTimeZone(TimeZone defaultTimeZone) {
        this.defaultTimeZone = defaultTimeZone;
    }

    private synchronized TimeZone getDefaultTimeZone() {
        if (this.defaultTimeZone == null) {
            this.defaultTimeZone = TimeZone.getDefault();
        }

        return this.defaultTimeZone;
    }

    private final short getShortFromString(String val, int columnIndex)
        throws SQLException {
        try {
            if ((val != null) && (val.length() != 0)) {
                if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1) &&
                        (val.indexOf(".") == -1)) {
                    return parseShortWithOverflowCheck(columnIndex, null, val);
                }

                // Convert floating point
                return parseShortAsDouble(columnIndex, val);
            }

            return 0;
        } catch (NumberFormatException nfe) {
            try {
                return parseShortAsDouble(columnIndex, val);
            } catch (NumberFormatException newNfe) {
                ; // ignore, it's not a number
            }

            throw new SQLException(Messages.getString(
                    "ResultSet.Invalid_value_for_getShort()_-____217") +
                val //$NON-NLS-1$
                 +Messages.getString("ResultSet.___in_column__218") +
                columnIndex, SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }
    }

    private Time getTimeFromString(String timeAsString, int columnIndex,
        TimeZone tz, boolean rollForward) throws SQLException {
        int hr = 0;
        int min = 0;
        int sec = 0;

        try {
            if (timeAsString == null) {
                this.wasNullFlag = true;

                return null;
            } else if (timeAsString.equals("0000-00-00") ||
                    timeAsString.equals("0000-00-00 00:00:00") ||
                    timeAsString.equals("00000000000000")) {
                  if (ConnectionProperties.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL.equals(this.connection.getZeroDateTimeBehavior())) {
                  this.wasNullFlag = true;
                  
                  return null;      
                } else if (ConnectionProperties.ZERO_DATETIME_BEHAVIOR_EXCEPTION.equals(this.connection.getZeroDateTimeBehavior())) {
                  throw new SQLException("Value '" + timeAsString + " can not be represented as java.sql.Time", 
                              SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                }
            }

            this.wasNullFlag = false;

            Field timeColField = this.fields[columnIndex - 1];

            if (timeColField.getMysqlType() == MysqlDefs.FIELD_TYPE_TIMESTAMP) {
                // It's a timestamp
                int length = timeAsString.length();

                switch (length) {
                case 14:
                case 12: {
                    hr = Integer.parseInt(timeAsString.substring(length - 6,
                                length - 4));
                    min = Integer.parseInt(timeAsString.substring(length - 4,
                                length - 2));
                    sec = Integer.parseInt(timeAsString.substring(length - 2,
                                length));
                }

                break;

                case 10: {
                    hr = Integer.parseInt(timeAsString.substring(6, 8));
                    min = Integer.parseInt(timeAsString.substring(8, 10));
                    sec = 0;
                }

                break;

                default:
                    throw new SQLException(Messages.getString(
                            "ResultSet.Timestamp_too_small_to_convert_to_Time_value_in_column__257") //$NON-NLS-1$
                         +columnIndex + "(" + this.fields[columnIndex - 1] + ").",
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                } /* endswitch */

                SQLWarning precisionLost = new SQLWarning(Messages.getString(
                            "ResultSet.Precision_lost_converting_TIMESTAMP_to_Time_with_getTime()_on_column__261") //$NON-NLS-1$
                         +columnIndex + "(" + this.fields[columnIndex - 1] + ").");

                if (this.warningChain == null) {
                  this.warningChain = precisionLost;
                } else {
                  this.warningChain.setNextWarning(precisionLost);
                }
            } else if (timeColField.getMysqlType() == MysqlDefs.FIELD_TYPE_DATETIME) {
                hr = Integer.parseInt(timeAsString.substring(11, 13));
                min = Integer.parseInt(timeAsString.substring(14, 16));
                sec = Integer.parseInt(timeAsString.substring(17, 19));

                SQLWarning precisionLost = new SQLWarning(Messages.getString(
                            "ResultSet.Precision_lost_converting_DATETIME_to_Time_with_getTime()_on_column__264") //$NON-NLS-1$
                         +columnIndex + "(" + this.fields[columnIndex - 1] + ").");

                if (this.warningChain == null) {
                  this.warningChain = precisionLost;
                } else {
                  this.warningChain.setNextWarning(precisionLost);
                }
            } else {
                // convert a String to a Time
                if ((timeAsString.length() != 5) &&
                        (timeAsString.length() != 8)) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Bad_format_for_Time____267") //$NON-NLS-1$
                         +timeAsString +
                        Messages.getString("ResultSet.___in_column__268") +
                        columnIndex + "(" //$NON-NLS-1$
                         + this.fields[columnIndex - 1] + ").",
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                }

                hr = Integer.parseInt(timeAsString.substring(0, 2));
                min = Integer.parseInt(timeAsString.substring(3, 5));
                sec = (timeAsString.length() == 5) ? 0
                                                   : Integer.parseInt(timeAsString.substring(
                            6));
            }

            return TimeUtil.changeTimezone(this.connection,
                fastTimeCreate(null, hr, min, sec),
                this.connection.getServerTimezoneTZ(), tz, rollForward);
        } catch (Exception ex) {
            throw new SQLException(ex.getClass().getName(),
                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
        }
    }

    /**
     * Get the value of a column in the current row as a java.sql.Time object
     * in the given timezone
     *
     * @param columnIndex the first column is 1, the second is 2...
     * @param tz the Timezone to use
     *
     * @return the column value; null if SQL NULL
     *
     * @exception java.sql.SQLException if a database access error occurs
     */
05052     private Time getTimeInternal(int columnIndex, TimeZone tz, boolean rollForward)
        throws java.sql.SQLException {
        if (this.isBinaryEncoded) {
            return getNativeTime(columnIndex, tz, rollForward);
        }

        String timeAsString = getStringInternal(columnIndex, false);

        return getTimeFromString(timeAsString, columnIndex, tz, rollForward);
    }

    private Timestamp getTimestampFromString(int columnIndex,
        String timestampValue, TimeZone tz, boolean rollForward) throws java.sql.SQLException {
        try {
            this.wasNullFlag = false;

            if (timestampValue == null) {
                this.wasNullFlag = true;

                return null;
            }

            int length = timestampValue.length();

            if ((length > 0) && (timestampValue.charAt(0) == '0') &&
                    (timestampValue.equals("0000-00-00") ||
                    timestampValue.equals("0000-00-00 00:00:00") ||
                    timestampValue.equals("00000000000000") ||
                    timestampValue.equals("0"))) {
               
                if (ConnectionProperties.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL.equals(this.connection.getZeroDateTimeBehavior())) {
                  this.wasNullFlag = true;
                   
                  return null;
                } else if (ConnectionProperties.ZERO_DATETIME_BEHAVIOR_EXCEPTION.equals(this.connection.getZeroDateTimeBehavior())) {
                  throw new SQLException("Value '" + timestampValue + " can not be represented as java.sql.Timestamp", 
                              SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                }
                
                // We're left with the case of 'round' to a date Java _can_
                // represent, which is '0001-01-01'.
                return fastTimestampCreate(null, 1, 1, 1, 0, 0, 0, 0);
                
            } else if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR) {
                return TimeUtil.changeTimezone(this.connection,
                    fastTimestampCreate(null,
                        Integer.parseInt(timestampValue.substring(0, 4)), 1, 1,
                        0, 0, 0, 0), this.connection.getServerTimezoneTZ(), tz, rollForward);
            } else {
                  if (timestampValue.endsWith(".")) {
                        timestampValue = timestampValue.substring(0, timestampValue.length() - 1);    
                  }
                  
                // Convert from TIMESTAMP or DATE
                switch (length) {
                case 26:
                case 25:
                case 24:
                case 23:
                case 22:
                case 21:
                case 20:
                case 19: {
                    int year = Integer.parseInt(timestampValue.substring(0, 4));
                    int month = Integer.parseInt(timestampValue.substring(5, 7));
                    int day = Integer.parseInt(timestampValue.substring(8, 10));
                    int hour = Integer.parseInt(timestampValue.substring(11, 13));
                    int minutes = Integer.parseInt(timestampValue.substring(
                                14, 16));
                    int seconds = Integer.parseInt(timestampValue.substring(
                                17, 19));

                    int nanos = 0;

                    if (length > 19) {
                        int decimalIndex = timestampValue.lastIndexOf('.');

                        if (decimalIndex != -1) {
                            if ((decimalIndex + 2) <= timestampValue.length()) {
                                nanos = Integer.parseInt(timestampValue.substring(decimalIndex +
                                            1));
                            } else {
                                throw new IllegalArgumentException(); // re-thrown further down with a 
                                                                      // much better error message
                            }
                        }
                    }

                    return TimeUtil.changeTimezone(this.connection,
                        fastTimestampCreate(null, year, month, day, hour,
                            minutes, seconds, nanos),
                            this.connection.getServerTimezoneTZ(), tz, rollForward);
                }

                case 14: {
                    int year = Integer.parseInt(timestampValue.substring(0, 4));
                    int month = Integer.parseInt(timestampValue.substring(4, 6));
                    int day = Integer.parseInt(timestampValue.substring(6, 8));
                    int hour = Integer.parseInt(timestampValue.substring(8, 10));
                    int minutes = Integer.parseInt(timestampValue.substring(
                                10, 12));
                    int seconds = Integer.parseInt(timestampValue.substring(
                                12, 14));

                    return TimeUtil.changeTimezone(this.connection,
                        fastTimestampCreate(null, year, month, day, hour,
                            minutes, seconds, 0),
                            this.connection.getServerTimezoneTZ(), tz, rollForward);
                }

                case 12: {
                    int year = Integer.parseInt(timestampValue.substring(0, 2));

                    if (year <= 69) {
                        year = (year + 100);
                    }

                    int month = Integer.parseInt(timestampValue.substring(2, 4));
                    int day = Integer.parseInt(timestampValue.substring(4, 6));
                    int hour = Integer.parseInt(timestampValue.substring(6, 8));
                    int minutes = Integer.parseInt(timestampValue.substring(8,
                                10));
                    int seconds = Integer.parseInt(timestampValue.substring(
                                10, 12));

                    return TimeUtil.changeTimezone(this.connection,
                        fastTimestampCreate(null, year + 1900, month, day,
                            hour, minutes, seconds, 0),
                            this.connection.getServerTimezoneTZ(), tz, rollForward);
                }

                case 10: {
                    int year;
                    int month;
                    int day;
                    int hour;
                    int minutes;

                    if ((this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_DATE) ||
                            (timestampValue.indexOf("-") != -1)) {
                        year = Integer.parseInt(timestampValue.substring(0, 4));
                        month = Integer.parseInt(timestampValue.substring(5, 7));
                        day = Integer.parseInt(timestampValue.substring(8, 10));
                        hour = 0;
                        minutes = 0;
                    } else {
                        year = Integer.parseInt(timestampValue.substring(0, 2));

                        if (year <= 69) {
                            year = (year + 100);
                        }

                        month = Integer.parseInt(timestampValue.substring(2, 4));
                        day = Integer.parseInt(timestampValue.substring(4, 6));
                        hour = Integer.parseInt(timestampValue.substring(6, 8));
                        minutes = Integer.parseInt(timestampValue.substring(8,
                                    10));

                        year += 1900; // two-digit year
                    }

                    return TimeUtil.changeTimezone(this.connection,
                        fastTimestampCreate(null, year, month, day, hour,
                            minutes, 0, 0), this.connection.getServerTimezoneTZ(), tz, rollForward);
                }

                case 8: {
                  if (timestampValue.indexOf(":") != -1) {
                        int hour = Integer.parseInt(timestampValue.substring(
                                0, 2));
                        int minutes = Integer.parseInt(timestampValue.substring(
                                3, 5));
                        int seconds = Integer.parseInt(timestampValue.substring(6, 8));

                        return TimeUtil.changeTimezone(this.connection,
                                    fastTimestampCreate(null, 70, 0,
                                                1, hour, minutes, seconds, 0),
                                                this.connection.getServerTimezoneTZ(), tz, rollForward);
                        
                  }
                        
                  int year = Integer.parseInt(timestampValue.substring(
                                0, 4));
                  int month = Integer.parseInt(timestampValue.substring(
                                4, 6));
                  int day = Integer.parseInt(timestampValue.substring(6, 8));

                  return TimeUtil.changeTimezone(this.connection,
                              fastTimestampCreate(null, year - 1900, month - 1,
                                    day, 0, 0, 0, 0),
                                    this.connection.getServerTimezoneTZ(), tz, rollForward);    
                }

                case 6: {
                    int year = Integer.parseInt(timestampValue.substring(0, 2));

                    if (year <= 69) {
                        year = (year + 100);
                    }

                    int month = Integer.parseInt(timestampValue.substring(2, 4));
                    int day = Integer.parseInt(timestampValue.substring(4, 6));

                    return TimeUtil.changeTimezone(this.connection,
                        fastTimestampCreate(null, year + 1900, month, day, 0,
                            0, 0, 0), this.connection.getServerTimezoneTZ(), tz, rollForward);
                }

                case 4: {
                    int year = Integer.parseInt(timestampValue.substring(0, 2));

                    if (year <= 69) {
                        year = (year + 100);
                    }

                    int month = Integer.parseInt(timestampValue.substring(2, 4));

                    return TimeUtil.changeTimezone(this.connection,
                        fastTimestampCreate(null, year + 1900, month, 1, 0, 0,
                            0, 0), this.connection.getServerTimezoneTZ(), tz, rollForward);
                }

                case 2: {
                    int year = Integer.parseInt(timestampValue.substring(0, 2));

                    if (year <= 69) {
                        year = (year + 100);
                    }

                    return TimeUtil.changeTimezone(this.connection,
                        fastTimestampCreate(null, year + 1900, 1, 1, 0, 0, 0, 0),
                        this.connection.getServerTimezoneTZ(), tz, rollForward);
                }

                default:
                    throw new java.sql.SQLException(
                        "Bad format for Timestamp '" + timestampValue +
                        "' in column " + columnIndex + ".",
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                }
            }
        } catch (Exception e) {
            throw new java.sql.SQLException("Cannot convert value '" +
                timestampValue + "' from column " + columnIndex +
                " to TIMESTAMP.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
        }
    }

    /**
     * Get the value of a column in the current row as a java.sql.Timestamp
     * object in the given timezone
     *
     * @param columnIndex the first column is 1, the second is 2...
     * @param tz the timezone to use
     *
     * @return the column value; null if SQL NULL
     *
     * @exception java.sql.SQLException if a database access error occurs
     */
05311     private Timestamp getTimestampInternal(int columnIndex, TimeZone tz, boolean rollForward)
        throws java.sql.SQLException {
        if (this.isBinaryEncoded) {
            return getNativeTimestamp(columnIndex, tz, rollForward);
        }

        String timestampValue = getStringInternal(columnIndex, false);

        return getTimestampFromString(columnIndex, timestampValue, tz, rollForward);
    }

    private synchronized Date fastDateCreate(Calendar cal, int year, int month,
        int day) {
        if (cal == null) {
            if (this.fastDateCal == null) {
                this.fastDateCal = new GregorianCalendar();
                this.fastDateCal.setTimeZone(this.getDefaultTimeZone());
            }

            cal = this.fastDateCal;
        }

        return TimeUtil.fastDateCreate(cal, year, month, day);
    }

    private synchronized Time fastTimeCreate(Calendar cal, int hour,
        int minute, int second) {
        if (cal == null) {
            if (this.fastDateCal == null) {
                this.fastDateCal = new GregorianCalendar();
                this.fastDateCal.setTimeZone(this.getDefaultTimeZone());
            }

            cal = this.fastDateCal;
        }

        return TimeUtil.fastTimeCreate(cal, hour, minute, second);
    }

    private synchronized Timestamp fastTimestampCreate(Calendar cal, int year,
        int month, int day, int hour, int minute, int seconds, int secondsPart) {
        if (cal == null) {
            if (this.fastDateCal == null) {
                this.fastDateCal = new GregorianCalendar();
                this.fastDateCal.setTimeZone(this.getDefaultTimeZone());
            }

            cal = this.fastDateCal;
        }

        return TimeUtil.fastTimestampCreate(cal, year, month, day, hour,
            minute, seconds, secondsPart);
    }

    private void issueDataTruncationWarningIfConfigured(int columnIndex,
        int readSize, int truncatedToSize) {
        DataTruncation dt = new DataTruncation(columnIndex, false, true,
                readSize, truncatedToSize);
    }
    
    /**
     * JDBC 2.0 Get an array column.
     *
     * @param i the first column is 1, the second is 2, ...
     *
     * @return an object representing an SQL array
     *
     * @throws SQLException if a database error occurs
     * @throws NotImplemented DOCUMENT ME!
     */
05381     protected java.sql.Array getNativeArray(int i) throws SQLException {
        throw new NotImplemented();
    }

    /**
     * A column value can be retrieved as a stream of ASCII characters and then
     * read in chunks from the stream.  This method is particulary suitable
     * for retrieving large LONGVARCHAR values. The JDBC driver will do any
     * necessary conversion from the database format into ASCII.
     *
     * <p>
     * <B>Note:</B> All 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.  Also, a stream may return 0 for
     * available() whether there is data available or not.
     * </p>
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     *
     * @return a Java InputStream that delivers the database column value as a
     *         stream of one byte ASCII characters.  If the value is SQL NULL
     *         then the result is null
     *
     * @exception SQLException if a database access error occurs
     *
     * @see getBinaryStream
     */
05408     protected InputStream getNativeAsciiStream(int columnIndex)
        throws SQLException {
        checkRowPos();

        return getNativeBinaryStream(columnIndex);
    }

    /**
     * Get the value of a column in the current row as a java.math.BigDecimal
     * object
     *
     * @param columnIndex the first column is 1, the second is 2...
     * @param scale the number of digits to the right of the decimal
     *
     * @return the column value; if the value is SQL NULL, null
     *
     * @exception SQLException if a database access error occurs
     */
05426     protected BigDecimal getNativeBigDecimal(int columnIndex, int scale)
        throws SQLException {
        String stringVal = getNativeString(columnIndex);
        BigDecimal val;

        if (stringVal != null) {
            if (stringVal.length() == 0) {
                val = new BigDecimal(0);

                try {
                    return val.setScale(scale);
                } catch (ArithmeticException ex) {
                  try {
                        return val.setScale(scale, BigDecimal.ROUND_HALF_UP);
                  } catch (ArithmeticException arEx) {
                        throw new SQLException(Messages.getString(
                            "ResultSet.Bad_format_for_BigDecimal____124") //$NON-NLS-1$
                            +stringVal +
                            Messages.getString("ResultSet.___in_column__125") +
                            columnIndex + "(" //$NON-NLS-1$
                            + this.fields[columnIndex - 1] + ").",
                            SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                  }
                } 
            }

            try {
                val = new BigDecimal(stringVal);
            } catch (NumberFormatException ex) {
                throw new SQLException(Messages.getString(
                        "ResultSet.Bad_format_for_BigDecimal____119") //$NON-NLS-1$
                     +stringVal + "' in column " + columnIndex + "(" +
                     this.fields[columnIndex - 1] + ").",
                    SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
            }

            try {
                return val.setScale(scale);
            } catch (ArithmeticException ex) {
                  try {
                        return val.setScale(scale, BigDecimal.ROUND_HALF_UP);
                  } catch (ArithmeticException arEx) {
                        throw new SQLException(Messages.getString(
                        "ResultSet.Bad_format_for_BigDecimal____124") //$NON-NLS-1$
                        +stringVal +
                        Messages.getString("ResultSet.___in_column__125") +
                        columnIndex + "(" //$NON-NLS-1$
                        + this.fields[columnIndex - 1] + ").",
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                  }
            }
        }

        return null;
    }

    /**
     * JDBC 2.0 Get the value of a column in the current row as a
     * java.math.BigDecimal object.
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     *
     * @return the column value (full precision); if the value is SQL NULL, the
     *         result is null
     *
     * @exception SQLException if a database-access error occurs.
     */
05493     protected BigDecimal getNativeBigDecimal(int columnIndex)
        throws SQLException {
        String stringVal = getNativeString(columnIndex);

        int scale = this.fields[columnIndex - 1].getDecimals();
        
        return getBigDecimalFromString(stringVal, columnIndex, scale);
    }

    /**
     * A column value can also be retrieved as a binary strea.  This method is
     * suitable for retrieving LONGVARBINARY values.
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return a Java InputStream that delivers the database column value as a
     *         stream of bytes.  If the value is SQL NULL, then the result is
     *         null
     *
     * @exception SQLException if a database access error occurs
     *
     * @see getAsciiStream
     * @see getUnicodeStream
     */
05517     protected InputStream getNativeBinaryStream(int columnIndex)
        throws SQLException {
        checkRowPos();

        byte[] b = getNativeBytes(columnIndex, false);

        if (b != null) {
            return new ByteArrayInputStream(b);
        }

        return null;
    }

    /**
     * JDBC 2.0 Get a BLOB column.
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     *
     * @return an object representing a BLOB
     *
     * @throws SQLException if an error occurs.
     */
05539     protected java.sql.Blob getNativeBlob(int columnIndex)
        throws SQLException {
        checkRowPos();

        checkColumnBounds(columnIndex);

        try {
            if (this.thisRow[columnIndex - 1] == null) {
                  this.wasNullFlag = true;
            } else {
                  this.wasNullFlag = false;
            }
        } catch (NullPointerException ex) {
            this.wasNullFlag = true;
        }

        if (this.wasNullFlag) {
            return null;
        }

        int mysqlType = this.fields[columnIndex - 1].getMysqlType();

        byte[] dataAsBytes = null;

        switch (mysqlType) {
        case MysqlDefs.FIELD_TYPE_TINY_BLOB:
        case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
        case MysqlDefs.FIELD_TYPE_LONG_BLOB:
        case MysqlDefs.FIELD_TYPE_BLOB:
            dataAsBytes = (byte[]) this.thisRow[columnIndex - 1];

        default:
            dataAsBytes = getNativeBytes(columnIndex, false);
        }

        if (!this.connection.getEmulateLocators()) {
            return new Blob(dataAsBytes);
        }

        return new BlobFromLocator(this, columnIndex);
    }

    /**
     * Get the value of a column in the current row as a Java boolean
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return the column value, false for SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
05590     protected boolean getNativeBoolean(int columnIndex)
        throws SQLException {
      int columnIndexMinusOne = columnIndex - 1;
      
      Field field = this.fields[columnIndexMinusOne];
      
      if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) {
            if (this.thisRow[columnIndexMinusOne] == null) {
                  this.wasNullFlag = true;
                  
                  return false;
            }
            
            this.wasNullFlag = false;
            
            if (((byte[])this.thisRow[columnIndexMinusOne]).length == 0) {
                  return false;
            }
            
            return (((byte[])this.thisRow[columnIndexMinusOne])[0] > (byte)0);
            
      }
      
      switch (field.getSQLType()) {
                  case Types.BIT:
                  case Types.TINYINT:
                  case Types.SMALLINT:
                  case Types.INTEGER:
                  case Types.BIGINT:
                  case Types.DECIMAL:
                  case Types.NUMERIC:
                  case Types.REAL:
                  case Types.FLOAT:
                  case Types.DOUBLE:
                        byte boolVal = getNativeByte(columnIndex);
                  
                        return boolVal == 1;
            default:
                  String stringVal = getNativeConvertToString(columnIndex, field);

                  return getBooleanFromString(stringVal, columnIndex);
      }  
    }

    /**
     * Get the value of a column in the current row as a Java byte.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
05643     protected byte getNativeByte(int columnIndex) throws SQLException {
        checkRowPos();

        checkColumnBounds(columnIndex);

        if (this.thisRow[columnIndex - 1] == null) {
            this.wasNullFlag = true;

            return 0;
        }

        try {
            if (this.thisRow[columnIndex - 1] == null) {
                  this.wasNullFlag = true;
            } else {
                  this.wasNullFlag = false;
            }
        } catch (NullPointerException E) {
            this.wasNullFlag = true;
        }

        if (this.wasNullFlag) {
            return 0;
        }

        columnIndex--;
        
        Field field = this.fields[columnIndex];

        switch (field.getMysqlType()) {
        case MysqlDefs.FIELD_TYPE_TINY:
            return (byte)((byte[])this.thisRow[columnIndex])[0];
        case MysqlDefs.FIELD_TYPE_SHORT:
        case MysqlDefs.FIELD_TYPE_YEAR:
            int valueAsShort = getNativeShort(columnIndex + 1);
        
            if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsShort < Byte.MIN_VALUE || valueAsShort > Byte.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsShort), columnIndex + 1, Types.TINYINT);
                  }
            }
            
            return (byte) valueAsShort;
        case MysqlDefs.FIELD_TYPE_INT24:
        case MysqlDefs.FIELD_TYPE_LONG:
            int valueAsInt = getNativeInt(columnIndex + 1);
        
            if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsInt < Byte.MIN_VALUE || valueAsInt > Byte.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsInt), columnIndex + 1, Types.TINYINT);
                  }
            }
            
            return (byte)valueAsInt;

        case MysqlDefs.FIELD_TYPE_FLOAT:
            float valueAsFloat = getNativeFloat(columnIndex + 1);
            
            if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsFloat < Byte.MIN_VALUE || valueAsFloat > Byte.MAX_VALUE) {
                        
                        throwRangeException(String.valueOf(valueAsFloat), columnIndex + 1, Types.TINYINT);
                  }
            }
        
            return (byte) valueAsFloat;

        case MysqlDefs.FIELD_TYPE_DOUBLE:
            double valueAsDouble = getNativeDouble(columnIndex + 1);
        
            if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsDouble < Byte.MIN_VALUE || valueAsDouble > Byte.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsDouble), columnIndex + 1, Types.TINYINT);
                  }
            }
            
            return (byte) valueAsDouble;

        case MysqlDefs.FIELD_TYPE_LONGLONG:
            long valueAsLong = getNativeLong(columnIndex + 1);
        
            if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsLong < Byte.MIN_VALUE || valueAsLong > Byte.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsLong), columnIndex + 1, Types.TINYINT);
                  }
            }
            
            return (byte) valueAsLong;

        default:
            if (this.useUsageAdvisor) {
                  issueConversionViaParsingWarning("getByte()", 
                              columnIndex, 
                              this.thisRow[columnIndex], 
                              this.fields[columnIndex], 
                              new int[] {MysqlDefs.FIELD_TYPE_DOUBLE,
                                    MysqlDefs.FIELD_TYPE_TINY,
                                          MysqlDefs.FIELD_TYPE_SHORT,
                                          MysqlDefs.FIELD_TYPE_LONG,
                                          MysqlDefs.FIELD_TYPE_LONGLONG,
                                          MysqlDefs.FIELD_TYPE_FLOAT});
            }
            
            return getByteFromString(getNativeString(columnIndex + 1), columnIndex + 1);
        }
    }

    /**
     * Get the value of a column in the current row as a Java byte array.
     *
     * <p>
     * <b>Be warned</b> If the blob is huge, then you may run out of memory.
     * </p>
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     *
     * @return the column value; if the value is SQL NULL, the result is null
     *
     * @exception SQLException if a database access error occurs
     */
05763     protected byte[] getNativeBytes(int columnIndex, boolean noConversion) throws SQLException {
        checkRowPos();

        checkColumnBounds(columnIndex);

        try {
            if (this.thisRow[columnIndex - 1] == null) {
                  this.wasNullFlag = true;
            } else {
                  this.wasNullFlag = false;
            }
        } catch (NullPointerException E) {
            this.wasNullFlag = true;
        }

        if (this.wasNullFlag) {
            return null;
        }

        int mysqlType = this.fields[columnIndex - 1].getMysqlType();

        // Workaround for emulated locators in servers > 4.1,
        // as server returns SUBSTRING(blob) as STRING type...
        if (noConversion) {
            mysqlType = MysqlDefs.FIELD_TYPE_BLOB;
        }
        
        switch (mysqlType) {
        case MysqlDefs.FIELD_TYPE_TINY_BLOB:
        case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
        case MysqlDefs.FIELD_TYPE_LONG_BLOB:
        case MysqlDefs.FIELD_TYPE_BLOB:
        case MysqlDefs.FIELD_TYPE_BIT:
            return (byte[]) this.thisRow[columnIndex - 1];

        default:
            return getBytesFromString(getNativeString(columnIndex), columnIndex);
        }
    }
    
    /**
     * JDBC 2.0
     *
     * <p>
     * Get the value of a column in the current row as a java.io.Reader.
     * </p>
     *
     * @param columnIndex the column to get the value from
     *
     * @return the value in the column as a java.io.Reader.
     *
     * @throws SQLException if an error occurs
     */
05816     protected java.io.Reader getNativeCharacterStream(int columnIndex)
        throws SQLException {
        String stringVal = getNativeString(columnIndex);

        return getCharacterStreamFromString(stringVal, columnIndex);
    }

    /**
     * JDBC 2.0 Get a CLOB column.
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     *
     * @return an object representing a CLOB
     *
     * @throws SQLException if an error occurs
     */
05832     protected java.sql.Clob getNativeClob(int columnIndex)
        throws SQLException {
        String stringVal = getNativeString(columnIndex);

        return getClobFromString(stringVal, columnIndex);
    }

    /**
     * Get the value of a column in the current row as a java.sql.Date object
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return the column value; null if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
05848     protected java.sql.Date getNativeDate(int columnIndex)
        throws SQLException {
        return getNativeDate(columnIndex, null);
    }

    /**
     * JDBC 2.0 Get the value of a column in the current row as a java.sql.Date
     * object.  Use the calendar to construct an appropriate millisecond value
     * for the Date, if the underlying database doesn't store timezone
     * information.
     *
     * @param columnIndex the first column is 1, the second is 2, ...
     * @param tz the calendar to use in constructing the date
     *
     * @return the column value; if the value is SQL NULL, the result is null
     *
     * @exception SQLException if a database-access error occurs.
     */
05866     protected java.sql.Date getNativeDate(int columnIndex, TimeZone tz)
        throws SQLException {
      checkRowPos();
        checkColumnBounds(columnIndex);

        if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_DATE) {
            byte[] bits = (byte[])this.thisRow[columnIndex - 1];
            
            
            if (bits == null) {
                this.wasNullFlag = true;
                
                return null;
            } 
                
            this.wasNullFlag = false;
            
            java.sql.Date dateToReturn = null;
            
            int year = 0;
            int month = 0;
            int day = 0;

            int hour = 0;
            int minute = 0;
            int seconds = 0;

            if (bits.length != 0) {
                year = (bits[0] & 0xff) 
                              | ((bits[1] & 0xff) << 8);
                
                month = bits[2];
                day = bits[3];
            }

            if ((year == 0) && (month == 0) && (day == 0)) {
                if (ConnectionProperties.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL.equals(
                            this.connection.getZeroDateTimeBehavior())) {
                    this.wasNullFlag = true;
                    
                    return null;
                } else if (ConnectionProperties.ZERO_DATETIME_BEHAVIOR_EXCEPTION.equals(
                            this.connection.getZeroDateTimeBehavior())) {
                    throw new SQLException("Value '0000-00-00' can not be represented as java.sql.Date",
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                }

                year = 1;
                month = 1;
                day = 1;
            }

            
            return TimeUtil.fastDateCreate(getCalendarInstanceForSessionOrNew(),
                        year, month, day);
        }
        

        if (this.useUsageAdvisor) {
            issueConversionViaParsingWarning("getDate()", 
                        columnIndex, 
                        this.thisRow[columnIndex], 
                        this.fields[columnIndex], 
                        new int[] {MysqlDefs.FIELD_TYPE_DATE});
      }
        
        String stringVal = getNativeString(columnIndex);

        return getDateFromString(stringVal, columnIndex);
           
    }

    /**
     * Get the value of a column in the current row as a Java double.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
05947     protected double getNativeDouble(int columnIndex) throws SQLException {
        checkRowPos();
        checkColumnBounds(columnIndex);

        columnIndex--; /// JDBC is 1-based

        if (this.thisRow[columnIndex] == null) {
            this.wasNullFlag = true;

            return 0;
        }

        this.wasNullFlag = false;

        switch (this.fields[columnIndex].getMysqlType()) {
        case MysqlDefs.FIELD_TYPE_DOUBLE:
            byte[] bits = (byte[]) this.thisRow[columnIndex];
        
            long valueAsLong = (bits[0] & 0xff)
                        | ((long) (bits[1] & 0xff) << 8)
                        | ((long) (bits[2] & 0xff) << 16)
                        | ((long) (bits[3] & 0xff) << 24)
                        | ((long) (bits[4] & 0xff) << 32)
                        | ((long) (bits[5] & 0xff) << 40)
                        | ((long) (bits[6] & 0xff) << 48)
                        | ((long) (bits[7] & 0xff) << 56);
            
            return Double.longBitsToDouble(valueAsLong);
        case MysqlDefs.FIELD_TYPE_TINY:
            return (double) getNativeByte(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_SHORT:
        case MysqlDefs.FIELD_TYPE_YEAR:
            return (double) getNativeShort(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_INT24:
        case MysqlDefs.FIELD_TYPE_LONG:
            return (double) getNativeInt(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_LONGLONG:
            return (double) getNativeLong(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_FLOAT:
            return (double) getNativeFloat(columnIndex + 1);

        default:

            if (this.useUsageAdvisor) {
                  issueConversionViaParsingWarning("getDouble()", 
                              columnIndex, 
                              this.thisRow[columnIndex], 
                              this.fields[columnIndex], 
                              new int[] {MysqlDefs.FIELD_TYPE_DOUBLE,
                                    MysqlDefs.FIELD_TYPE_TINY,
                                          MysqlDefs.FIELD_TYPE_SHORT,
                                          MysqlDefs.FIELD_TYPE_LONG,
                                          MysqlDefs.FIELD_TYPE_LONGLONG,
                                          MysqlDefs.FIELD_TYPE_FLOAT});
            }
            
            String stringVal = getNativeString(columnIndex + 1);

            return getDoubleFromString(stringVal, columnIndex + 1);
        }
    }

    /**
     * Get the value of a column in the current row as a Java float.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
06018     protected float getNativeFloat(int columnIndex) throws SQLException {
        checkRowPos();
        checkColumnBounds(columnIndex);

        columnIndex--; /// JDBC is 1-based

        if (this.thisRow[columnIndex] == null) {
            this.wasNullFlag = true;

            return 0;
        }

        this.wasNullFlag = false;

        // TODO: Truncation check
        switch (this.fields[columnIndex].getMysqlType()) {
        case MysqlDefs.FIELD_TYPE_DOUBLE:
            return (float)getNativeDouble(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_TINY:
            return (float)getNativeByte(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_SHORT:
        case MysqlDefs.FIELD_TYPE_YEAR:
            return (float)getNativeShort(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_INT24:
        case MysqlDefs.FIELD_TYPE_LONG:
            return (float)getNativeInt(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_LONGLONG:
            return (float)getNativeLong(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_FLOAT:
            byte[] bits = (byte[])this.thisRow[columnIndex];
            
            int asInt = (bits[0] & 0xff) | ((bits[1] & 0xff) << 8)
                        | ((bits[2] & 0xff) << 16)
                        | ((bits[3] & 0xff) << 24);
            
            return Float.intBitsToFloat(asInt);

        default:

            if (this.useUsageAdvisor) {
                  issueConversionViaParsingWarning("getFloat()", 
                              columnIndex, 
                              this.thisRow[columnIndex], 
                              this.fields[columnIndex], 
                              new int[] {MysqlDefs.FIELD_TYPE_DOUBLE,
                                    MysqlDefs.FIELD_TYPE_TINY,
                                          MysqlDefs.FIELD_TYPE_SHORT,
                                          MysqlDefs.FIELD_TYPE_LONG,
                                          MysqlDefs.FIELD_TYPE_LONGLONG,
                                          MysqlDefs.FIELD_TYPE_FLOAT});
            }
            
            String stringVal = getNativeString(columnIndex + 1);

            return getFloatFromString(stringVal, columnIndex + 1);
        }
    }



      /**
     * Get the value of a column in the current row as a Java int.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
06087     protected int getNativeInt(int columnIndex) throws SQLException {
        checkRowPos();
        checkColumnBounds(columnIndex);

        columnIndex--; /// JDBC is 1-based

        if (this.thisRow[columnIndex] == null) {
            this.wasNullFlag = true;

            return 0;
        }

        this.wasNullFlag = false;

        switch (this.fields[columnIndex].getMysqlType()) {
        
        case MysqlDefs.FIELD_TYPE_TINY:
            return getNativeByte(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_SHORT:
        case MysqlDefs.FIELD_TYPE_YEAR:
            return getNativeShort(columnIndex + 1); 
        case MysqlDefs.FIELD_TYPE_INT24:
        case MysqlDefs.FIELD_TYPE_LONG:
            byte[] bits = (byte[])this.thisRow[columnIndex];
        
            int valueAsInt = (bits[0] & 0xff) 
                        | ((bits[1] & 0xff) << 8)
                        | ((bits[2] & 0xff) << 16)
                        | ((bits[3] & 0xff) << 24);
            
            return valueAsInt;
        case MysqlDefs.FIELD_TYPE_LONGLONG:
            long valueAsLong = getNativeLong(columnIndex + 1);
        
            if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsLong < Integer.MIN_VALUE || valueAsLong > Integer.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsLong), columnIndex + 1, Types.INTEGER);
                  }
            }
            
            return (int) valueAsLong;
        case MysqlDefs.FIELD_TYPE_DOUBLE:
            double valueAsDouble = getNativeDouble(columnIndex + 1);
        
            if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsDouble), columnIndex + 1, Types.INTEGER);
                  }
            }           

            return (int) valueAsDouble;
        case MysqlDefs.FIELD_TYPE_FLOAT:
            valueAsDouble = getNativeFloat(columnIndex + 1);
        
            if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsDouble), columnIndex + 1, Types.INTEGER);
                  }
            }
            
            return (int) valueAsDouble;
      
        default:

            if (this.useUsageAdvisor) {
                  issueConversionViaParsingWarning("getInt()", 
                              columnIndex, 
                              this.thisRow[columnIndex], 
                              this.fields[columnIndex], 
                              new int[] {MysqlDefs.FIELD_TYPE_DOUBLE,
                                    MysqlDefs.FIELD_TYPE_TINY,
                                          MysqlDefs.FIELD_TYPE_SHORT,
                                          MysqlDefs.FIELD_TYPE_LONG,
                                          MysqlDefs.FIELD_TYPE_LONGLONG,
                                          MysqlDefs.FIELD_TYPE_FLOAT});
            }
            
            String stringVal = getNativeString(columnIndex + 1);

            return getIntFromString(stringVal, columnIndex + 1);
        }
    }

    /**
     * Get the value of a column in the current row as a Java long.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
06179     protected long getNativeLong(int columnIndex) throws SQLException {
        checkRowPos();
        checkColumnBounds(columnIndex);

        columnIndex--; /// JDBC is 1-based

        if (this.thisRow[columnIndex] == null) {
            this.wasNullFlag = true;

            return 0;
        }

        this.wasNullFlag = false;

        switch (this.fields[columnIndex].getMysqlType()) {
        case MysqlDefs.FIELD_TYPE_TINY:
            return getNativeByte(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_SHORT:
        case MysqlDefs.FIELD_TYPE_YEAR:
            return getNativeShort(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_INT24:
        case MysqlDefs.FIELD_TYPE_LONG:
            return getNativeInt(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_LONGLONG:
            byte[] bits = (byte[])this.thisRow[columnIndex];
        
            long valueAsLong = (bits[0] & 0xff)
                  | ((long) (bits[1] & 0xff) << 8)
                        | ((long) (bits[2] & 0xff) << 16)
                        | ((long) (bits[3] & 0xff) << 24)
                        | ((long) (bits[4] & 0xff) << 32)
                        | ((long) (bits[5] & 0xff) << 40)
                        | ((long) (bits[6] & 0xff) << 48)
                        | ((long) (bits[7] & 0xff) << 56);
            
            return valueAsLong;
        case MysqlDefs.FIELD_TYPE_DOUBLE:
            double valueAsDouble = getNativeDouble(columnIndex + 1);
        
            if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsDouble < Long.MIN_VALUE || valueAsDouble > Long.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsDouble), columnIndex + 1, Types.BIGINT);
                  }
            }
            
            return (long) valueAsDouble;
        case MysqlDefs.FIELD_TYPE_FLOAT:
            valueAsDouble = getNativeFloat(columnIndex + 1);
        
            if (this.connection.getJdbcCompliantTruncation()) {
                  if (valueAsDouble < Long.MIN_VALUE || valueAsDouble > Long.MAX_VALUE) {
                        throwRangeException(String.valueOf(valueAsDouble), columnIndex + 1, Types.BIGINT);
                  }
            }
            
            return (long) valueAsDouble;
        default:

            if (this.useUsageAdvisor) {
                  issueConversionViaParsingWarning("getLong()", 
                              columnIndex, 
                              this.thisRow[columnIndex], 
                              this.fields[columnIndex], 
                              new int[] {MysqlDefs.FIELD_TYPE_DOUBLE,
                                    MysqlDefs.FIELD_TYPE_TINY,
                                          MysqlDefs.FIELD_TYPE_SHORT,
                                          MysqlDefs.FIELD_TYPE_LONG,
                                          MysqlDefs.FIELD_TYPE_LONGLONG,
                                          MysqlDefs.FIELD_TYPE_FLOAT});
            }
            
            String stringVal = getNativeString(columnIndex + 1);

            return getLongFromString(stringVal, columnIndex + 1);
        }
    }

    /**
     * JDBC 2.0 Get a REF(&lt;structured-type&gt;) column.
     *
     * @param i the first column is 1, the second is 2, ...
     *
     * @return an object representing data of an SQL REF type
     *
     * @throws SQLException as this is not implemented
     * @throws NotImplemented DOCUMENT ME!
     */
06266     protected java.sql.Ref getNativeRef(int i) throws SQLException {
        throw new NotImplemented();
    }

    /**
     * Get the value of a column in the current row as a Java short.
     *
     * @param columnIndex the first column is 1, the second is 2,...
     *
     * @return the column value; 0 if SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
06279     protected short getNativeShort(int columnIndex) throws SQLException {
        checkRowPos();
        checkColumnBounds(columnIndex);

        columnIndex--; /// JDBC is 1-based

        if (this.thisRow[columnIndex] == null) {
            this.wasNullFlag = true;

            return 0;
        }

        this.wasNullFlag = false;

        // TODO: Truncation warning?
        switch (this.fields[columnIndex].getMysqlType()) {
        case MysqlDefs.FIELD_TYPE_DOUBLE:
            return (short)getNativeDouble(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_TINY:
            return getNativeByte(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_SHORT:
        case MysqlDefs.FIELD_TYPE_YEAR:
            byte[] bits = (byte[]) this.thisRow[columnIndex];
        
            short shortVal = (short)((bits[0] & 0xff) 
                        | ((bits[1] & 0xff) << 8));
            
            return shortVal;
        case MysqlDefs.FIELD_TYPE_INT24:
        case MysqlDefs.FIELD_TYPE_LONG:
            return (short)getNativeInt(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_LONGLONG:
            return (short)getNativeLong(columnIndex + 1);
        case MysqlDefs.FIELD_TYPE_FLOAT:
            return (short)getNativeFloat(columnIndex + 1);

        default:

            if (this.useUsageAdvisor) {
                  issueConversionViaParsingWarning("getShort()", 
                              columnIndex, 
                              this.thisRow[columnIndex], 
                              this.fields[columnIndex], 
                              new int[] {MysqlDefs.FIELD_TYPE_DOUBLE,
                                    MysqlDefs.FIELD_TYPE_TINY,
                                          MysqlDefs.FIELD_TYPE_SHORT,
                                          MysqlDefs.FIELD_TYPE_LONG,
                                          MysqlDefs.FIELD_TYPE_LONGLONG,
                                          MysqlDefs.FIELD_TYPE_FLOAT});
            }
            
            String stringVal = getNativeString(columnIndex + 1);

            return getShortFromString(stringVal, columnIndex + 1);
        }
    }

    /**
     * Get the value of a column in the current row as a Java String
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return the column value, null for SQL NULL
     *
     * @exception SQLException if a database access error occurs
     */
06345     protected String getNativeString(int columnIndex) throws SQLException {
        checkRowPos();
        checkColumnBounds(columnIndex);

        if (this.fields == null) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Query_generated_no_fields_for_ResultSet_133"), //$NON-NLS-1$
                SQLError.SQL_STATE_INVALID_COLUMN_NUMBER);
        }

        try {
            if (this.thisRow[columnIndex - 1] == null) {
                  this.wasNullFlag = true;

                return null;
            }

            this.wasNullFlag = false;
        } catch (NullPointerException E) {
            this.wasNullFlag = true;

            return null;
        }

        String stringVal = null;

        if (this.thisRow[columnIndex - 1] instanceof String) {
            return (String) this.thisRow[columnIndex - 1];
        }

        Field field = this.fields[columnIndex - 1];

        /*
        int mysqlType = field.getMysqlType();

        switch (mysqlType) {
        case MysqlDefs.FIELD_TYPE_TINY_BLOB:
        case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
        case MysqlDefs.FIELD_TYPE_LONG_BLOB:
        case MysqlDefs.FIELD_TYPE_BLOB:
        case MysqlDefs.FIELD_TYPE_DECIMAL:

            if ((this.connection != null) && this.connection.getUseUnicode()) {
                try {
                    String encoding = this.fields[columnIndex - 1].getCharacterSet();

                    if (encoding == null) {
                        stringVal = new String((byte[]) this.thisRow[columnIndex -
                                1]);
                    } else {
                        SingleByteCharsetConverter converter = this.connection.getCharsetConverter(encoding);

                        if (converter != null) {
                            stringVal = converter.toString((byte[]) this.thisRow[columnIndex -
                                    1]);
                        } else {
                            stringVal = new String((byte[]) this.thisRow[columnIndex -
                                    1], encoding);
                        }
                    }
                } catch (java.io.UnsupportedEncodingException E) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Unsupported_character_encoding____135") //$NON-NLS-1$
                         + this.connection.getEncoding() + "'.", "0S100");
                }
            } else {
                stringVal = StringUtils.toAsciiString((byte[]) this.thisRow[columnIndex -
                        1]);
            }

            // Cache this conversion if the type is a MySQL string type
            if ((mysqlType == MysqlDefs.FIELD_TYPE_STRING) ||
                    (mysqlType == MysqlDefs.FIELD_TYPE_VAR_STRING)) {
                this.thisRow[columnIndex - 1] = stringVal;
            }

            return stringVal;

        case MysqlDefs.FIELD_TYPE_VAR_STRING:
        case MysqlDefs.FIELD_TYPE_STRING:

            if (this.thisRow[columnIndex - 1] instanceof String) {
                return (String) this.thisRow[columnIndex - 1];
            }

            if ((this.connection != null) && this.connection.getUseUnicode()) {
                try {
                    String encoding = this.fields[columnIndex - 1].getCharacterSet();

                    if (encoding == null) {
                        stringVal = new String((byte[]) this.thisRow[columnIndex -
                                1]);
                    } else {
                        SingleByteCharsetConverter converter = this.connection.getCharsetConverter(encoding);

                        if (converter != null) {
                            stringVal = converter.toString((byte[]) this.thisRow[columnIndex -
                                    1]);
                        } else {
                            stringVal = new String((byte[]) this.thisRow[columnIndex -
                                    1], encoding);
                        }
                    }
                } catch (java.io.UnsupportedEncodingException E) {
                    throw new SQLException(Messages.getString(
                            "ResultSet.Unsupported_character_encoding____138") //$NON-NLS-1$
                         + this.connection.getEncoding() + "'.", "0S100");
                }
            } else {
                stringVal = StringUtils.toAsciiString((byte[]) this.thisRow[columnIndex -
                        1]);
            }

            // Cache this conversion if the type is a MySQL string type
            if ((mysqlType == MysqlDefs.FIELD_TYPE_STRING) ||
                    (mysqlType == MysqlDefs.FIELD_TYPE_VAR_STRING)) {
                this.thisRow[columnIndex - 1] = stringVal;
            }

            return stringVal;

        default:
        */
            // TODO: Check Types Here.
            stringVal = getNativeConvertToString(columnIndex, field);

            if (field.isZeroFill() && (stringVal != null)) {
                int origLength = stringVal.length();

                StringBuffer zeroFillBuf = new StringBuffer(origLength);

                int numZeros = field.getLength() - origLength;

                for (int i = 0; i < numZeros; i++) {
                    zeroFillBuf.append('0');
                }

                zeroFillBuf.append(stringVal);

                stringVal = zeroFillBuf.toString();
            }

            return stringVal;
        //}
    }

    /**
     * @see ResultSet#getURL(int)
     */
06494     protected URL getNativeURL(int colIndex) throws SQLException {
        String val = getString(colIndex);

        if (val == null) {
            return null;
        }

        try {
            return new URL(val);
        } catch (MalformedURLException mfe) {
            throw new SQLException(Messages.getString(
                    "ResultSet.Malformed_URL____141") + val + "'",
                SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
        }
    }

    /**
     * A column value can also be retrieved as a stream of Unicode characters.
     * We implement this as a binary stream.
     *
     * @param columnIndex the first column is 1, the second is 2...
     *
     * @return a Java InputStream that delivers the database column value as a
     *         stream of two byte Unicode characters.  If the value is SQL
     *         NULL, then the result is null
     *
     * @exception SQLException if a database access error occurs
     *
     * @see getAsciiStream
     * @see getBinaryStream
     */
06525     protected InputStream getNativeUnicodeStream(int columnIndex)
        throws SQLException {
        checkRowPos();

        return getBinaryStream(columnIndex);
    }

      /**
       * Optimization to only use one calendar per-session, or calculate it
       * for each call, depending on user configuration
       */
06536       private synchronized Calendar getCalendarInstanceForSessionOrNew() {
            if (this.connection.getDynamicCalendars()) {
                  return Calendar.getInstance();
            }
                  
            if (this.sessionCalendar == null) {
                  this.sessionCalendar = Calendar.getInstance();
            }
            
            return this.sessionCalendar;
      }

      private Time getNativeTime(int columnIndex, TimeZone tz, boolean rollForward)
          throws SQLException {
          checkRowPos();
          checkColumnBounds(columnIndex);
      
          if (this.thisRow[columnIndex - 1] == null) {
              this.wasNullFlag = true;
          } else {
              this.wasNullFlag = false;
          }
      
          int mysqlType = this.fields[columnIndex - 1].getMysqlType();
      
          if (mysqlType == MysqlDefs.FIELD_TYPE_TIME) {
              
            byte[] bits = (byte[])this.thisRow[columnIndex - 1];
            
            int length = bits.length;
            int hour = 0;
            int minute = 0;
            int seconds = 0;

            if (length != 0) {
                //bits[0] // skip tm->neg
                //binaryData.readLong(); // skip daysPart
                hour = bits[5];
                minute = bits[6];
                seconds = bits[7];
            }

            Time time = TimeUtil.fastTimeCreate(getCalendarInstanceForSessionOrNew(),
                        hour, minute, seconds);
                
              Time adjustedTime = TimeUtil.changeTimezone(this.connection, time,
                      this.connection.getServerTimezoneTZ(), tz, rollForward);
      
              return adjustedTime;
          }
      
          if (this.useUsageAdvisor) {
                  issueConversionViaParsingWarning("getTime()", 
                              columnIndex, 
                              this.thisRow[columnIndex], 
                              this.fields[columnIndex], 
                              new int[] {MysqlDefs.FIELD_TYPE_TIME});
            }
                  
          String strTime = getNativeString(columnIndex);
      
          return getTimeFromString(strTime, columnIndex, tz, rollForward);
      }

      private Timestamp getNativeTimestamp(int columnIndex, TimeZone tz, boolean rollForward)
          throws SQLException {
          checkRowPos();
          checkColumnBounds(columnIndex);
      
          if (this.thisRow[columnIndex - 1] == null) {
              this.wasNullFlag = true;
      
              return null;
          }
      
          this.wasNullFlag = false;
      
          int mysqlType = this.fields[columnIndex - 1].getMysqlType();
      
          switch (mysqlType) {
          case MysqlDefs.FIELD_TYPE_DATETIME:
          case MysqlDefs.FIELD_TYPE_TIMESTAMP:
            byte[] bits = (byte[]) this.thisRow[columnIndex - 1];

            int length = bits.length;
            
            int year = 0;
            int month = 0;
            int day = 0;

            int hour = 0;
            int minute = 0;
            int seconds = 0;

            int nanos = 0;

              if (length != 0) {
                  year = (bits[0] & 0xff) | ((bits[1] & 0xff) << 8);
                  month = bits[2];
                  day = bits[3];
      
                  if (length > 4) {
                      hour = bits[4];
                      minute = bits[5];
                      seconds = bits[6];
                  }
      
                  if (length > 7) {
                      nanos = (bits[7] & 0xff) 
                                    | ((bits[8] & 0xff) << 8)
                                    | ((bits[9] & 0xff) << 16)
                                    | ((bits[10] & 0xff) << 24);
                  }
              }
      
              if ((year == 0) && (month == 0) && (day == 0)) {
                  if (ConnectionProperties.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL.equals(
                              this.connection.getZeroDateTimeBehavior())) {
                      this.wasNullFlag = true;
      
                      return null;
                  } else if (ConnectionProperties.ZERO_DATETIME_BEHAVIOR_EXCEPTION.equals(
                              this.connection.getZeroDateTimeBehavior())) {
                      throw new SQLException("Value '0000-00-00' can not be represented as java.sql.Timestamp",
                          SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                  }
      
                  year = 1;
                  month = 1;
                  day = 1;
              }
              
              Timestamp ts = TimeUtil.fastTimestampCreate(getCalendarInstanceForSessionOrNew(),
                          year, month, day, hour, minute, seconds, nanos);
            
              Timestamp adjustedTs = TimeUtil.changeTimezone(this.connection, ts,
                      this.connection.getServerTimezoneTZ(), tz, rollForward);
      
              return adjustedTs;
      
          default:
      
            if (this.useUsageAdvisor) {
                  issueConversionViaParsingWarning("getTimestamp()", 
                              columnIndex, 
                              this.thisRow[columnIndex], 
                              this.fields[columnIndex], 
                              new int[] {MysqlDefs.FIELD_TYPE_TIMESTAMP,
                                    MysqlDefs.FIELD_TYPE_DATETIME});
            }
            
              String strTimestamp = getNativeString(columnIndex);
      
              return getTimestampFromString(columnIndex, strTimestamp, tz, rollForward);
          }
      } 
      
      private String getNativeConvertToString(int columnIndex, Field field)
            throws SQLException {
            
            //
            // TODO: When using usage advisor, warn about conversions (some are costly)
            //
            
            int sqlType = field.getSQLType();
            int mysqlType = field.getMysqlType();
            
            if (this.connection.getUseUsageAdvisor()) {
                  StringBuffer messageBuf = new StringBuffer();
                  messageBuf.append("Costly type conversion for prepared statement.");
                  messageBuf.append(" Column number '");
                  messageBuf.append(columnIndex);
                  messageBuf.append("' is MySQL type '");
                  messageBuf.append(MysqlDefs.typeToName(mysqlType));
                  messageBuf.append("' but needed to be converted to a String for further");
                  messageBuf.append(" processing/conversion. It is more efficient to ensure");
                  messageBuf.append(" that the datatype asked for via ResultSet.get*() matches");
                  messageBuf.append(" what was returned from the server.");
                  
                  this.eventSink.consumeEvent(new ProfilerEvent(
                              ProfilerEvent.TYPE_WARN, "", //$NON-NLS-1$
                              this.owningStatement == null ? "N/A" : this.owningStatement.currentCatalog, //$NON-NLS-1$
                              this.connection.getId(), this.owningStatement == null ? -1 : this.owningStatement.getId(),
                              -1, System.currentTimeMillis(), 0,
                              null, null, 
                              messageBuf.toString()));
            }
            
            switch (sqlType) {
            case Types.BIT:
                  boolean booleanVal = getNativeBoolean(columnIndex);
                  
                  if (this.wasNullFlag) {
                        return null;
                  }
                        
                  return String.valueOf(booleanVal);

            case Types.TINYINT:
                  byte tinyintVal = getNativeByte(columnIndex);
                  
                  if (this.wasNullFlag) {
                        return null;
                  }
                  
                  if (!field.isUnsigned()) {          
                        return String.valueOf(tinyintVal);
                  }
                  
                  short unsignedTinyVal = (short) (tinyintVal & 0xff);
                  
                  return String.valueOf(unsignedTinyVal);
                  
            case Types.SMALLINT:
                  
                  int intVal = getNativeInt(columnIndex);
                  
                  if (this.wasNullFlag) {
                        return null;
                  }
                  
                  if (!field.isUnsigned()) {    
                        return String.valueOf(intVal);
                  }
                  
                  intVal = intVal & 0xffff;
            
                  return String.valueOf(intVal);
                  
            case Types.INTEGER:
                  intVal = getNativeInt(columnIndex);
                  
                  if (this.wasNullFlag) {
                        return null;
                  }
                  
                  if (!field.isUnsigned()) {
      
                        return String.valueOf(intVal);
                  }
                  
                  long longVal = intVal & 0xffffffffL;;
            
                  return String.valueOf(longVal);
                  
            case Types.BIGINT:
                  
                  if (!field.isUnsigned()) {
                        longVal = getNativeLong(columnIndex);
                        
                        if (this.wasNullFlag) {
                              return null;
                        }
                                    
                        return String.valueOf(longVal);
                  }
                  
                  longVal = getNativeLong(columnIndex);
                  
                  if (this.wasNullFlag) {
                        return null;
                  }
                  
                  return String.valueOf(convertLongToUlong(longVal));
            case Types.REAL:
                  float floatVal = getNativeFloat(columnIndex);
                  
                  if (this.wasNullFlag) {
                        return null;
                  }
                              
                  return String.valueOf(floatVal);

            case Types.FLOAT:
            case Types.DOUBLE:
                  double doubleVal = getNativeDouble(columnIndex);
                  
                  if (this.wasNullFlag) {
                        return null;
                  }
                              
                  return String.valueOf(doubleVal);
                  
            case Types.DECIMAL:
            case Types.NUMERIC:
                  String stringVal = StringUtils.toAsciiString((byte[])this.thisRow[columnIndex - 1]);
            
                  BigDecimal val;
                  
                  if (stringVal != null) {
                        if (stringVal.length() == 0) {
                              val = new BigDecimal(0);
                              
                              return val.toString();
                        }
                        
                        try {
                              val = new BigDecimal(stringVal);
                        } catch (NumberFormatException ex) {
                              throw new SQLException(Messages.getString(
                              "ResultSet.Bad_format_for_BigDecimal____86") //$NON-NLS-1$
                              +stringVal +
                              Messages.getString("ResultSet.___in_column__87") +
                              columnIndex + "(" //$NON-NLS-1$
                              + this.fields[columnIndex - 1] + ").",
                              SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
                        }
                        
                        return val.toString();
                  }
            
                  return null;
            

            
            case Types.CHAR:
            case Types.VARCHAR:
            case Types.LONGVARCHAR:
            
                  return extractStringFromNativeColumn(columnIndex, mysqlType);
            case Types.BINARY:
            case Types.VARBINARY:
            case Types.LONGVARBINARY:
                  
                  if (!field.isBlob()) {
                        return extractStringFromNativeColumn(columnIndex, mysqlType);
                  } else if (!field.isBinary()) {
                        return extractStringFromNativeColumn(columnIndex, mysqlType);
                  } else {
                        byte[] data = getBytes(columnIndex);
                        Object obj = data;
                        
                        if ((data != null) && (data.length >= 2)) {
                              if ((data[0] == -84) && (data[1] == -19)) {
                                    // Serialized object?
                                    try {
                                          ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);
                                          ObjectInputStream objIn = new ObjectInputStream(bytesIn);
                                          obj = objIn.readObject();
                                          objIn.close();
                                          bytesIn.close();
                                    } catch (ClassNotFoundException cnfe) {
                                          throw new SQLException(Messages.getString(
                                          "ResultSet.Class_not_found___91") //$NON-NLS-1$
                                          +cnfe.toString() +
                                          Messages.getString(
                                          "ResultSet._while_reading_serialized_object_92")); //$NON-NLS-1$
                                    } catch (IOException ex) {
                                          obj = data; // not serialized?
                                    }
                              }
                              
                              return obj.toString();
                        }
                        
                        return extractStringFromNativeColumn(columnIndex, mysqlType);
                  }
            
            case Types.DATE:
                  if (mysqlType != MysqlDefs.FIELD_TYPE_YEAR) {
                        Date dt = getNativeDate(columnIndex);
                        
                        if (dt == null) {
                              return null;
                        }
                        
                        return String.valueOf(dt);
                  }
                        
                  short shortVal = getNativeShort(columnIndex);
                  
                  if (this.wasNullFlag) {
                        return null;
                  }
                  
                  return String.valueOf(shortVal);

            case Types.TIME:
                  Time tm = getNativeTime(columnIndex, this.defaultTimeZone, false);
                  
                  if (tm == null) {
                        return null;
                  }
                  
                  return String.valueOf(tm);
            
            case Types.TIMESTAMP:
                  Timestamp tstamp = getNativeTimestamp(columnIndex, this.defaultTimeZone, false);
                  
                  if (tstamp == null) {
                        return null;
                  }
                  
                  String result = String.valueOf(tstamp);
                  
                  if (!this.connection.getNoDatetimeStringSync()) {
                        return result;
                  } 
                  
                  if (result.endsWith(".0")) {
                        return result.substring(0, result.length() - 2);
                  }
            
            default:
                  return extractStringFromNativeColumn(columnIndex, mysqlType);
            }
      }
      
      /**
       * @param wrapperStatement The wrapperStatement to set.
       */
06947       public void setWrapperStatement(java.sql.Statement wrapperStatement) {
            this.wrapperStatement = wrapperStatement;
      }
}

Generated by  Doxygen 1.6.0   Back to index