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

com.mysql.jdbc.ResultSetImpl Maven / Gradle / Ivy

There is a newer version: 8.0.33
Show newest version
/*
  Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.

  The MySQL Connector/J is licensed under the terms of the GPLv2
  , like most MySQL Connectors.
  There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
  this software, see the FOSS License Exception
  .

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

  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., 51 Franklin St, Fifth
  Floor, Boston, MA 02110-1301  USA

 */

package com.mysql.jdbc;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Array;
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.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.TreeMap;

import com.mysql.jdbc.log.LogUtils;
import com.mysql.jdbc.profiler.ProfilerEvent;
import com.mysql.jdbc.profiler.ProfilerEventHandler;

/**
 * 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.
 * 
 * 

* 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. *

* *

* 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. *

* *

* For maximum portability, ResultSet columns within each row should be read in left-to-right order and each column should be read only once. *

* *

* 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. *

* *

* 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. *

* *

* 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. *

* *

* The number, types and properties of a ResultSet's columns are provided by the ResultSetMetaData object returned by the getMetaData method. *

*/ public class ResultSetImpl implements ResultSetInternalMethods { private static final Constructor JDBC_4_RS_4_ARG_CTOR; private static final Constructor JDBC_4_RS_5_ARG_CTOR;; private static final Constructor JDBC_4_UPD_RS_5_ARG_CTOR; static { if (Util.isJdbc4()) { try { String jdbc4ClassName = Util.isJdbc42() ? "com.mysql.jdbc.JDBC42ResultSet" : "com.mysql.jdbc.JDBC4ResultSet"; JDBC_4_RS_4_ARG_CTOR = Class.forName(jdbc4ClassName) .getConstructor(new Class[] { Long.TYPE, Long.TYPE, MySQLConnection.class, com.mysql.jdbc.StatementImpl.class }); JDBC_4_RS_5_ARG_CTOR = Class.forName(jdbc4ClassName) .getConstructor(new Class[] { String.class, Field[].class, RowData.class, MySQLConnection.class, com.mysql.jdbc.StatementImpl.class }); jdbc4ClassName = Util.isJdbc42() ? "com.mysql.jdbc.JDBC42UpdatableResultSet" : "com.mysql.jdbc.JDBC4UpdatableResultSet"; JDBC_4_UPD_RS_5_ARG_CTOR = Class.forName(jdbc4ClassName) .getConstructor(new Class[] { String.class, Field[].class, RowData.class, MySQLConnection.class, com.mysql.jdbc.StatementImpl.class }); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } else { JDBC_4_RS_4_ARG_CTOR = null; JDBC_4_RS_5_ARG_CTOR = null; JDBC_4_UPD_RS_5_ARG_CTOR = null; } } /** * Epsillon between Float.MIN_VALUE and the double representation of said value. */ protected static final double MIN_DIFF_PREC = Float.parseFloat(Float.toString(Float.MIN_VALUE)) - Double.parseDouble(Float.toString(Float.MIN_VALUE)); /** * Epsillon between Float.MAX_VALUE and the double representation of said value. */ protected static final double MAX_DIFF_PREC = Float.parseFloat(Float.toString(Float.MAX_VALUE)) - Double.parseDouble(Float.toString(Float.MAX_VALUE)); /** Counter used to generate IDs for profiling. */ static int resultCounter = 1; /** * Converts the given value as a java long, to an 'unsigned' long, using the java.math.BigInteger class. */ 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); } /** The catalog that was in use when we were created */ protected String catalog = null; /** Map column names (and all of their permutations) to column indices */ protected Map columnLabelToIndex = null; /** * The above map is a case-insensitive tree-map, it can be slow, this caches lookups into that map, because the other alternative is to create new * object instances for every call to findColumn().... */ protected Map columnToIndexCache = null; /** Keep track of columns accessed */ protected boolean[] columnUsed = null; /** The Connection instance that created us */ protected volatile MySQLConnection connection; // The connection that created us protected long connectionId = 0; /** The current row #, -1 == before start of result set */ protected int currentRow = -1; // Cursor to current row; /** Are we in the middle of doing updates to the current row? */ protected boolean doingUpdates = false; protected ProfilerEventHandler eventSink = null; Calendar fastDefaultCal = null; Calendar fastClientCal = null; /** The direction to fetch rows (always FETCH_FORWARD) */ protected int fetchDirection = FETCH_FORWARD; /** The number of rows to fetch in one go... */ protected int fetchSize = 0; /** The fields for this result set */ protected Field[] fields; // The fields /** * First character of the query that created this result set...Used to determine whether or not to parse server info messages in certain * circumstances. */ protected char firstCharOfQuery; /** Map of fully-specified column names to column indices */ protected Map fullColumnNameToIndex = null; protected Map columnNameToIndex = null; protected boolean hasBuiltIndexMapping = false; /** * Is the data stored as strings (default) or natively (which is the case with results from PrepStmts) */ protected boolean isBinaryEncoded = false; /** Has this result set been closed? */ protected boolean isClosed = false; protected ResultSetInternalMethods nextResultSet = null; /** Are we on the insert row? */ protected boolean onInsertRow = false; /** The statement that created us */ protected com.mysql.jdbc.StatementImpl owningStatement; /** * StackTrace generated where ResultSet was created... used when profiling */ protected String pointOfOrigin; /** Are we tracking items for profileSql? */ protected boolean profileSql = false; /** * Do we actually contain rows, or just information about UPDATE/INSERT/DELETE? */ protected boolean reallyResult = false; /** The id (used when profiling) to identify us */ protected int resultId; /** Are we read-only or updatable? */ protected int resultSetConcurrency = 0; /** Are we scroll-sensitive/insensitive? */ protected int resultSetType = 0; /** The actual rows */ protected RowData rowData; // The results /** * Any info message from the server that was created while generating this result set (if 'info parsing' is enabled for the connection). */ protected String serverInfo = null; PreparedStatement statementUsedForFetchingRows; /** Pointer to current row data */ protected ResultSetRow thisRow = null; // Values for current row // 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? */ protected long updateCount; /** Value generated for AUTO_INCREMENT columns */ protected long updateId = -1; private boolean useStrictFloatingPoint = false; protected boolean useUsageAdvisor = false; /** The warning chain */ protected java.sql.SQLWarning warningChain = null; /** Did the previous value retrieval find a NULL? */ protected boolean wasNullFlag = false; protected java.sql.Statement wrapperStatement; protected boolean retainOwningStatement; protected Calendar gmtCalendar = null; protected boolean useFastDateParsing = false; private boolean padCharsWithSpace = false; private boolean jdbcCompliantTruncationForReads; private boolean useFastIntParsing = true; private boolean useColumnNamesInFindColumn; private ExceptionInterceptor exceptionInterceptor; final static char[] EMPTY_SPACE = new char[255]; static { for (int i = 0; i < EMPTY_SPACE.length; i++) { EMPTY_SPACE[i] = ' '; } } protected static ResultSetImpl getInstance(long updateCount, long updateID, MySQLConnection conn, StatementImpl creatorStmt) throws SQLException { if (!Util.isJdbc4()) { return new ResultSetImpl(updateCount, updateID, conn, creatorStmt); } return (ResultSetImpl) Util.handleNewInstance(JDBC_4_RS_4_ARG_CTOR, new Object[] { Long.valueOf(updateCount), Long.valueOf(updateID), conn, creatorStmt }, conn.getExceptionInterceptor()); } /** * Creates a result set instance that represents a query result -- We need * to provide factory-style methods so we can support both JDBC3 (and older) * and JDBC4 runtimes, otherwise the class verifier complains when it tries * to load JDBC4-only interface classes that are present in JDBC4 method * signatures. */ protected static ResultSetImpl getInstance(String catalog, Field[] fields, RowData tuples, MySQLConnection conn, StatementImpl creatorStmt, boolean isUpdatable) throws SQLException { if (!Util.isJdbc4()) { if (!isUpdatable) { return new ResultSetImpl(catalog, fields, tuples, conn, creatorStmt); } return new UpdatableResultSet(catalog, fields, tuples, conn, creatorStmt); } if (!isUpdatable) { return (ResultSetImpl) Util.handleNewInstance(JDBC_4_RS_5_ARG_CTOR, new Object[] { catalog, fields, tuples, conn, creatorStmt }, conn.getExceptionInterceptor()); } return (ResultSetImpl) Util.handleNewInstance(JDBC_4_UPD_RS_5_ARG_CTOR, new Object[] { catalog, fields, tuples, conn, creatorStmt }, conn.getExceptionInterceptor()); } /** * 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 * @param creatorStmt */ public ResultSetImpl(long updateCount, long updateID, MySQLConnection conn, StatementImpl creatorStmt) { this.updateCount = updateCount; this.updateId = updateID; this.reallyResult = false; this.fields = new Field[0]; this.connection = conn; this.owningStatement = creatorStmt; this.retainOwningStatement = false; if (this.connection != null) { this.exceptionInterceptor = this.connection.getExceptionInterceptor(); this.retainOwningStatement = this.connection.getRetainStatementAfterResultSetClose(); this.connectionId = this.connection.getId(); this.serverTimeZoneTz = this.connection.getServerTimezoneTZ(); this.padCharsWithSpace = this.connection.getPadCharsWithSpace(); this.useLegacyDatetimeCode = this.connection.getUseLegacyDatetimeCode(); } } /** * 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 * * @throws SQLException * if an error occurs */ public ResultSetImpl(String catalog, Field[] fields, RowData tuples, MySQLConnection conn, StatementImpl creatorStmt) throws SQLException { this.connection = conn; this.retainOwningStatement = false; if (this.connection != null) { this.exceptionInterceptor = this.connection.getExceptionInterceptor(); this.useStrictFloatingPoint = this.connection.getStrictFloatingPoint(); this.connectionId = this.connection.getId(); this.useFastDateParsing = this.connection.getUseFastDateParsing(); this.profileSql = this.connection.getProfileSql(); this.retainOwningStatement = this.connection.getRetainStatementAfterResultSetClose(); this.jdbcCompliantTruncationForReads = this.connection.getJdbcCompliantTruncationForReads(); this.useFastIntParsing = this.connection.getUseFastIntParsing(); this.serverTimeZoneTz = this.connection.getServerTimezoneTZ(); this.padCharsWithSpace = this.connection.getPadCharsWithSpace(); } this.owningStatement = creatorStmt; this.catalog = catalog; this.fields = fields; this.rowData = tuples; this.updateCount = this.rowData.size(); if (NonRegisteringDriver.DEBUG) { System.out.println(Messages.getString("ResultSet.Retrieved__1") + this.updateCount + " rows"); } 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.fields != null) { initializeWithMetadata(); } // else called by Connection.initializeResultsMetadataFromCache() when cached this.useLegacyDatetimeCode = this.connection.getUseLegacyDatetimeCode(); this.useColumnNamesInFindColumn = this.connection.getUseColumnNamesInFindColumn(); setRowPositionValidity(); } public void initializeWithMetadata() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { this.rowData.setMetadata(this.fields); this.columnToIndexCache = new HashMap(); if (this.profileSql || this.connection.getUseUsageAdvisor()) { this.columnUsed = new boolean[this.fields.length]; this.pointOfOrigin = LogUtils.findCallingClassAndMethod(new Throwable()); this.resultId = resultCounter++; this.useUsageAdvisor = this.connection.getUseUsageAdvisor(); this.eventSink = ProfilerEventHandlerFactory.getInstance(this.connection); } if (this.connection.getGatherPerformanceMetrics()) { this.connection.incrementNumberOfResultSetsCreated(); Set tableNamesSet = new HashSet(); for (int i = 0; i < this.fields.length; i++) { Field f = this.fields[i]; String tableName = f.getOriginalTableName(); if (tableName == null) { tableName = f.getTableName(); } if (tableName != null) { if (this.connection.lowerCaseTableNames()) { tableName = tableName.toLowerCase(); // on windows, table // names are not case-sens. } tableNamesSet.add(tableName); } } this.connection.reportNumberOfTablesAccessed(tableNamesSet.size()); } } } private synchronized Calendar getFastDefaultCalendar() { if (this.fastDefaultCal == null) { this.fastDefaultCal = new GregorianCalendar(Locale.US); this.fastDefaultCal.setTimeZone(this.getDefaultTimeZone()); } return this.fastDefaultCal; } private synchronized Calendar getFastClientCalendar() { if (this.fastClientCal == null) { this.fastClientCal = new GregorianCalendar(Locale.US); } return this.fastClientCal; } /** * JDBC 2.0 * *

* Move to an absolute row number in the result set. *

* *

* 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. *

* *

* 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. *

* *

* 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. *

* *

* Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). *

* * @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. */ public boolean absolute(int row) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { boolean b; if (this.rowData.size() == 0) { b = false; } else { if (this.onInsertRow) { this.onInsertRow = false; } if (this.doingUpdates) { this.doingUpdates = false; } if (this.thisRow != null) { this.thisRow.closeOpenStreams(); } if (row == 0) { beforeFirst(); b = false; } else 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; } } } setRowPositionValidity(); return b; } } /** * JDBC 2.0 * *

* Moves to the end of the result set, just after the last row. Has no effect if the result set contains no rows. *

* * @exception SQLException * if a database-access error occurs, or result set type is * TYPE_FORWARD_ONLY. */ public void afterLast() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if (this.onInsertRow) { this.onInsertRow = false; } if (this.doingUpdates) { this.doingUpdates = false; } if (this.thisRow != null) { this.thisRow.closeOpenStreams(); } if (this.rowData.size() != 0) { this.rowData.afterLast(); this.thisRow = null; } setRowPositionValidity(); } } /** * JDBC 2.0 * *

* Moves to the front of the result set, just before the first row. Has no effect if the result set contains no rows. *

* * @exception SQLException * if a database-access error occurs, or result set type is * TYPE_FORWARD_ONLY */ public void beforeFirst() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if (this.onInsertRow) { this.onInsertRow = false; } if (this.doingUpdates) { this.doingUpdates = false; } if (this.rowData.size() == 0) { return; } if (this.thisRow != null) { this.thisRow.closeOpenStreams(); } this.rowData.beforeFirst(); this.thisRow = null; setRowPositionValidity(); } } // --------------------------------------------------------------------- // Traversal/Positioning // --------------------------------------------------------------------- /** * Builds a hash between column names and their indices for fast retrieval. */ public void buildIndexMapping() throws SQLException { int numFields = this.fields.length; this.columnLabelToIndex = new TreeMap(String.CASE_INSENSITIVE_ORDER); this.fullColumnNameToIndex = new TreeMap(String.CASE_INSENSITIVE_ORDER); this.columnNameToIndex = new TreeMap(String.CASE_INSENSITIVE_ORDER); // 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 = Integer.valueOf(i); String columnName = this.fields[i].getOriginalName(); String columnLabel = this.fields[i].getName(); String fullColumnName = this.fields[i].getFullName(); if (columnLabel != null) { this.columnLabelToIndex.put(columnLabel, index); } if (fullColumnName != null) { this.fullColumnNameToIndex.put(fullColumnName, index); } if (columnName != null) { this.columnNameToIndex.put(columnName, index); } } // set the flag to prevent rebuilding... this.hasBuiltIndexMapping = true; } /** * 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 */ public void cancelRowUpdates() throws SQLException { throw new NotUpdatable(); } /** * Ensures that the result set is not closed * * @throws SQLException * if the result set is closed */ protected final MySQLConnection checkClosed() throws SQLException { MySQLConnection c = this.connection; if (c == null) { throw SQLError.createSQLException(Messages.getString("ResultSet.Operation_not_allowed_after_ResultSet_closed_144"), SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor()); } return c; } /** * 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 */ protected final void checkColumnBounds(int columnIndex) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if ((columnIndex < 1)) { throw SQLError.createSQLException( Messages.getString("ResultSet.Column_Index_out_of_range_low", new Object[] { Integer.valueOf(columnIndex), Integer.valueOf(this.fields.length) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } else if ((columnIndex > this.fields.length)) { throw SQLError.createSQLException( Messages.getString("ResultSet.Column_Index_out_of_range_high", new Object[] { Integer.valueOf(columnIndex), Integer.valueOf(this.fields.length) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } if (this.profileSql || this.useUsageAdvisor) { this.columnUsed[columnIndex - 1] = true; } } } /** * 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 */ protected void checkRowPos() throws SQLException { checkClosed(); if (!this.onValidRow) { throw SQLError.createSQLException(this.invalidRowReason, SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor()); } } private boolean onValidRow = false; private String invalidRowReason = null; protected boolean useLegacyDatetimeCode; private TimeZone serverTimeZoneTz; private void setRowPositionValidity() throws SQLException { if (!this.rowData.isDynamic() && (this.rowData.size() == 0)) { this.invalidRowReason = Messages.getString("ResultSet.Illegal_operation_on_empty_result_set"); this.onValidRow = false; } else if (this.rowData.isBeforeFirst()) { this.invalidRowReason = Messages.getString("ResultSet.Before_start_of_result_set_146"); this.onValidRow = false; } else if (this.rowData.isAfterLast()) { this.invalidRowReason = Messages.getString("ResultSet.After_end_of_result_set_148"); this.onValidRow = false; } else { this.onValidRow = true; this.invalidRowReason = null; } } /** * We can't do this ourselves, otherwise the contract for * Statement.getMoreResults() won't work correctly. */ public synchronized void clearNextResult() { this.nextResultSet = null; } /** * After this call, getWarnings returns null until a new warning is reported * for this ResultSet * * @exception SQLException * if a database access error occurs */ public void clearWarnings() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { 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. * *

* Note: 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. *

* * @exception SQLException * if a database access error occurs */ public void close() throws SQLException { realClose(true); } private int convertToZeroWithEmptyCheck() throws SQLException { if (this.connection.getEmptyStringsConvertToZero()) { return 0; } throw SQLError.createSQLException("Can't convert empty string ('') to numeric", SQLError.SQL_STATE_INVALID_CHARACTER_VALUE_FOR_CAST, getExceptionInterceptor()); } private String convertToZeroLiteralStringWithEmptyCheck() throws SQLException { if (this.connection.getEmptyStringsConvertToZero()) { return "0"; } throw SQLError.createSQLException("Can't convert empty string ('') to numeric", SQLError.SQL_STATE_INVALID_CHARACTER_VALUE_FOR_CAST, getExceptionInterceptor()); } // // Note, row data is linked between these two result sets // public ResultSetInternalMethods copy() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { ResultSetImpl rs = ResultSetImpl.getInstance(this.catalog, this.fields, this.rowData, this.connection, this.owningStatement, false); // note, doesn't work for updatable result sets if (this.isBinaryEncoded) { rs.setBinaryEncoded(); } return rs; } } public void redefineFieldsForDBMD(Field[] f) { this.fields = f; for (int i = 0; i < this.fields.length; i++) { this.fields[i].setUseOldNameMetadata(true); this.fields[i].setConnection(this.connection); } } public void populateCachedMetaData(CachedResultSetMetaData cachedMetaData) throws SQLException { cachedMetaData.fields = this.fields; cachedMetaData.columnNameToIndex = this.columnLabelToIndex; cachedMetaData.fullColumnNameToIndex = this.fullColumnNameToIndex; cachedMetaData.metadata = getMetaData(); } public void initializeFromCachedMetaData(CachedResultSetMetaData cachedMetaData) { this.fields = cachedMetaData.fields; this.columnLabelToIndex = cachedMetaData.columnNameToIndex; this.fullColumnNameToIndex = cachedMetaData.fullColumnNameToIndex; this.hasBuiltIndexMapping = 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 */ public void deleteRow() throws SQLException { throw new NotUpdatable(); } /** * @param columnIndex * @param stringVal * @param mysqlType * @throws SQLException */ private String extractStringFromNativeColumn(int columnIndex, int mysqlType) throws SQLException { int columnIndexMinusOne = columnIndex - 1; this.wasNullFlag = false; if (this.thisRow.isNull(columnIndexMinusOne)) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; String encoding = this.fields[columnIndexMinusOne].getEncoding(); return this.thisRow.getString(columnIndex - 1, encoding, this.connection); } protected Date fastDateCreate(Calendar cal, int year, int month, int day) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { Calendar targetCalendar = cal; if (cal == null) { if (this.connection.getNoTimezoneConversionForDateType()) { targetCalendar = getFastClientCalendar(); } else { targetCalendar = getFastDefaultCalendar(); } } if (!this.useLegacyDatetimeCode) { return TimeUtil.fastDateCreate(year, month, day, targetCalendar); } boolean useGmtMillis = cal == null && !this.connection.getNoTimezoneConversionForDateType() && this.connection.getUseGmtMillisForDatetimes(); return TimeUtil.fastDateCreate(useGmtMillis, useGmtMillis ? getGmtCalendar() : targetCalendar, targetCalendar, year, month, day); } } protected Time fastTimeCreate(Calendar cal, int hour, int minute, int second) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if (!this.useLegacyDatetimeCode) { return TimeUtil.fastTimeCreate(hour, minute, second, cal, getExceptionInterceptor()); } if (cal == null) { cal = getFastDefaultCalendar(); } return TimeUtil.fastTimeCreate(cal, hour, minute, second, getExceptionInterceptor()); } } protected Timestamp fastTimestampCreate(Calendar cal, int year, int month, int day, int hour, int minute, int seconds, int secondsPart) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if (!this.useLegacyDatetimeCode) { return TimeUtil.fastTimestampCreate(cal.getTimeZone(), year, month, day, hour, minute, seconds, secondsPart); } if (cal == null) { cal = getFastDefaultCalendar(); } boolean useGmtMillis = this.connection.getUseGmtMillisForDatetimes(); return TimeUtil.fastTimestampCreate(useGmtMillis, useGmtMillis ? getGmtCalendar() : null, cal, year, month, day, hour, minute, seconds, secondsPart); } } /* * /** * Required by JDBC spec */ /* * protected void finalize() throws Throwable { * if (!this.isClosed) { * realClose(false); * } * } */ // --------------------------JDBC 2.0----------------------------------- // --------------------------------------------------------------------- // Getter's and Setter's // --------------------------------------------------------------------- /* * [For JDBC-3.0 and older - http://java.sun.com/j2se/1.5.0/docs/api/java/sql/ResultSet.html#findColumn(java.lang.String)] * 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 * * [For JDBC-4.0 and newer - http://java.sun.com/javase/6/docs/api/java/sql/ResultSet.html#findColumn(java.lang.String)] * * Maps the given ResultSet column label to its ResultSet column index. * * @param columnLabel * the label for the column specified with the SQL AS clause. If the * SQL AS clause was not specified, then the label is the name of the column * * @return the column index of the given column name */ public int findColumn(String columnName) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { Integer index; if (!this.hasBuiltIndexMapping) { buildIndexMapping(); } index = this.columnToIndexCache.get(columnName); if (index != null) { return index.intValue() + 1; } index = this.columnLabelToIndex.get(columnName); if (index == null && this.useColumnNamesInFindColumn) { index = this.columnNameToIndex.get(columnName); } if (index == null) { index = this.fullColumnNameToIndex.get(columnName); } if (index != null) { this.columnToIndexCache.put(columnName, index); 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 SQLError.createSQLException(Messages.getString("ResultSet.Column____112") + columnName + Messages.getString("ResultSet.___not_found._113"), SQLError.SQL_STATE_COLUMN_NOT_FOUND, getExceptionInterceptor()); } } /** * JDBC 2.0 * *

* Moves to the first row in the result set. *

* * @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. */ public boolean first() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { boolean b = true; if (this.rowData.isEmpty()) { b = false; } else { if (this.onInsertRow) { this.onInsertRow = false; } if (this.doingUpdates) { this.doingUpdates = false; } this.rowData.beforeFirst(); this.thisRow = this.rowData.next(); } setRowPositionValidity(); 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 */ public java.sql.Array getArray(int i) throws SQLException { checkColumnBounds(i); throw SQLError.createSQLFeatureNotSupportedException(); } /** * 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 */ public java.sql.Array getArray(String colName) throws SQLException { return getArray(findColumn(colName)); } /** * 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. * *

* Note: 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. *

* * @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 */ public InputStream getAsciiStream(int columnIndex) throws SQLException { checkRowPos(); if (!this.isBinaryEncoded) { return getBinaryStream(columnIndex); } return getNativeBinaryStream(columnIndex); } /** * @param columnName * * @throws SQLException */ public InputStream getAsciiStream(String columnName) throws SQLException { return getAsciiStream(findColumn(columnName)); } /** * 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. */ 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(convertToZeroLiteralStringWithEmptyCheck()); return val; } try { val = new BigDecimal(stringVal); return val; } catch (NumberFormatException ex) { throw SQLError.createSQLException( Messages.getString("ResultSet.Bad_format_for_BigDecimal", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } return null; } return getNativeBigDecimal(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 * * @deprecated */ @Deprecated 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(convertToZeroLiteralStringWithEmptyCheck()); try { return val.setScale(scale); } catch (ArithmeticException ex) { try { return val.setScale(scale, BigDecimal.ROUND_HALF_UP); } catch (ArithmeticException arEx) { throw SQLError.createSQLException( Messages.getString("ResultSet.Bad_format_for_BigDecimal", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } } try { val = new BigDecimal(stringVal); } catch (NumberFormatException ex) { if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) { long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex); val = new BigDecimal(valueAsLong); } else { throw SQLError.createSQLException( Messages.getString("ResultSet.Bad_format_for_BigDecimal", new Object[] { Integer.valueOf(columnIndex), stringVal }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } try { return val.setScale(scale); } catch (ArithmeticException ex) { try { return val.setScale(scale, BigDecimal.ROUND_HALF_UP); } catch (ArithmeticException arithEx) { throw SQLError.createSQLException( Messages.getString("ResultSet.Bad_format_for_BigDecimal", new Object[] { Integer.valueOf(columnIndex), stringVal }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } } return null; } return getNativeBigDecimal(columnIndex, scale); } /** * 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 */ public BigDecimal getBigDecimal(String columnName) throws SQLException { return getBigDecimal(findColumn(columnName)); } /** * @param columnName * @param scale * * @throws SQLException * * @deprecated */ @Deprecated public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException { return getBigDecimal(findColumn(columnName), scale); } private final BigDecimal getBigDecimalFromString(String stringVal, int columnIndex, int scale) throws SQLException { BigDecimal bdVal; if (stringVal != null) { if (stringVal.length() == 0) { bdVal = new BigDecimal(convertToZeroLiteralStringWithEmptyCheck()); try { return bdVal.setScale(scale); } catch (ArithmeticException ex) { try { return bdVal.setScale(scale, BigDecimal.ROUND_HALF_UP); } catch (ArithmeticException arEx) { throw new SQLException( Messages.getString("ResultSet.Bad_format_for_BigDecimal", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } } } 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", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } } } catch (NumberFormatException ex) { if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) { long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex); try { return new BigDecimal(valueAsLong).setScale(scale); } catch (ArithmeticException arEx1) { try { return new BigDecimal(valueAsLong).setScale(scale, BigDecimal.ROUND_HALF_UP); } catch (ArithmeticException arEx2) { throw new SQLException( Messages.getString("ResultSet.Bad_format_for_BigDecimal", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } } } if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_TINY && this.connection.getTinyInt1isBit() && this.fields[columnIndex - 1].getLength() == 1) { return new BigDecimal(stringVal.equalsIgnoreCase("true") ? 1 : 0).setScale(scale); } throw new SQLException(Messages.getString("ResultSet.Bad_format_for_BigDecimal", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } } return null; } /** * A column value can also be retrieved as a binary stream. 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 */ public InputStream getBinaryStream(int columnIndex) throws SQLException { checkRowPos(); if (!this.isBinaryEncoded) { checkColumnBounds(columnIndex); int columnIndexMinusOne = columnIndex - 1; if (this.thisRow.isNull(columnIndexMinusOne)) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; return this.thisRow.getBinaryInputStream(columnIndexMinusOne); } return getNativeBinaryStream(columnIndex); } /** * @param columnName * * @throws SQLException */ 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. */ public java.sql.Blob getBlob(int columnIndex) throws SQLException { if (!this.isBinaryEncoded) { checkRowPos(); checkColumnBounds(columnIndex); int columnIndexMinusOne = columnIndex - 1; if (this.thisRow.isNull(columnIndexMinusOne)) { this.wasNullFlag = true; } else { this.wasNullFlag = false; } if (this.wasNullFlag) { return null; } if (!this.connection.getEmulateLocators()) { return new Blob(this.thisRow.getColumnValue(columnIndexMinusOne), getExceptionInterceptor()); } return new BlobFromLocator(this, columnIndex, getExceptionInterceptor()); } 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. */ 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 */ public boolean getBoolean(int columnIndex) throws SQLException { 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) { return byteArrayToBoolean(columnIndexMinusOne); } this.wasNullFlag = false; int sqlType = field.getSQLType(); switch (sqlType) { case Types.BOOLEAN: if (field.getMysqlType() == -1) { // from dbmd String stringVal = getString(columnIndex); return getBooleanFromString(stringVal); } long boolVal = getLong(columnIndex, false); return (boolVal == -1 || boolVal > 0); 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: boolVal = getLong(columnIndex, false); return (boolVal == -1 || boolVal > 0); default: if (this.connection.getPedantic()) { // Table B-6 from JDBC spec switch (sqlType) { case Types.BINARY: case Types.VARBINARY: case Types.LONGVARBINARY: case Types.DATE: case Types.TIME: case Types.TIMESTAMP: case Types.CLOB: case Types.BLOB: case Types.ARRAY: case Types.REF: case Types.DATALINK: case Types.STRUCT: case Types.JAVA_OBJECT: throw SQLError.createSQLException("Required type conversion not allowed", SQLError.SQL_STATE_INVALID_CHARACTER_VALUE_FOR_CAST, getExceptionInterceptor()); } } if (sqlType == Types.BINARY || sqlType == Types.VARBINARY || sqlType == Types.LONGVARBINARY || sqlType == Types.BLOB) { return byteArrayToBoolean(columnIndexMinusOne); } if (this.useUsageAdvisor) { issueConversionViaParsingWarning("getBoolean()", columnIndex, this.thisRow.getColumnValue(columnIndexMinusOne), this.fields[columnIndex], new int[] { MysqlDefs.FIELD_TYPE_BIT, 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 = getString(columnIndex); return getBooleanFromString(stringVal); } } private boolean byteArrayToBoolean(int columnIndexMinusOne) throws SQLException { Object value = this.thisRow.getColumnValue(columnIndexMinusOne); if (value == null) { this.wasNullFlag = true; return false; } this.wasNullFlag = false; if (((byte[]) value).length == 0) { return false; } byte boolVal = ((byte[]) value)[0]; if (boolVal == (byte) '1') { return true; } else if (boolVal == (byte) '0') { return false; } return (boolVal == -1 || boolVal > 0); } /** * @param columnName * * @throws SQLException */ public boolean getBoolean(String columnName) throws SQLException { return getBoolean(findColumn(columnName)); } private final boolean getBooleanFromString(String stringVal) 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; } /** * 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 */ 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); } /** * @param columnName * * @throws SQLException */ public byte getByte(String columnName) throws SQLException { return getByte(findColumn(columnName)); } private final byte getByteFromString(String stringVal, int columnIndex) throws SQLException { if (stringVal != null && stringVal.length() == 0) { return (byte) convertToZeroWithEmptyCheck(); } // // JDK-6 doesn't like trailing whitespace // // Note this isn't a performance issue, other than the iteration over the string, as String.trim() will return a new string only if whitespace is // present // if (stringVal == null) { return 0; } stringVal = stringVal.trim(); try { int decimalIndex = stringVal.indexOf("."); if (decimalIndex != -1) { double valueAsDouble = Double.parseDouble(stringVal); if (this.jdbcCompliantTruncationForReads) { if (valueAsDouble < Byte.MIN_VALUE || valueAsDouble > Byte.MAX_VALUE) { throwRangeException(stringVal, columnIndex, Types.TINYINT); } } return (byte) valueAsDouble; } long valueAsLong = Long.parseLong(stringVal); if (this.jdbcCompliantTruncationForReads) { if (valueAsLong < Byte.MIN_VALUE || valueAsLong > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), columnIndex, Types.TINYINT); } } return (byte) valueAsLong; } catch (NumberFormatException NFE) { throw SQLError.createSQLException( Messages.getString("ResultSet.Value____173") + stringVal + Messages.getString("ResultSet.___is_out_of_range_[-127,127]_174"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } /** * Get the value of a column in the current row as a Java byte array. * *

* Be warned If the blob is huge, then you may run out of memory. *

* * @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 */ public byte[] getBytes(int columnIndex) throws SQLException { return getBytes(columnIndex, false); } protected byte[] getBytes(int columnIndex, boolean noConversion) throws SQLException { if (!this.isBinaryEncoded) { checkRowPos(); checkColumnBounds(columnIndex); int columnIndexMinusOne = columnIndex - 1; if (this.thisRow.isNull(columnIndexMinusOne)) { this.wasNullFlag = true; } else { this.wasNullFlag = false; } if (this.wasNullFlag) { return null; } return this.thisRow.getColumnValue(columnIndexMinusOne); } return getNativeBytes(columnIndex, noConversion); } /** * @param columnName * * @throws SQLException */ public byte[] getBytes(String columnName) throws SQLException { return getBytes(findColumn(columnName)); } private final byte[] getBytesFromString(String stringVal) throws SQLException { if (stringVal != null) { return StringUtils.getBytes(stringVal, this.connection.getEncoding(), this.connection.getServerCharset(), this.connection.parserKnowsUnicode(), this.connection, getExceptionInterceptor()); } return null; } public int getBytesSize() throws SQLException { RowData localRowData = this.rowData; checkClosed(); if (localRowData instanceof RowDataStatic) { int bytesSize = 0; int numRows = localRowData.size(); for (int i = 0; i < numRows; i++) { bytesSize += localRowData.getAt(i).getBytesSize(); } return bytesSize; } return -1; } /** * Optimization to only use one calendar per-session, or calculate it for * each call, depending on user configuration */ protected Calendar getCalendarInstanceForSessionOrNew() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if (this.connection != null) { return this.connection.getCalendarInstanceForSessionOrNew(); } // punt, no connection around return new GregorianCalendar(); } } /** * JDBC 2.0 * *

* Get the value of a column in the current row as a java.io.Reader. *

* * @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 */ public java.io.Reader getCharacterStream(int columnIndex) throws SQLException { if (!this.isBinaryEncoded) { checkColumnBounds(columnIndex); int columnIndexMinusOne = columnIndex - 1; if (this.thisRow.isNull(columnIndexMinusOne)) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; return this.thisRow.getReader(columnIndexMinusOne); } return getNativeCharacterStream(columnIndex); } /** * JDBC 2.0 * *

* Get the value of a column in the current row as a java.io.Reader. *

* * @param columnName * the column name to retrieve the value from * * @return the value as a java.io.Reader * * @throws SQLException * if an error occurs */ public java.io.Reader getCharacterStream(String columnName) throws SQLException { return getCharacterStream(findColumn(columnName)); } private final java.io.Reader getCharacterStreamFromString(String stringVal) throws SQLException { if (stringVal != null) { return new StringReader(stringVal); } return null; } /** * 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 */ public java.sql.Clob getClob(int i) throws SQLException { if (!this.isBinaryEncoded) { String asString = getStringForClob(i); if (asString == null) { return null; } return new com.mysql.jdbc.Clob(asString, getExceptionInterceptor()); } 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 */ public java.sql.Clob getClob(String colName) throws SQLException { return getClob(findColumn(colName)); } private final java.sql.Clob getClobFromString(String stringVal) throws SQLException { return new com.mysql.jdbc.Clob(stringVal, getExceptionInterceptor()); } /** * 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 */ public int getConcurrency() throws SQLException { return (CONCUR_READ_ONLY); } /** * Get the name of the SQL cursor used by this ResultSet * *

* 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. *

* *

* 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. *

* *

* Note: If positioned update is not supported, a SQLException is thrown. *

* * @return the ResultSet's SQL cursor name. * * @exception SQLException * if a database access error occurs */ public String getCursorName() throws SQLException { throw SQLError.createSQLException(Messages.getString("ResultSet.Positioned_Update_not_supported"), SQLError.SQL_STATE_DRIVER_NOT_CAPABLE, getExceptionInterceptor()); } /** * 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 */ public java.sql.Date getDate(int columnIndex) throws java.sql.SQLException { return getDate(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 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. */ public java.sql.Date getDate(int columnIndex, Calendar cal) throws SQLException { if (this.isBinaryEncoded) { return getNativeDate(columnIndex, cal); } if (!this.useFastDateParsing) { String stringVal = getStringInternal(columnIndex, false); if (stringVal == null) { return null; } return getDateFromString(stringVal, columnIndex, cal); } checkColumnBounds(columnIndex); int columnIndexMinusOne = columnIndex - 1; Date tmpDate = this.thisRow.getDateFast(columnIndexMinusOne, this.connection, this, cal); if ((this.thisRow.isNull(columnIndexMinusOne)) || (tmpDate == null)) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; return tmpDate; } /** * @param columnName * * @throws java.sql.SQLException */ public java.sql.Date getDate(String columnName) throws java.sql.SQLException { return getDate(findColumn(columnName)); } /** * 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. */ public java.sql.Date getDate(String columnName, Calendar cal) throws SQLException { return getDate(findColumn(columnName), cal); } private final java.sql.Date getDateFromString(String stringVal, int columnIndex, Calendar targetCalendar) throws SQLException { int year = 0; int month = 0; int day = 0; try { this.wasNullFlag = false; if (stringVal == null) { this.wasNullFlag = true; return null; } // // JDK-6 doesn't like trailing whitespace // // Note this isn't a performance issue, other than the iteration over the string, as String.trim() will return a new string only if whitespace is // present // stringVal = stringVal.trim(); // truncate fractional part int dec = stringVal.indexOf("."); if (dec > -1) { stringVal = stringVal.substring(0, dec); } if (stringVal.equals("0") || stringVal.equals("0000-00-00") || stringVal.equals("0000-00-00 00:00:00") || stringVal.equals("00000000000000") || stringVal.equals("0")) { if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL.equals(this.connection.getZeroDateTimeBehavior())) { this.wasNullFlag = true; return null; } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION.equals(this.connection.getZeroDateTimeBehavior())) { throw SQLError.createSQLException("Value '" + stringVal + "' can not be represented as java.sql.Date", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } // We're left with the case of 'round' to a date Java _can_ represent, which is '0001-01-01'. return fastDateCreate(targetCalendar, 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(targetCalendar, 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(targetCalendar, 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(targetCalendar, 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(targetCalendar, year + 1900, month, 1); } case 2: { year = Integer.parseInt(stringVal.substring(0, 2)); if (year <= 69) { year = year + 100; } return fastDateCreate(targetCalendar, year + 1900, 1, 1); } default: throw SQLError.createSQLException( Messages.getString("ResultSet.Bad_format_for_Date", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } else if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR) { if (stringVal.length() == 2 || stringVal.length() == 1) { year = Integer.parseInt(stringVal); if (year <= 69) { year = year + 100; } year += 1900; } else { year = Integer.parseInt(stringVal.substring(0, 4)); } return fastDateCreate(targetCalendar, year, 1, 1); } else if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_TIME) { return fastDateCreate(targetCalendar, 1970, 1, 1); // Return EPOCH } else { if (stringVal.length() < 10) { if (stringVal.length() == 8) { return fastDateCreate(targetCalendar, 1970, 1, 1); // Return EPOCH for TIME } throw SQLError.createSQLException( Messages.getString("ResultSet.Bad_format_for_Date", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } if (stringVal.length() != 18) { year = Integer.parseInt(stringVal.substring(0, 4)); month = Integer.parseInt(stringVal.substring(5, 7)); day = Integer.parseInt(stringVal.substring(8, 10)); } else { // JDK-1.3 timestamp format, not real easy to parse positionally :p StringTokenizer st = new StringTokenizer(stringVal, "- "); year = Integer.parseInt(st.nextToken()); month = Integer.parseInt(st.nextToken()); day = Integer.parseInt(st.nextToken()); } } return fastDateCreate(targetCalendar, year, month, day); } catch (SQLException sqlEx) { throw sqlEx; // don't re-wrap } catch (Exception e) { SQLException sqlEx = SQLError.createSQLException( Messages.getString("ResultSet.Bad_format_for_Date", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); sqlEx.initCause(e); throw sqlEx; } } private TimeZone getDefaultTimeZone() { return this.useLegacyDatetimeCode ? this.connection.getDefaultTimeZone() : this.serverTimeZoneTz; } /** * 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 */ public double getDouble(int columnIndex) throws SQLException { if (!this.isBinaryEncoded) { return getDoubleInternal(columnIndex); } return getNativeDouble(columnIndex); } /** * @param columnName * * @throws SQLException */ public double getDouble(String columnName) throws SQLException { return getDouble(findColumn(columnName)); } private final double getDoubleFromString(String stringVal, int columnIndex) throws SQLException { return getDoubleInternal(stringVal, columnIndex); } /** * 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 */ 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 */ protected double getDoubleInternal(String stringVal, int colIndex) throws SQLException { try { if ((stringVal == null)) { return 0; } if (stringVal.length() == 0) { return convertToZeroWithEmptyCheck(); } 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) { if (this.fields[colIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) { long valueAsLong = getNumericRepresentationOfSQLBitType(colIndex); return valueAsLong; } throw SQLError.createSQLException(Messages.getString("ResultSet.Bad_format_for_number", new Object[] { stringVal, Integer.valueOf(colIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } /** * 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 */ public int getFetchDirection() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { return this.fetchDirection; } } /** * 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 */ public int getFetchSize() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { return this.fetchSize; } } /** * Returns the first character of the query that this result set was created * from. * * @return the first character of the query...uppercased */ public char getFirstCharOfQuery() { try { synchronized (checkClosed().getConnectionMutex()) { return this.firstCharOfQuery; } } catch (SQLException e) { throw new RuntimeException(e); // FIXME: Need to evolve interface } } /** * 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 */ public float getFloat(int columnIndex) throws SQLException { if (!this.isBinaryEncoded) { String val = null; val = getString(columnIndex); return getFloatFromString(val, columnIndex); } return getNativeFloat(columnIndex); } /** * @param columnName * * @throws SQLException */ public float getFloat(String columnName) throws SQLException { return getFloat(findColumn(columnName)); } private final float getFloatFromString(String val, int columnIndex) throws SQLException { try { if ((val != null)) { if (val.length() == 0) { return convertToZeroWithEmptyCheck(); } float f = Float.parseFloat(val); if (this.jdbcCompliantTruncationForReads) { if (f == Float.MIN_VALUE || f == Float.MAX_VALUE) { double valAsDouble = Double.parseDouble(val); // Straight comparison is not reliable when at absolute endpoints of Float.MIN_VALUE or Float.MAX_VALUE, so use epsillons with DOUBLEs if ((valAsDouble < Float.MIN_VALUE - MIN_DIFF_PREC) || (valAsDouble > Float.MAX_VALUE - MAX_DIFF_PREC)) { throwRangeException(String.valueOf(valAsDouble), columnIndex, Types.FLOAT); } } } return f; } return 0; // for NULL } catch (NumberFormatException nfe) { try { Double valueAsDouble = new Double(val); float valueAsFloat = valueAsDouble.floatValue(); if (this.jdbcCompliantTruncationForReads) { if (this.jdbcCompliantTruncationForReads && valueAsFloat == Float.NEGATIVE_INFINITY || valueAsFloat == Float.POSITIVE_INFINITY) { throwRangeException(valueAsDouble.toString(), columnIndex, Types.FLOAT); } } return valueAsFloat; } catch (NumberFormatException newNfe) { // ignore, it's not a number } throw SQLError.createSQLException(Messages.getString("ResultSet.Invalid_value_for_getFloat()_-____200") + val + Messages.getString("ResultSet.___in_column__201") + columnIndex, SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } /** * 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 */ public int getInt(int columnIndex) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); if (!this.isBinaryEncoded) { int columnIndexMinusOne = columnIndex - 1; if (this.thisRow.isNull(columnIndexMinusOne)) { this.wasNullFlag = true; return 0; } this.wasNullFlag = false; if (this.fields[columnIndexMinusOne].getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) { long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex); if (this.jdbcCompliantTruncationForReads && (valueAsLong < Integer.MIN_VALUE || valueAsLong > Integer.MAX_VALUE)) { throwRangeException(String.valueOf(valueAsLong), columnIndex, Types.INTEGER); } return (int) valueAsLong; } if (this.useFastIntParsing) { if (this.thisRow.length(columnIndexMinusOne) == 0) { return convertToZeroWithEmptyCheck(); } boolean needsFullParse = this.thisRow.isFloatingPointNumber(columnIndexMinusOne); if (!needsFullParse) { try { return getIntWithOverflowCheck(columnIndexMinusOne); } catch (NumberFormatException nfe) { try { return parseIntAsDouble(columnIndex, this.thisRow.getString(columnIndexMinusOne, this.fields[columnIndexMinusOne].getEncoding(), this.connection)); } catch (NumberFormatException newNfe) { // ignore, it's not a number } throw SQLError.createSQLException( Messages.getString("ResultSet.Invalid_value_for_getInt()_-____74") + this.thisRow.getString(columnIndexMinusOne, this.fields[columnIndexMinusOne].getEncoding(), this.connection) + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } } String val = null; try { val = getString(columnIndex); if ((val == null)) { return 0; } if (val.length() == 0) { return convertToZeroWithEmptyCheck(); } if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1) && (val.indexOf(".") == -1)) { int intVal = Integer.parseInt(val); checkForIntegerTruncation(columnIndexMinusOne, null, intVal); return intVal; } // Convert floating point int intVal = parseIntAsDouble(columnIndex, val); checkForIntegerTruncation(columnIndex, null, intVal); return intVal; } catch (NumberFormatException nfe) { try { return parseIntAsDouble(columnIndex, val); } catch (NumberFormatException newNfe) { // ignore, it's not a number } throw SQLError.createSQLException(Messages.getString("ResultSet.Invalid_value_for_getInt()_-____74") + val + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } return getNativeInt(columnIndex); } /** * @param columnName * * @throws SQLException */ public int getInt(String columnName) throws SQLException { return getInt(findColumn(columnName)); } private final int getIntFromString(String val, int columnIndex) throws SQLException { try { if ((val != null)) { if (val.length() == 0) { return convertToZeroWithEmptyCheck(); } if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1) && (val.indexOf(".") == -1)) { // // JDK-6 doesn't like trailing whitespace // // Note this isn't a performance issue, other than the iteration over the string, as String.trim() will return a new string only if // whitespace is present // val = val.trim(); int valueAsInt = Integer.parseInt(val); if (this.jdbcCompliantTruncationForReads) { 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.jdbcCompliantTruncationForReads) { if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), columnIndex, Types.INTEGER); } } return (int) valueAsDouble; } return 0; // for NULL } catch (NumberFormatException nfe) { try { double valueAsDouble = Double.parseDouble(val); if (this.jdbcCompliantTruncationForReads) { 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 SQLError.createSQLException( Messages.getString("ResultSet.Invalid_value_for_getInt()_-____206") + val + Messages.getString("ResultSet.___in_column__207") + columnIndex, SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } /** * 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 */ public long getLong(int columnIndex) throws SQLException { return getLong(columnIndex, true); } private long getLong(int columnIndex, boolean overflowCheck) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); if (!this.isBinaryEncoded) { int columnIndexMinusOne = columnIndex - 1; if (this.thisRow.isNull(columnIndexMinusOne)) { this.wasNullFlag = true; return 0; } this.wasNullFlag = false; if (this.fields[columnIndexMinusOne].getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) { return getNumericRepresentationOfSQLBitType(columnIndex); } if (this.useFastIntParsing) { if (this.thisRow.length(columnIndexMinusOne) == 0) { return convertToZeroWithEmptyCheck(); } boolean needsFullParse = this.thisRow.isFloatingPointNumber(columnIndexMinusOne); if (!needsFullParse) { try { return getLongWithOverflowCheck(columnIndexMinusOne, overflowCheck); } catch (NumberFormatException nfe) { try { return parseLongAsDouble(columnIndexMinusOne, this.thisRow.getString(columnIndexMinusOne, this.fields[columnIndexMinusOne].getEncoding(), this.connection)); } catch (NumberFormatException newNfe) { // ignore, it's not a number } throw SQLError.createSQLException( Messages.getString("ResultSet.Invalid_value_for_getLong()_-____79") + this.thisRow.getString(columnIndexMinusOne, this.fields[columnIndexMinusOne].getEncoding(), this.connection) + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } } String val = null; try { val = getString(columnIndex); if (val == null) { return 0; } if (val.length() == 0) { return convertToZeroWithEmptyCheck(); } if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1)) { return parseLongWithOverflowCheck(columnIndexMinusOne, null, val, overflowCheck); } // Convert floating point return parseLongAsDouble(columnIndexMinusOne, val); } catch (NumberFormatException nfe) { try { return parseLongAsDouble(columnIndexMinusOne, val); } catch (NumberFormatException newNfe) { // ignore, it's not a number } throw SQLError.createSQLException(Messages.getString("ResultSet.Invalid_value_for_getLong()_-____79") + val + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } return getNativeLong(columnIndex, overflowCheck, true); } /** * @param columnName * * @throws SQLException */ public long getLong(String columnName) throws SQLException { return getLong(findColumn(columnName)); } private final long getLongFromString(String val, int columnIndexZeroBased) throws SQLException { try { if ((val != null)) { if (val.length() == 0) { return convertToZeroWithEmptyCheck(); } if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1)) { return parseLongWithOverflowCheck(columnIndexZeroBased, null, val, true); } // Convert floating point return parseLongAsDouble(columnIndexZeroBased, val); } return 0; // for NULL } catch (NumberFormatException nfe) { try { // To do: Warn of over/underflow??? return parseLongAsDouble(columnIndexZeroBased, val); } catch (NumberFormatException newNfe) { // ignore, it's not a number } throw SQLError.createSQLException(Messages.getString("ResultSet.Invalid_value_for_getLong()_-____211") + val + Messages.getString("ResultSet.___in_column__212") + (columnIndexZeroBased + 1), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } /** * 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 */ public java.sql.ResultSetMetaData getMetaData() throws SQLException { checkClosed(); return new com.mysql.jdbc.ResultSetMetaData(this.fields, this.connection.getUseOldAliasMetadataBehavior(), this.connection.getYearIsDateType(), getExceptionInterceptor()); } /** * 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 */ protected java.sql.Array getNativeArray(int i) throws SQLException { throw SQLError.createSQLFeatureNotSupportedException(); } /** * 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. * *

* Note: 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. *

* * @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 */ protected InputStream getNativeAsciiStream(int columnIndex) throws SQLException { checkRowPos(); return getNativeBinaryStream(columnIndex); } /** * 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. */ protected BigDecimal getNativeBigDecimal(int columnIndex) throws SQLException { checkColumnBounds(columnIndex); int scale = this.fields[columnIndex - 1].getDecimals(); return getNativeBigDecimal(columnIndex, scale); } /** * 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 */ protected BigDecimal getNativeBigDecimal(int columnIndex, int scale) throws SQLException { checkColumnBounds(columnIndex); String stringVal = null; Field f = this.fields[columnIndex - 1]; Object value = this.thisRow.getColumnValue(columnIndex - 1); if (value == null) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; switch (f.getSQLType()) { case Types.DECIMAL: case Types.NUMERIC: stringVal = StringUtils.toAsciiString((byte[]) value); break; default: stringVal = getNativeString(columnIndex); } return getBigDecimalFromString(stringVal, columnIndex, scale); } /** * A column value can also be retrieved as a binary stream. 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 */ protected InputStream getNativeBinaryStream(int columnIndex) throws SQLException { checkRowPos(); int columnIndexMinusOne = columnIndex - 1; if (this.thisRow.isNull(columnIndexMinusOne)) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; switch (this.fields[columnIndexMinusOne].getSQLType()) { case Types.BIT: case Types.BINARY: case Types.VARBINARY: case Types.BLOB: case Types.LONGVARBINARY: return this.thisRow.getBinaryInputStream(columnIndexMinusOne); } 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. */ protected java.sql.Blob getNativeBlob(int columnIndex) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); Object value = this.thisRow.getColumnValue(columnIndex - 1); if (value == null) { this.wasNullFlag = true; } else { this.wasNullFlag = false; } 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[]) value; break; default: dataAsBytes = getNativeBytes(columnIndex, false); } if (!this.connection.getEmulateLocators()) { return new Blob(dataAsBytes, getExceptionInterceptor()); } return new BlobFromLocator(this, columnIndex, getExceptionInterceptor()); } public static boolean arraysEqual(byte[] left, byte[] right) { if (left == null) { return right == null; } if (right == null) { return false; } if (left.length != right.length) { return false; } for (int i = 0; i < left.length; i++) { if (left[i] != right[i]) { return false; } } return true; } /** * 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 */ protected byte getNativeByte(int columnIndex) throws SQLException { return getNativeByte(columnIndex, true); } protected byte getNativeByte(int columnIndex, boolean overflowCheck) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); Object value = this.thisRow.getColumnValue(columnIndex - 1); if (value == null) { this.wasNullFlag = true; return 0; } this.wasNullFlag = false; columnIndex--; Field field = this.fields[columnIndex]; switch (field.getMysqlType()) { case MysqlDefs.FIELD_TYPE_BIT: long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex + 1); if (overflowCheck && this.jdbcCompliantTruncationForReads && (valueAsLong < Byte.MIN_VALUE || valueAsLong > Byte.MAX_VALUE)) { throwRangeException(String.valueOf(valueAsLong), columnIndex + 1, Types.TINYINT); } return (byte) valueAsLong; case MysqlDefs.FIELD_TYPE_TINY: byte valueAsByte = ((byte[]) value)[0]; if (!field.isUnsigned()) { return valueAsByte; } short valueAsShort = (valueAsByte >= 0) ? valueAsByte : (short) (valueAsByte + (short) 256); if (overflowCheck && this.jdbcCompliantTruncationForReads) { if (valueAsShort > Byte.MAX_VALUE) { throwRangeException(String.valueOf(valueAsShort), columnIndex + 1, Types.TINYINT); } } return (byte) valueAsShort; case MysqlDefs.FIELD_TYPE_SHORT: case MysqlDefs.FIELD_TYPE_YEAR: valueAsShort = getNativeShort(columnIndex + 1); if (overflowCheck && this.jdbcCompliantTruncationForReads) { 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, false); if (overflowCheck && this.jdbcCompliantTruncationForReads) { 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 (overflowCheck && this.jdbcCompliantTruncationForReads) { 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 (overflowCheck && this.jdbcCompliantTruncationForReads) { 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: valueAsLong = getNativeLong(columnIndex + 1, false, true); if (overflowCheck && this.jdbcCompliantTruncationForReads) { 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.getColumnValue(columnIndex - 1), 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. * *

* Be warned If the blob is huge, then you may run out of memory. *

* * @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 */ protected byte[] getNativeBytes(int columnIndex, boolean noConversion) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); Object value = this.thisRow.getColumnValue(columnIndex - 1); if (value == null) { this.wasNullFlag = true; } else { this.wasNullFlag = false; } if (this.wasNullFlag) { return null; } Field field = this.fields[columnIndex - 1]; int mysqlType = field.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[]) value; case MysqlDefs.FIELD_TYPE_STRING: case MysqlDefs.FIELD_TYPE_VARCHAR: case MysqlDefs.FIELD_TYPE_VAR_STRING: if (value instanceof byte[]) { return (byte[]) value; } break; default: break; } int sqlType = field.getSQLType(); if (sqlType == Types.VARBINARY || sqlType == Types.BINARY) { return (byte[]) value; } return getBytesFromString(getNativeString(columnIndex)); } /** * JDBC 2.0 * *

* Get the value of a column in the current row as a java.io.Reader. *

* * @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 */ protected java.io.Reader getNativeCharacterStream(int columnIndex) throws SQLException { int columnIndexMinusOne = columnIndex - 1; switch (this.fields[columnIndexMinusOne].getSQLType()) { case Types.CHAR: case Types.VARCHAR: case Types.LONGVARCHAR: case Types.CLOB: if (this.thisRow.isNull(columnIndexMinusOne)) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; return this.thisRow.getReader(columnIndexMinusOne); } String asString = getStringForClob(columnIndex); if (asString == null) { return null; } return getCharacterStreamFromString(asString); } /** * 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 */ protected java.sql.Clob getNativeClob(int columnIndex) throws SQLException { String stringVal = getStringForClob(columnIndex); if (stringVal == null) { return null; } return getClobFromString(stringVal); } private String getNativeConvertToString(int columnIndex, Field field) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { int sqlType = field.getSQLType(); int mysqlType = field.getMysqlType(); switch (sqlType) { case Types.BIT: return String.valueOf(getNumericRepresentationOfSQLBitType(columnIndex)); case Types.BOOLEAN: boolean booleanVal = getBoolean(columnIndex); if (this.wasNullFlag) { return null; } return String.valueOf(booleanVal); case Types.TINYINT: byte tinyintVal = getNativeByte(columnIndex, false); if (this.wasNullFlag) { return null; } if (!field.isUnsigned() || tinyintVal >= 0) { return String.valueOf(tinyintVal); } short unsignedTinyVal = (short) (tinyintVal & 0xff); return String.valueOf(unsignedTinyVal); case Types.SMALLINT: int intVal = getNativeInt(columnIndex, false); if (this.wasNullFlag) { return null; } if (!field.isUnsigned() || intVal >= 0) { return String.valueOf(intVal); } intVal = intVal & 0xffff; return String.valueOf(intVal); case Types.INTEGER: intVal = getNativeInt(columnIndex, false); if (this.wasNullFlag) { return null; } if (!field.isUnsigned() || intVal >= 0 || field.getMysqlType() == MysqlDefs.FIELD_TYPE_INT24) { return String.valueOf(intVal); } long longVal = intVal & 0xffffffffL; return String.valueOf(longVal); case Types.BIGINT: if (!field.isUnsigned()) { longVal = getNativeLong(columnIndex, false, true); if (this.wasNullFlag) { return null; } return String.valueOf(longVal); } longVal = getNativeLong(columnIndex, false, false); 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(this.thisRow.getColumnValue(columnIndex - 1)); BigDecimal val; if (stringVal != null) { this.wasNullFlag = false; if (stringVal.length() == 0) { val = new BigDecimal(0); return val.toString(); } try { val = new BigDecimal(stringVal); } catch (NumberFormatException ex) { throw SQLError.createSQLException( Messages.getString("ResultSet.Bad_format_for_BigDecimal", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } return val.toString(); } this.wasNullFlag = true; 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 (this.connection.getAutoDeserialize()) { 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 SQLError.createSQLException(Messages.getString("ResultSet.Class_not_found___91") + cnfe.toString() + Messages.getString("ResultSet._while_reading_serialized_object_92"), getExceptionInterceptor()); } catch (IOException ex) { obj = data; // not serialized? } } return obj.toString(); } } return extractStringFromNativeColumn(columnIndex, mysqlType); } case Types.DATE: // The YEAR datatype needs to be handled differently here. if (mysqlType == MysqlDefs.FIELD_TYPE_YEAR) { short shortVal = getNativeShort(columnIndex); if (!this.connection.getYearIsDateType()) { if (this.wasNullFlag) { return null; } return String.valueOf(shortVal); } if (field.getLength() == 2) { if (shortVal <= 69) { shortVal = (short) (shortVal + 100); } shortVal += 1900; } return fastDateCreate(null, shortVal, 1, 1).toString(); } if (this.connection.getNoDatetimeStringSync()) { byte[] asBytes = getNativeBytes(columnIndex, true); if (asBytes == null) { return null; } if (asBytes.length == 0 /* * newer versions of the server * seem to do this when they see all-zero datetime data */) { return "0000-00-00"; } int year = (asBytes[0] & 0xff) | ((asBytes[1] & 0xff) << 8); int month = asBytes[2]; int day = asBytes[3]; if (year == 0 && month == 0 && day == 0) { return "0000-00-00"; } } Date dt = getNativeDate(columnIndex); if (dt == null) { return null; } return String.valueOf(dt); case Types.TIME: Time tm = getNativeTime(columnIndex, null, this.connection.getDefaultTimeZone(), false); if (tm == null) { return null; } return String.valueOf(tm); case Types.TIMESTAMP: if (this.connection.getNoDatetimeStringSync()) { byte[] asBytes = getNativeBytes(columnIndex, true); if (asBytes == null) { return null; } if (asBytes.length == 0 /* * newer versions of the server * seem to do this when they see all-zero datetime data */) { return "0000-00-00 00:00:00"; } int year = (asBytes[0] & 0xff) | ((asBytes[1] & 0xff) << 8); int month = asBytes[2]; int day = asBytes[3]; if (year == 0 && month == 0 && day == 0) { return "0000-00-00 00:00:00"; } } Timestamp tstamp = getNativeTimestamp(columnIndex, null, this.connection.getDefaultTimeZone(), 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); } return extractStringFromNativeColumn(columnIndex, mysqlType); default: return extractStringFromNativeColumn(columnIndex, mysqlType); } } } /** * 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 */ 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. */ protected java.sql.Date getNativeDate(int columnIndex, Calendar cal) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); int columnIndexMinusOne = columnIndex - 1; int mysqlType = this.fields[columnIndexMinusOne].getMysqlType(); java.sql.Date dateToReturn = null; if (mysqlType == MysqlDefs.FIELD_TYPE_DATE) { dateToReturn = this.thisRow.getNativeDate(columnIndexMinusOne, this.connection, this, cal); } else { TimeZone tz = (cal != null) ? cal.getTimeZone() : this.getDefaultTimeZone(); boolean rollForward = (tz != null && !tz.equals(this.getDefaultTimeZone())); dateToReturn = (Date) this.thisRow.getNativeDateTimeValue(columnIndexMinusOne, null, Types.DATE, mysqlType, tz, rollForward, this.connection, this); } // // normally, we allow ResultSetImpl methods to check for null first, but with DATETIME values we have this wacky need to support // 0000-00-00 00:00:00 -> NULL, so we have to defer to the RowHolder implementation, and check the return value. // if (dateToReturn == null) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; return dateToReturn; } java.sql.Date getNativeDateViaParseConversion(int columnIndex) throws SQLException { if (this.useUsageAdvisor) { issueConversionViaParsingWarning("getDate()", columnIndex, this.thisRow.getColumnValue(columnIndex - 1), this.fields[columnIndex - 1], new int[] { MysqlDefs.FIELD_TYPE_DATE }); } String stringVal = getNativeString(columnIndex); return getDateFromString(stringVal, columnIndex, null); } /** * 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 */ protected double getNativeDouble(int columnIndex) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); columnIndex--; // / JDBC is 1-based if (this.thisRow.isNull(columnIndex)) { this.wasNullFlag = true; return 0; } this.wasNullFlag = false; Field f = this.fields[columnIndex]; switch (f.getMysqlType()) { case MysqlDefs.FIELD_TYPE_DOUBLE: return this.thisRow.getNativeDouble(columnIndex); case MysqlDefs.FIELD_TYPE_TINY: if (!f.isUnsigned()) { return getNativeByte(columnIndex + 1); } return getNativeShort(columnIndex + 1); case MysqlDefs.FIELD_TYPE_SHORT: case MysqlDefs.FIELD_TYPE_YEAR: if (!f.isUnsigned()) { return getNativeShort(columnIndex + 1); } return getNativeInt(columnIndex + 1); case MysqlDefs.FIELD_TYPE_INT24: case MysqlDefs.FIELD_TYPE_LONG: if (!f.isUnsigned()) { return getNativeInt(columnIndex + 1); } return getNativeLong(columnIndex + 1); case MysqlDefs.FIELD_TYPE_LONGLONG: long valueAsLong = getNativeLong(columnIndex + 1); if (!f.isUnsigned()) { return valueAsLong; } BigInteger asBigInt = convertLongToUlong(valueAsLong); // TODO: Check for overflow return asBigInt.doubleValue(); case MysqlDefs.FIELD_TYPE_FLOAT: return getNativeFloat(columnIndex + 1); case MysqlDefs.FIELD_TYPE_BIT: return getNumericRepresentationOfSQLBitType(columnIndex + 1); default: String stringVal = getNativeString(columnIndex + 1); if (this.useUsageAdvisor) { issueConversionViaParsingWarning("getDouble()", columnIndex, stringVal, 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 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 */ protected float getNativeFloat(int columnIndex) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); columnIndex--; // / JDBC is 1-based if (this.thisRow.isNull(columnIndex)) { this.wasNullFlag = true; return 0; } this.wasNullFlag = false; Field f = this.fields[columnIndex]; switch (f.getMysqlType()) { case MysqlDefs.FIELD_TYPE_BIT: long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex + 1); return valueAsLong; case MysqlDefs.FIELD_TYPE_DOUBLE: // Only foolproof way to check for overflow Not efficient, but if you don't want to be inefficient, use the correct binding for the type! Double valueAsDouble = new Double(getNativeDouble(columnIndex + 1)); float valueAsFloat = valueAsDouble.floatValue(); if (this.jdbcCompliantTruncationForReads && valueAsFloat == Float.NEGATIVE_INFINITY || valueAsFloat == Float.POSITIVE_INFINITY) { throwRangeException(valueAsDouble.toString(), columnIndex + 1, Types.FLOAT); } return (float) getNativeDouble(columnIndex + 1); case MysqlDefs.FIELD_TYPE_TINY: if (!f.isUnsigned()) { return getNativeByte(columnIndex + 1); } return getNativeShort(columnIndex + 1); case MysqlDefs.FIELD_TYPE_SHORT: case MysqlDefs.FIELD_TYPE_YEAR: if (!f.isUnsigned()) { return getNativeShort(columnIndex + 1); } return getNativeInt(columnIndex + 1); case MysqlDefs.FIELD_TYPE_INT24: case MysqlDefs.FIELD_TYPE_LONG: if (!f.isUnsigned()) { return getNativeInt(columnIndex + 1); } return getNativeLong(columnIndex + 1); case MysqlDefs.FIELD_TYPE_LONGLONG: valueAsLong = getNativeLong(columnIndex + 1); if (!f.isUnsigned()) { return valueAsLong; } BigInteger asBigInt = convertLongToUlong(valueAsLong); // TODO: Check for overflow return asBigInt.floatValue(); case MysqlDefs.FIELD_TYPE_FLOAT: return this.thisRow.getNativeFloat(columnIndex); default: String stringVal = getNativeString(columnIndex + 1); if (this.useUsageAdvisor) { issueConversionViaParsingWarning("getFloat()", columnIndex, stringVal, 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 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 */ protected int getNativeInt(int columnIndex) throws SQLException { return getNativeInt(columnIndex, true); } protected int getNativeInt(int columnIndex, boolean overflowCheck) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); columnIndex--; // / JDBC is 1-based if (this.thisRow.isNull(columnIndex)) { this.wasNullFlag = true; return 0; } this.wasNullFlag = false; Field f = this.fields[columnIndex]; switch (f.getMysqlType()) { case MysqlDefs.FIELD_TYPE_BIT: long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex + 1); if (overflowCheck && this.jdbcCompliantTruncationForReads && (valueAsLong < Integer.MIN_VALUE || valueAsLong > Integer.MAX_VALUE)) { throwRangeException(String.valueOf(valueAsLong), columnIndex + 1, Types.INTEGER); } return (int) valueAsLong; case MysqlDefs.FIELD_TYPE_TINY: byte tinyintVal = getNativeByte(columnIndex + 1, false); if (!f.isUnsigned() || tinyintVal >= 0) { return tinyintVal; } return tinyintVal + 256; case MysqlDefs.FIELD_TYPE_SHORT: case MysqlDefs.FIELD_TYPE_YEAR: short asShort = getNativeShort(columnIndex + 1, false); if (!f.isUnsigned() || asShort >= 0) { return asShort; } return asShort + 65536; case MysqlDefs.FIELD_TYPE_INT24: case MysqlDefs.FIELD_TYPE_LONG: int valueAsInt = this.thisRow.getNativeInt(columnIndex); if (!f.isUnsigned()) { return valueAsInt; } valueAsLong = (valueAsInt >= 0) ? valueAsInt : valueAsInt + 4294967296L; if (overflowCheck && this.jdbcCompliantTruncationForReads && valueAsLong > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), columnIndex + 1, Types.INTEGER); } return (int) valueAsLong; case MysqlDefs.FIELD_TYPE_LONGLONG: valueAsLong = getNativeLong(columnIndex + 1, false, true); if (overflowCheck && this.jdbcCompliantTruncationForReads) { 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 (overflowCheck && this.jdbcCompliantTruncationForReads) { 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 (overflowCheck && this.jdbcCompliantTruncationForReads) { if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), columnIndex + 1, Types.INTEGER); } } return (int) valueAsDouble; default: String stringVal = getNativeString(columnIndex + 1); if (this.useUsageAdvisor) { issueConversionViaParsingWarning("getInt()", columnIndex, stringVal, 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 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 */ protected long getNativeLong(int columnIndex) throws SQLException { return getNativeLong(columnIndex, true, true); } protected long getNativeLong(int columnIndex, boolean overflowCheck, boolean expandUnsignedLong) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); columnIndex--; // / JDBC is 1-based if (this.thisRow.isNull(columnIndex)) { this.wasNullFlag = true; return 0; } this.wasNullFlag = false; Field f = this.fields[columnIndex]; switch (f.getMysqlType()) { case MysqlDefs.FIELD_TYPE_BIT: return getNumericRepresentationOfSQLBitType(columnIndex + 1); case MysqlDefs.FIELD_TYPE_TINY: if (!f.isUnsigned()) { return getNativeByte(columnIndex + 1); } return getNativeInt(columnIndex + 1); case MysqlDefs.FIELD_TYPE_SHORT: if (!f.isUnsigned()) { return getNativeShort(columnIndex + 1); } return getNativeInt(columnIndex + 1, false); case MysqlDefs.FIELD_TYPE_YEAR: return getNativeShort(columnIndex + 1); case MysqlDefs.FIELD_TYPE_INT24: case MysqlDefs.FIELD_TYPE_LONG: int asInt = getNativeInt(columnIndex + 1, false); if (!f.isUnsigned() || asInt >= 0) { return asInt; } return asInt + 4294967296L; case MysqlDefs.FIELD_TYPE_LONGLONG: long valueAsLong = this.thisRow.getNativeLong(columnIndex); if (!f.isUnsigned() || !expandUnsignedLong) { return valueAsLong; } BigInteger asBigInt = convertLongToUlong(valueAsLong); if (overflowCheck && this.jdbcCompliantTruncationForReads && ((asBigInt.compareTo(new BigInteger(String.valueOf(Long.MAX_VALUE))) > 0) || (asBigInt.compareTo(new BigInteger(String.valueOf(Long.MIN_VALUE))) < 0))) { throwRangeException(asBigInt.toString(), columnIndex + 1, Types.BIGINT); } return getLongFromString(asBigInt.toString(), columnIndex); case MysqlDefs.FIELD_TYPE_DOUBLE: double valueAsDouble = getNativeDouble(columnIndex + 1); if (overflowCheck && this.jdbcCompliantTruncationForReads) { 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 (overflowCheck && this.jdbcCompliantTruncationForReads) { if (valueAsDouble < Long.MIN_VALUE || valueAsDouble > Long.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), columnIndex + 1, Types.BIGINT); } } return (long) valueAsDouble; default: String stringVal = getNativeString(columnIndex + 1); if (this.useUsageAdvisor) { issueConversionViaParsingWarning("getLong()", columnIndex, stringVal, 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 getLongFromString(stringVal, columnIndex + 1); } } /** * JDBC 2.0 Get a REF(<structured-type>) 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 */ protected java.sql.Ref getNativeRef(int i) throws SQLException { throw SQLError.createSQLFeatureNotSupportedException(); } /** * 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 */ protected short getNativeShort(int columnIndex) throws SQLException { return getNativeShort(columnIndex, true); } protected short getNativeShort(int columnIndex, boolean overflowCheck) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); columnIndex--; // / JDBC is 1-based if (this.thisRow.isNull(columnIndex)) { this.wasNullFlag = true; return 0; } this.wasNullFlag = false; Field f = this.fields[columnIndex]; switch (f.getMysqlType()) { case MysqlDefs.FIELD_TYPE_BIT: long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex + 1); if (overflowCheck && this.jdbcCompliantTruncationForReads && (valueAsLong < Short.MIN_VALUE || valueAsLong > Short.MAX_VALUE)) { throwRangeException(String.valueOf(valueAsLong), columnIndex + 1, Types.SMALLINT); } return (short) valueAsLong; case MysqlDefs.FIELD_TYPE_TINY: byte tinyintVal = getNativeByte(columnIndex + 1, false); if (!f.isUnsigned() || tinyintVal >= 0) { return tinyintVal; } return (short) (tinyintVal + (short) 256); case MysqlDefs.FIELD_TYPE_SHORT: case MysqlDefs.FIELD_TYPE_YEAR: short asShort = this.thisRow.getNativeShort(columnIndex); if (!f.isUnsigned()) { return asShort; } int valueAsInt = asShort & 0xffff; if (overflowCheck && this.jdbcCompliantTruncationForReads && valueAsInt > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsInt), columnIndex + 1, Types.SMALLINT); } return (short) valueAsInt; case MysqlDefs.FIELD_TYPE_INT24: case MysqlDefs.FIELD_TYPE_LONG: if (!f.isUnsigned()) { valueAsInt = getNativeInt(columnIndex + 1, false); if (overflowCheck && this.jdbcCompliantTruncationForReads && valueAsInt > Short.MAX_VALUE || valueAsInt < Short.MIN_VALUE) { throwRangeException(String.valueOf(valueAsInt), columnIndex + 1, Types.SMALLINT); } return (short) valueAsInt; } valueAsLong = getNativeLong(columnIndex + 1, false, true); if (overflowCheck && this.jdbcCompliantTruncationForReads && valueAsLong > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), columnIndex + 1, Types.SMALLINT); } return (short) valueAsLong; case MysqlDefs.FIELD_TYPE_LONGLONG: valueAsLong = getNativeLong(columnIndex + 1, false, false); if (!f.isUnsigned()) { if (overflowCheck && this.jdbcCompliantTruncationForReads) { if (valueAsLong < Short.MIN_VALUE || valueAsLong > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsLong), columnIndex + 1, Types.SMALLINT); } } return (short) valueAsLong; } BigInteger asBigInt = convertLongToUlong(valueAsLong); if (overflowCheck && this.jdbcCompliantTruncationForReads && ((asBigInt.compareTo(new BigInteger(String.valueOf(Short.MAX_VALUE))) > 0) || (asBigInt.compareTo(new BigInteger(String.valueOf(Short.MIN_VALUE))) < 0))) { throwRangeException(asBigInt.toString(), columnIndex + 1, Types.SMALLINT); } return (short) getIntFromString(asBigInt.toString(), columnIndex + 1); case MysqlDefs.FIELD_TYPE_DOUBLE: double valueAsDouble = getNativeDouble(columnIndex + 1); if (overflowCheck && this.jdbcCompliantTruncationForReads) { if (valueAsDouble < Short.MIN_VALUE || valueAsDouble > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), columnIndex + 1, Types.SMALLINT); } } return (short) valueAsDouble; case MysqlDefs.FIELD_TYPE_FLOAT: float valueAsFloat = getNativeFloat(columnIndex + 1); if (overflowCheck && this.jdbcCompliantTruncationForReads) { if (valueAsFloat < Short.MIN_VALUE || valueAsFloat > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsFloat), columnIndex + 1, Types.SMALLINT); } } return (short) valueAsFloat; default: String stringVal = getNativeString(columnIndex + 1); if (this.useUsageAdvisor) { issueConversionViaParsingWarning("getShort()", columnIndex, stringVal, 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 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 */ protected String getNativeString(int columnIndex) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); if (this.fields == null) { throw SQLError.createSQLException(Messages.getString("ResultSet.Query_generated_no_fields_for_ResultSet_133"), SQLError.SQL_STATE_INVALID_COLUMN_NUMBER, getExceptionInterceptor()); } if (this.thisRow.isNull(columnIndex - 1)) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; String stringVal = null; Field field = this.fields[columnIndex - 1]; // TODO: Check Types Here. stringVal = getNativeConvertToString(columnIndex, field); int mysqlType = field.getMysqlType(); if (mysqlType != MysqlDefs.FIELD_TYPE_TIMESTAMP && mysqlType != MysqlDefs.FIELD_TYPE_DATE && field.isZeroFill() && (stringVal != null)) { int origLength = stringVal.length(); StringBuilder zeroFillBuf = new StringBuilder(origLength); long numZeros = field.getLength() - origLength; for (long i = 0; i < numZeros; i++) { zeroFillBuf.append('0'); } zeroFillBuf.append(stringVal); stringVal = zeroFillBuf.toString(); } return stringVal; } private Time getNativeTime(int columnIndex, Calendar targetCalendar, TimeZone tz, boolean rollForward) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); int columnIndexMinusOne = columnIndex - 1; int mysqlType = this.fields[columnIndexMinusOne].getMysqlType(); Time timeVal = null; if (mysqlType == MysqlDefs.FIELD_TYPE_TIME) { timeVal = this.thisRow.getNativeTime(columnIndexMinusOne, targetCalendar, tz, rollForward, this.connection, this); } else { timeVal = (Time) this.thisRow.getNativeDateTimeValue(columnIndexMinusOne, null, Types.TIME, mysqlType, tz, rollForward, this.connection, this); } // // normally, we allow ResultSetImpl methods to check for null first, but with DATETIME values we have this wacky need to support // 0000-00-00 00:00:00 -> NULL, so we have to defer to the RowHolder implementation, and check the return value. // if (timeVal == null) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; return timeVal; } Time getNativeTimeViaParseConversion(int columnIndex, Calendar targetCalendar, TimeZone tz, boolean rollForward) throws SQLException { if (this.useUsageAdvisor) { issueConversionViaParsingWarning("getTime()", columnIndex, this.thisRow.getColumnValue(columnIndex - 1), this.fields[columnIndex - 1], new int[] { MysqlDefs.FIELD_TYPE_TIME }); } String strTime = getNativeString(columnIndex); return getTimeFromString(strTime, targetCalendar, columnIndex, tz, rollForward); } private Timestamp getNativeTimestamp(int columnIndex, Calendar targetCalendar, TimeZone tz, boolean rollForward) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); int columnIndexMinusOne = columnIndex - 1; Timestamp tsVal = null; int mysqlType = this.fields[columnIndexMinusOne].getMysqlType(); switch (mysqlType) { case MysqlDefs.FIELD_TYPE_DATETIME: case MysqlDefs.FIELD_TYPE_TIMESTAMP: tsVal = this.thisRow.getNativeTimestamp(columnIndexMinusOne, targetCalendar, tz, rollForward, this.connection, this); break; default: tsVal = (Timestamp) this.thisRow.getNativeDateTimeValue(columnIndexMinusOne, null, Types.TIMESTAMP, mysqlType, tz, rollForward, this.connection, this); } // // normally, we allow ResultSetImpl methods to check for null first but with DATETIME values we have this wacky need to support // 0000-00-00 00:00:00 -> NULL, so we have to defer to the RowHolder implementation, and check the return value. // if (tsVal == null) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; return tsVal; } Timestamp getNativeTimestampViaParseConversion(int columnIndex, Calendar targetCalendar, TimeZone tz, boolean rollForward) throws SQLException { if (this.useUsageAdvisor) { issueConversionViaParsingWarning("getTimestamp()", columnIndex, this.thisRow.getColumnValue(columnIndex - 1), this.fields[columnIndex - 1], new int[] { MysqlDefs.FIELD_TYPE_TIMESTAMP, MysqlDefs.FIELD_TYPE_DATETIME }); } String strTimestamp = getNativeString(columnIndex); return getTimestampFromString(columnIndex, targetCalendar, strTimestamp, tz, rollForward); } // --------------------------------------------------------------------- // Updates // --------------------------------------------------------------------- /** * 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 */ protected InputStream getNativeUnicodeStream(int columnIndex) throws SQLException { checkRowPos(); return getBinaryStream(columnIndex); } /** * @see ResultSetInternalMethods#getURL(int) */ 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 SQLError.createSQLException(Messages.getString("ResultSet.Malformed_URL____141") + val + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } /** * @return Returns the nextResultSet, if any, null if none exists. */ public synchronized ResultSetInternalMethods getNextResultSet() { return this.nextResultSet; } /** * Get the value of a column in the current row as a Java object * *

* 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. *

* *

* This method may also be used to read database specific abstract data types. *

* * @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 */ public Object getObject(int columnIndex) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); int columnIndexMinusOne = columnIndex - 1; if (this.thisRow.isNull(columnIndexMinusOne)) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; Field field; field = this.fields[columnIndexMinusOne]; switch (field.getSQLType()) { case Types.BIT: if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT && !field.isSingleBit()) { return getObjectDeserializingIfNeeded(columnIndex); } return Boolean.valueOf(getBoolean(columnIndex)); case Types.BOOLEAN: return Boolean.valueOf(getBoolean(columnIndex)); case Types.TINYINT: if (!field.isUnsigned()) { return Integer.valueOf(getByte(columnIndex)); } return Integer.valueOf(getInt(columnIndex)); case Types.SMALLINT: return Integer.valueOf(getInt(columnIndex)); case Types.INTEGER: if (!field.isUnsigned() || field.getMysqlType() == MysqlDefs.FIELD_TYPE_INT24) { return Integer.valueOf(getInt(columnIndex)); } return Long.valueOf(getLong(columnIndex)); case Types.BIGINT: if (!field.isUnsigned()) { return Long.valueOf(getLong(columnIndex)); } String stringVal = getString(columnIndex); if (stringVal == null) { return null; } try { return new BigInteger(stringVal); } catch (NumberFormatException nfe) { throw SQLError.createSQLException( Messages.getString("ResultSet.Bad_format_for_BigInteger", new Object[] { Integer.valueOf(columnIndex), stringVal }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } 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 SQLError.createSQLException( Messages.getString("ResultSet.Bad_format_for_BigDecimal", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } 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: if (!field.isOpaqueBinary()) { return getString(columnIndex); } return getBytes(columnIndex); case Types.LONGVARCHAR: if (!field.isOpaqueBinary()) { return getStringForClob(columnIndex); } return getBytes(columnIndex); case Types.BINARY: case Types.VARBINARY: case Types.LONGVARBINARY: if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_GEOMETRY) { return getBytes(columnIndex); } return getObjectDeserializingIfNeeded(columnIndex); case Types.DATE: if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR && !this.connection.getYearIsDateType()) { return Short.valueOf(getShort(columnIndex)); } return getDate(columnIndex); case Types.TIME: return getTime(columnIndex); case Types.TIMESTAMP: return getTimestamp(columnIndex); default: return getString(columnIndex); } } private Object getObjectDeserializingIfNeeded(int columnIndex) throws SQLException { final Field field = this.fields[columnIndex - 1]; if (field.isBinary() || field.isBlob()) { 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 SQLError.createSQLException(Messages.getString("ResultSet.Class_not_found___91") + cnfe.toString() + Messages.getString("ResultSet._while_reading_serialized_object_92"), getExceptionInterceptor()); } catch (IOException ex) { obj = data; // not serialized? } } else { return getString(columnIndex); } } return obj; } return data; } return getBytes(columnIndex); } @SuppressWarnings("unchecked") public T getObject(int columnIndex, Class type) throws SQLException { if (type == null) { throw SQLError.createSQLException("Type parameter can not be null", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } if (type.equals(String.class)) { return (T) getString(columnIndex); } else if (type.equals(BigDecimal.class)) { return (T) getBigDecimal(columnIndex); } else if (type.equals(Boolean.class) || type.equals(Boolean.TYPE)) { return (T) Boolean.valueOf(getBoolean(columnIndex)); } else if (type.equals(Integer.class) || type.equals(Integer.TYPE)) { return (T) Integer.valueOf(getInt(columnIndex)); } else if (type.equals(Long.class) || type.equals(Long.TYPE)) { return (T) Long.valueOf(getLong(columnIndex)); } else if (type.equals(Float.class) || type.equals(Float.TYPE)) { return (T) Float.valueOf(getFloat(columnIndex)); } else if (type.equals(Double.class) || type.equals(Double.TYPE)) { return (T) Double.valueOf(getDouble(columnIndex)); } else if (type.equals(byte[].class)) { return (T) getBytes(columnIndex); } else if (type.equals(java.sql.Date.class)) { return (T) getDate(columnIndex); } else if (type.equals(Time.class)) { return (T) getTime(columnIndex); } else if (type.equals(Timestamp.class)) { return (T) getTimestamp(columnIndex); } else if (type.equals(Clob.class)) { return (T) getClob(columnIndex); } else if (type.equals(Blob.class)) { return (T) getBlob(columnIndex); } else if (type.equals(Array.class)) { return (T) getArray(columnIndex); } else if (type.equals(Ref.class)) { return (T) getRef(columnIndex); } else if (type.equals(URL.class)) { return (T) getURL(columnIndex); } else { if (this.connection.getAutoDeserialize()) { try { return type.cast(getObject(columnIndex)); } catch (ClassCastException cce) { SQLException sqlEx = SQLError.createSQLException("Conversion not supported for type " + type.getName(), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); sqlEx.initCause(cce); throw sqlEx; } } throw SQLError.createSQLException("Conversion not supported for type " + type.getName(), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } // JDBC-4.1 public T getObject(String columnLabel, Class type) throws SQLException { return getObject(findColumn(columnLabel), type); } /** * 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 */ public Object getObject(int i, java.util.Map> map) throws SQLException { return getObject(i); } /** * Get the value of a column in the current row as a Java object * *

* 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. *

* *

* This method may also be used to read database specific abstract data types. *

* * @param columnName * is the SQL name of the column * * @return a Object holding the column value * * @exception SQLException * if a database access error occurs */ 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 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 */ public Object getObject(String colName, java.util.Map> map) throws SQLException { return getObject(findColumn(colName), map); } public Object getObjectStoredProc(int columnIndex, int desiredSqlType) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); Object value = this.thisRow.getColumnValue(columnIndex - 1); if (value == null) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; Field field; field = this.fields[columnIndex - 1]; switch (desiredSqlType) { case Types.BIT: case Types.BOOLEAN: // valueOf would be nicer here, but it isn't present in JDK-1.3.1, which is what the CTS uses. return Boolean.valueOf(getBoolean(columnIndex)); case Types.TINYINT: return Integer.valueOf(getInt(columnIndex)); case Types.SMALLINT: return Integer.valueOf(getInt(columnIndex)); case Types.INTEGER: if (!field.isUnsigned() || field.getMysqlType() == MysqlDefs.FIELD_TYPE_INT24) { return Integer.valueOf(getInt(columnIndex)); } return Long.valueOf(getLong(columnIndex)); case Types.BIGINT: if (field.isUnsigned()) { return getBigDecimal(columnIndex); } return Long.valueOf(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 SQLError.createSQLException( Messages.getString("ResultSet.Bad_format_for_BigDecimal", new Object[] { stringVal, Integer.valueOf(columnIndex) }), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } return val; } return null; case Types.REAL: return new Float(getFloat(columnIndex)); case Types.FLOAT: if (!this.connection.getRunningCTS13()) { return new Double(getFloat(columnIndex)); } 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: return getString(columnIndex); case Types.LONGVARCHAR: return getStringForClob(columnIndex); case Types.BINARY: case Types.VARBINARY: case Types.LONGVARBINARY: return getBytes(columnIndex); case Types.DATE: if (field.getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR && !this.connection.getYearIsDateType()) { return Short.valueOf(getShort(columnIndex)); } return getDate(columnIndex); case Types.TIME: return getTime(columnIndex); case Types.TIMESTAMP: return getTimestamp(columnIndex); default: return getString(columnIndex); } } public Object getObjectStoredProc(int i, java.util.Map map, int desiredSqlType) throws SQLException { return getObjectStoredProc(i, desiredSqlType); } public Object getObjectStoredProc(String columnName, int desiredSqlType) throws SQLException { return getObjectStoredProc(findColumn(columnName), desiredSqlType); } public Object getObjectStoredProc(String colName, java.util.Map map, int desiredSqlType) throws SQLException { return getObjectStoredProc(findColumn(colName), map, desiredSqlType); } /** * JDBC 2.0 Get a REF(<structured-type>) 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 */ public java.sql.Ref getRef(int i) throws SQLException { checkColumnBounds(i); throw SQLError.createSQLFeatureNotSupportedException(); } /** * JDBC 2.0 Get a REF(<structured-type>) 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 */ public java.sql.Ref getRef(String colName) throws SQLException { return getRef(findColumn(colName)); } /** * JDBC 2.0 * *

* Determine the current row number. The first row is number 1, the second number 2, etc. *

* * @return the current row number, else return 0 if there is no current row * * @exception SQLException * if a database-access error occurs. */ 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; } /** * Returns the server info (if any), or null if none. * * @return server info created for this ResultSet */ public String getServerInfo() { try { synchronized (checkClosed().getConnectionMutex()) { return this.serverInfo; } } catch (SQLException e) { throw new RuntimeException(e); // FIXME: Need to evolve public interface } } private long getNumericRepresentationOfSQLBitType(int columnIndex) throws SQLException { Object value = this.thisRow.getColumnValue(columnIndex - 1); if (this.fields[columnIndex - 1].isSingleBit() || ((byte[]) value).length == 1) { return ((byte[]) value)[0]; } byte[] asBytes = (byte[]) value; int shift = 0; long[] steps = new long[asBytes.length]; for (int i = asBytes.length - 1; i >= 0; i--) { steps[i] = (long) (asBytes[i] & 0xff) << shift; shift += 8; } long valueAsLong = 0; for (int i = 0; i < asBytes.length; i++) { valueAsLong |= steps[i]; } return valueAsLong; } /** * 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 */ public short getShort(int columnIndex) throws SQLException { checkRowPos(); checkColumnBounds(columnIndex); if (!this.isBinaryEncoded) { if (this.thisRow.isNull(columnIndex - 1)) { this.wasNullFlag = true; return 0; } this.wasNullFlag = false; if (this.fields[columnIndex - 1].getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) { long valueAsLong = getNumericRepresentationOfSQLBitType(columnIndex); if (this.jdbcCompliantTruncationForReads && (valueAsLong < Short.MIN_VALUE || valueAsLong > Short.MAX_VALUE)) { throwRangeException(String.valueOf(valueAsLong), columnIndex, Types.SMALLINT); } return (short) valueAsLong; } if (this.useFastIntParsing) { byte[] shortAsBytes = this.thisRow.getColumnValue(columnIndex - 1); if (shortAsBytes.length == 0) { return (short) convertToZeroWithEmptyCheck(); } 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 { return parseShortAsDouble(columnIndex, StringUtils.toString(shortAsBytes)); } catch (NumberFormatException newNfe) { // ignore, it's not a number } throw SQLError.createSQLException( Messages.getString("ResultSet.Invalid_value_for_getShort()_-____96") + StringUtils.toString(shortAsBytes) + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } } String val = null; try { val = getString(columnIndex); if (val == null) { return 0; } if (val.length() == 0) { return (short) convertToZeroWithEmptyCheck(); } if ((val.indexOf("e") == -1) && (val.indexOf("E") == -1) && (val.indexOf(".") == -1)) { return parseShortWithOverflowCheck(columnIndex, null, val); } // Convert floating point return parseShortAsDouble(columnIndex, val); } catch (NumberFormatException nfe) { try { return parseShortAsDouble(columnIndex, val); } catch (NumberFormatException newNfe) { // ignore, it's not a number } throw SQLError.createSQLException(Messages.getString("ResultSet.Invalid_value_for_getShort()_-____96") + val + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } return getNativeShort(columnIndex); } /** * @param columnName * * @throws SQLException */ public short getShort(String columnName) throws SQLException { return getShort(findColumn(columnName)); } private final short getShortFromString(String val, int columnIndex) throws SQLException { try { if ((val != null)) { if (val.length() == 0) { return (short) convertToZeroWithEmptyCheck(); } 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; // for NULL } catch (NumberFormatException nfe) { try { return parseShortAsDouble(columnIndex, val); } catch (NumberFormatException newNfe) { // ignore, it's not a number } throw SQLError.createSQLException(Messages.getString("ResultSet.Invalid_value_for_getShort()_-____217") + val + Messages.getString("ResultSet.___in_column__218") + columnIndex, SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } /** * 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 */ public java.sql.Statement getStatement() throws SQLException { try { synchronized (checkClosed().getConnectionMutex()) { if (this.wrapperStatement != null) { return this.wrapperStatement; } return this.owningStatement; } } catch (SQLException sqlEx) { if (!this.retainOwningStatement) { throw SQLError.createSQLException("Operation not allowed on closed ResultSet. Statements " + "can be retained over result set closure by setting the connection property " + "\"retainStatementAfterResultSetClose\" to \"true\".", SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor()); } 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 */ public String getString(int columnIndex) throws SQLException { String stringVal = getStringInternal(columnIndex, true); if (this.padCharsWithSpace && stringVal != null) { Field f = this.fields[columnIndex - 1]; if (f.getMysqlType() == MysqlDefs.FIELD_TYPE_STRING) { int fieldLength = (int) f.getLength() /* safe, bytes in a CHAR <= 1024 */ / f.getMaxBytesPerCharacter(); /* safe, this will never be 0 */ int currentLength = stringVal.length(); if (currentLength < fieldLength) { StringBuilder paddedBuf = new StringBuilder(fieldLength); paddedBuf.append(stringVal); int difference = fieldLength - currentLength; paddedBuf.append(EMPTY_SPACE, 0, difference); stringVal = paddedBuf.toString(); } } } return stringVal; } /** * 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 */ public String getString(String columnName) throws SQLException { return getString(findColumn(columnName)); } private String getStringForClob(int columnIndex) throws SQLException { String asString = null; String forcedEncoding = this.connection.getClobCharacterEncoding(); if (forcedEncoding == null) { if (!this.isBinaryEncoded) { asString = getString(columnIndex); } else { asString = getNativeString(columnIndex); } } else { try { byte[] asBytes = null; if (!this.isBinaryEncoded) { asBytes = getBytes(columnIndex); } else { asBytes = getNativeBytes(columnIndex, true); } if (asBytes != null) { asString = StringUtils.toString(asBytes, forcedEncoding); } } catch (UnsupportedEncodingException uee) { throw SQLError.createSQLException("Unsupported character encoding " + forcedEncoding, SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } return asString; } protected String getStringInternal(int columnIndex, boolean checkDateTypes) throws SQLException { if (!this.isBinaryEncoded) { checkRowPos(); checkColumnBounds(columnIndex); if (this.fields == null) { throw SQLError.createSQLException(Messages.getString("ResultSet.Query_generated_no_fields_for_ResultSet_99"), SQLError.SQL_STATE_INVALID_COLUMN_NUMBER, getExceptionInterceptor()); } // JDBC is 1-based, Java is not !? int internalColumnIndex = columnIndex - 1; if (this.thisRow.isNull(internalColumnIndex)) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; Field metadata = this.fields[internalColumnIndex]; String stringVal = null; if (metadata.getMysqlType() == MysqlDefs.FIELD_TYPE_BIT) { if (metadata.isSingleBit()) { byte[] value = this.thisRow.getColumnValue(internalColumnIndex); if (value.length == 0) { return String.valueOf(convertToZeroWithEmptyCheck()); } return String.valueOf(value[0]); } return String.valueOf(getNumericRepresentationOfSQLBitType(columnIndex)); } String encoding = metadata.getEncoding(); stringVal = this.thisRow.getString(internalColumnIndex, encoding, this.connection); // // Special handling for YEAR type from mysql, some people want it as a DATE, others want to treat it as a SHORT // if (metadata.getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR) { if (!this.connection.getYearIsDateType()) { return stringVal; } Date dt = getDateFromString(stringVal, columnIndex, null); if (dt == null) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; return dt.toString(); } // Handles timezone conversion and zero-date behavior if (checkDateTypes && !this.connection.getNoDatetimeStringSync()) { switch (metadata.getSQLType()) { case Types.TIME: Time tm = getTimeFromString(stringVal, null, columnIndex, 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, null); if (dt == null) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; return dt.toString(); case Types.TIMESTAMP: Timestamp ts = getTimestampFromString(columnIndex, null, 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); } /** * 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 */ public Time getTime(int columnIndex) throws java.sql.SQLException { return getTimeInternal(columnIndex, null, this.getDefaultTimeZone(), false); } /** * 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. */ public java.sql.Time getTime(int columnIndex, Calendar cal) throws SQLException { return getTimeInternal(columnIndex, cal, cal != null ? cal.getTimeZone() : this.getDefaultTimeZone(), true); } /** * 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. */ 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 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. */ public java.sql.Time getTime(String columnName, Calendar cal) throws SQLException { return getTime(findColumn(columnName), cal); } private Time getTimeFromString(String timeAsString, Calendar targetCalendar, int columnIndex, TimeZone tz, boolean rollForward) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { int hr = 0; int min = 0; int sec = 0; try { if (timeAsString == null) { this.wasNullFlag = true; return null; } // // JDK-6 doesn't like trailing whitespace // // Note this isn't a performance issue, other than the iteration over the string, as String.trim() will return a new string only if whitespace // is present // timeAsString = timeAsString.trim(); // truncate fractional part int dec = timeAsString.indexOf("."); if (dec > -1) { timeAsString = timeAsString.substring(0, dec); } if (timeAsString.equals("0") || timeAsString.equals("0000-00-00") || timeAsString.equals("0000-00-00 00:00:00") || timeAsString.equals("00000000000000")) { if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL.equals(this.connection.getZeroDateTimeBehavior())) { this.wasNullFlag = true; return null; } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION.equals(this.connection.getZeroDateTimeBehavior())) { throw SQLError.createSQLException("Value '" + timeAsString + "' can not be represented as java.sql.Time", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } // We're left with the case of 'round' to a time Java _can_ represent, which is '00:00:00' return fastTimeCreate(targetCalendar, 0, 0, 0); } 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 19: { // YYYY-MM-DD hh:mm:ss hr = Integer.parseInt(timeAsString.substring(length - 8, length - 6)); min = Integer.parseInt(timeAsString.substring(length - 5, length - 3)); sec = Integer.parseInt(timeAsString.substring(length - 2, length)); } break; 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 SQLError.createSQLException(Messages.getString("ResultSet.Timestamp_too_small_to_convert_to_Time_value_in_column__257") + columnIndex + "(" + this.fields[columnIndex - 1] + ").", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } SQLWarning precisionLost = new SQLWarning( Messages.getString("ResultSet.Precision_lost_converting_TIMESTAMP_to_Time_with_getTime()_on_column__261") + 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") + columnIndex + "(" + this.fields[columnIndex - 1] + ")."); if (this.warningChain == null) { this.warningChain = precisionLost; } else { this.warningChain.setNextWarning(precisionLost); } } else if (timeColField.getMysqlType() == MysqlDefs.FIELD_TYPE_DATE) { return fastTimeCreate(targetCalendar, 0, 0, 0); // midnight on the given // date } else { // convert a String to a Time if ((timeAsString.length() != 5) && (timeAsString.length() != 8)) { throw SQLError .createSQLException( Messages.getString("ResultSet.Bad_format_for_Time____267") + timeAsString + Messages.getString("ResultSet.___in_column__268") + columnIndex, SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } hr = Integer.parseInt(timeAsString.substring(0, 2)); min = Integer.parseInt(timeAsString.substring(3, 5)); sec = (timeAsString.length() == 5) ? 0 : Integer.parseInt(timeAsString.substring(6)); } Calendar sessionCalendar = this.getCalendarInstanceForSessionOrNew(); return TimeUtil.changeTimezone(this.connection, sessionCalendar, targetCalendar, fastTimeCreate(sessionCalendar, hr, min, sec), this.connection.getServerTimezoneTZ(), tz, rollForward); } catch (RuntimeException ex) { SQLException sqlEx = SQLError.createSQLException(ex.toString(), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); sqlEx.initCause(ex); throw sqlEx; } } } /** * 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 */ private Time getTimeInternal(int columnIndex, Calendar targetCalendar, TimeZone tz, boolean rollForward) throws java.sql.SQLException { checkRowPos(); if (this.isBinaryEncoded) { return getNativeTime(columnIndex, targetCalendar, tz, rollForward); } if (!this.useFastDateParsing) { String timeAsString = getStringInternal(columnIndex, false); return getTimeFromString(timeAsString, targetCalendar, columnIndex, tz, rollForward); } checkColumnBounds(columnIndex); int columnIndexMinusOne = columnIndex - 1; if (this.thisRow.isNull(columnIndexMinusOne)) { this.wasNullFlag = true; return null; } this.wasNullFlag = false; return this.thisRow.getTimeFast(columnIndexMinusOne, targetCalendar, tz, rollForward, this.connection, this); } /** * 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 */ public Timestamp getTimestamp(int columnIndex) throws java.sql.SQLException { return getTimestampInternal(columnIndex, null, 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. */ public java.sql.Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { return getTimestampInternal(columnIndex, cal, cal != null ? cal.getTimeZone() : this.getDefaultTimeZone(), true); } /** * @param columnName * * @throws java.sql.SQLException */ 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. */ public java.sql.Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException { return getTimestamp(findColumn(columnName), cal); } private Timestamp getTimestampFromString(int columnIndex, Calendar targetCalendar, String timestampValue, TimeZone tz, boolean rollForward) throws java.sql.SQLException { try { this.wasNullFlag = false; if (timestampValue == null) { this.wasNullFlag = true; return null; } // // JDK-6 doesn't like trailing whitespace // // Note this isn't a performance issue, other than the iteration over the string, as String.trim() will return a new string only if whitespace is // present // timestampValue = timestampValue.trim(); int length = timestampValue.length(); Calendar sessionCalendar = this.connection.getUseJDBCCompliantTimezoneShift() ? this.connection.getUtcCalendar() : getCalendarInstanceForSessionOrNew(); 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 (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL.equals(this.connection.getZeroDateTimeBehavior())) { this.wasNullFlag = true; return null; } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION.equals(this.connection.getZeroDateTimeBehavior())) { throw SQLError.createSQLException("Value '" + timestampValue + "' can not be represented as java.sql.Timestamp", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } // 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) { if (!this.useLegacyDatetimeCode) { return TimeUtil.fastTimestampCreate(tz, Integer.parseInt(timestampValue.substring(0, 4)), 1, 1, 0, 0, 0, 0); } return TimeUtil.changeTimezone(this.connection, sessionCalendar, targetCalendar, fastTimestampCreate(sessionCalendar, Integer.parseInt(timestampValue.substring(0, 4)), 1, 1, 0, 0, 0, 0), this.connection.getServerTimezoneTZ(), tz, rollForward); } else { // Convert from TIMESTAMP or DATE int year = 0; int month = 0; int day = 0; int hour = 0; int minutes = 0; int seconds = 0; int nanos = 0; // check for the fractional part int decimalIndex = timestampValue.indexOf("."); if (decimalIndex == length - 1) { // if the dot is in last position length--; } else if (decimalIndex != -1) { if ((decimalIndex + 2) <= length) { nanos = Integer.parseInt(timestampValue.substring(decimalIndex + 1)); int numDigits = length - (decimalIndex + 1); if (numDigits < 9) { int factor = (int) (Math.pow(10, 9 - numDigits)); nanos = nanos * factor; } length = decimalIndex; } else { throw new IllegalArgumentException(); // re-thrown further down with a much better error message } } switch (length) { case 26: case 25: case 24: case 23: case 22: case 21: case 20: case 19: { year = Integer.parseInt(timestampValue.substring(0, 4)); month = Integer.parseInt(timestampValue.substring(5, 7)); day = Integer.parseInt(timestampValue.substring(8, 10)); hour = Integer.parseInt(timestampValue.substring(11, 13)); minutes = Integer.parseInt(timestampValue.substring(14, 16)); seconds = Integer.parseInt(timestampValue.substring(17, 19)); break; } case 14: { year = Integer.parseInt(timestampValue.substring(0, 4)); month = Integer.parseInt(timestampValue.substring(4, 6)); day = Integer.parseInt(timestampValue.substring(6, 8)); hour = Integer.parseInt(timestampValue.substring(8, 10)); minutes = Integer.parseInt(timestampValue.substring(10, 12)); seconds = Integer.parseInt(timestampValue.substring(12, 14)); break; } case 12: { year = Integer.parseInt(timestampValue.substring(0, 2)); if (year <= 69) { year = (year + 100); } year += 1900; 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)); seconds = Integer.parseInt(timestampValue.substring(10, 12)); break; } case 10: { 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 } break; } case 8: { if (timestampValue.indexOf(":") != -1) { hour = Integer.parseInt(timestampValue.substring(0, 2)); minutes = Integer.parseInt(timestampValue.substring(3, 5)); seconds = Integer.parseInt(timestampValue.substring(6, 8)); year = 1970; month = 1; day = 1; break; } year = Integer.parseInt(timestampValue.substring(0, 4)); month = Integer.parseInt(timestampValue.substring(4, 6)); day = Integer.parseInt(timestampValue.substring(6, 8)); year -= 1900; month--; break; } case 6: { year = Integer.parseInt(timestampValue.substring(0, 2)); if (year <= 69) { year = (year + 100); } year += 1900; month = Integer.parseInt(timestampValue.substring(2, 4)); day = Integer.parseInt(timestampValue.substring(4, 6)); break; } case 4: { year = Integer.parseInt(timestampValue.substring(0, 2)); if (year <= 69) { year = (year + 100); } year += 1900; month = Integer.parseInt(timestampValue.substring(2, 4)); day = 1; break; } case 2: { year = Integer.parseInt(timestampValue.substring(0, 2)); if (year <= 69) { year = (year + 100); } year += 1900; month = 1; day = 1; break; } default: throw new java.sql.SQLException("Bad format for Timestamp '" + timestampValue + "' in column " + columnIndex + ".", SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } if (!this.useLegacyDatetimeCode) { return TimeUtil.fastTimestampCreate(tz, year, month, day, hour, minutes, seconds, nanos); } return TimeUtil.changeTimezone(this.connection, sessionCalendar, targetCalendar, fastTimestampCreate(sessionCalendar, year, month, day, hour, minutes, seconds, nanos), this.connection.getServerTimezoneTZ(), tz, rollForward); } } catch (RuntimeException e) { SQLException sqlEx = SQLError.createSQLException("Cannot convert value '" + timestampValue + "' from column " + columnIndex + " to TIMESTAMP.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); sqlEx.initCause(e); throw sqlEx; } } /** * 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 */ private Timestamp getTimestampInternal(int columnIndex, Calendar targetCalendar, TimeZone tz, boolean rollForward) throws java.sql.SQLException { if (this.isBinaryEncoded) { return getNativeTimestamp(columnIndex, targetCalendar, tz, rollForward); } Timestamp tsVal = null; if (!this.useFastDateParsing) { String timestampValue = getStringInternal(columnIndex, false); tsVal = getTimestampFromString(columnIndex, targetCalendar, timestampValue, tz, rollForward); } else { checkClosed(); checkRowPos(); checkColumnBounds(columnIndex); tsVal = this.thisRow.getTimestampFast(columnIndex - 1, targetCalendar, tz, rollForward, this.connection, this); } if (tsVal == null) { this.wasNullFlag = true; } else { this.wasNullFlag = false; } return tsVal; } /** * 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 */ public int getType() throws SQLException { return this.resultSetType; } /** * 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 */ @Deprecated public InputStream getUnicodeStream(int columnIndex) throws SQLException { if (!this.isBinaryEncoded) { checkRowPos(); return getBinaryStream(columnIndex); } return getNativeBinaryStream(columnIndex); } /** * @param columnName * * @throws SQLException * * @deprecated */ @Deprecated public InputStream getUnicodeStream(String columnName) throws SQLException { return getUnicodeStream(findColumn(columnName)); } public long getUpdateCount() { return this.updateCount; } public long getUpdateID() { return this.updateId; } /** * @see ResultSetInternalMethods#getURL(int) */ 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 SQLError.createSQLException(Messages.getString("ResultSet.Malformed_URL____104") + val + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } /** * @see ResultSetInternalMethods#getURL(String) */ 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 SQLError.createSQLException(Messages.getString("ResultSet.Malformed_URL____107") + val + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } /** * The first warning reported by calls on this ResultSet is returned. * Subsequent ResultSet warnings will be chained to this * java.sql.SQLWarning. * *

* The warning chain is automatically cleared each time a new row is read. *

* *

* Note: 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. *

* * @return the first java.sql.SQLWarning or null; * * @exception SQLException * if a database access error occurs. */ public java.sql.SQLWarning getWarnings() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { return this.warningChain; } } /** * 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 */ public void insertRow() throws SQLException { throw new NotUpdatable(); } /** * JDBC 2.0 * *

* Determine if the cursor is after the last row in the result set. *

* * @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. */ public boolean isAfterLast() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { boolean b = this.rowData.isAfterLast(); return b; } } /** * JDBC 2.0 * *

* Determine if the cursor is before the first row in the result set. *

* * @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. */ public boolean isBeforeFirst() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { return this.rowData.isBeforeFirst(); } } /** * JDBC 2.0 * *

* Determine if the cursor is on the first row of the result set. *

* * @return true if on the first row, false otherwise. * * @exception SQLException * if a database-access error occurs. */ public boolean isFirst() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { return this.rowData.isFirst(); } } /** * JDBC 2.0 * *

* 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. *

* * @return true if on the last row, false otherwise. * * @exception SQLException * if a database-access error occurs. */ public boolean isLast() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { return this.rowData.isLast(); } } /** * @param string * @param mysqlType * @param s */ private void issueConversionViaParsingWarning(String methodName, int columnIndex, Object value, Field fieldInfo, int[] typesWithNoParseConversion) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { StringBuilder originalQueryBuf = new StringBuilder(); if (this.owningStatement != null && this.owningStatement instanceof com.mysql.jdbc.PreparedStatement) { originalQueryBuf.append(Messages.getString("ResultSet.CostlyConversionCreatedFromQuery")); originalQueryBuf.append(((com.mysql.jdbc.PreparedStatement) this.owningStatement).originalSql); originalQueryBuf.append("\n\n"); } else { originalQueryBuf.append("."); } StringBuilder convertibleTypesBuf = new StringBuilder(); for (int i = 0; i < typesWithNoParseConversion.length; i++) { convertibleTypesBuf.append(MysqlDefs.typeToName(typesWithNoParseConversion[i])); convertibleTypesBuf.append("\n"); } String message = Messages.getString("ResultSet.CostlyConversion", new Object[] { methodName, Integer.valueOf(columnIndex + 1), fieldInfo.getOriginalName(), fieldInfo.getOriginalTableName(), originalQueryBuf.toString(), value != null ? value.getClass().getName() : ResultSetMetaData.getClassNameForJavaType(fieldInfo.getSQLType(), fieldInfo.isUnsigned(), fieldInfo.getMysqlType(), fieldInfo.isBinary() || fieldInfo.isBlob(), fieldInfo.isOpaqueBinary(), this.connection.getYearIsDateType()), MysqlDefs.typeToName(fieldInfo.getMysqlType()), convertibleTypesBuf.toString() }); this.eventSink .consumeEvent(new ProfilerEvent(ProfilerEvent.TYPE_WARN, "", (this.owningStatement == null) ? "N/A" : this.owningStatement.currentCatalog, this.connectionId, (this.owningStatement == null) ? (-1) : this.owningStatement.getId(), this.resultId, System.currentTimeMillis(), 0, Constants.MILLIS_I18N, null, this.pointOfOrigin, message)); } } /** * JDBC 2.0 * *

* Moves to the last row in the result set. *

* * @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. */ public boolean last() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { boolean b = true; if (this.rowData.size() == 0) { b = false; } else { if (this.onInsertRow) { this.onInsertRow = false; } if (this.doingUpdates) { this.doingUpdates = false; } if (this.thisRow != null) { this.thisRow.closeOpenStreams(); } this.rowData.beforeLast(); this.thisRow = this.rowData.next(); } setRowPositionValidity(); return b; } } // ///////////////////////////////////////// // // These number conversion routines save // a ton of "new()s", especially for the heavily // used getInt() and getDouble() methods // // ///////////////////////////////////////// /** * 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 */ 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 */ 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. * *

* 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 *

* * @return true if the new current is valid; false if there are no more rows * * @exception SQLException * if a database access error occurs */ public boolean next() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if (this.onInsertRow) { this.onInsertRow = false; } if (this.doingUpdates) { this.doingUpdates = false; } boolean b; if (!reallyResult()) { throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"), SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor()); } if (this.thisRow != null) { this.thisRow.closeOpenStreams(); } if (this.rowData.size() == 0) { b = false; } else { this.thisRow = this.rowData.next(); if (this.thisRow == null) { b = false; } else { clearWarnings(); b = true; } } setRowPositionValidity(); return b; } } private int parseIntAsDouble(int columnIndex, String val) throws NumberFormatException, SQLException { if (val == null) { return 0; } double valueAsDouble = Double.parseDouble(val); if (this.jdbcCompliantTruncationForReads) { if (valueAsDouble < Integer.MIN_VALUE || valueAsDouble > Integer.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), columnIndex, Types.INTEGER); } } return (int) valueAsDouble; } private int getIntWithOverflowCheck(int columnIndex) throws SQLException { int intValue = this.thisRow.getInt(columnIndex); checkForIntegerTruncation(columnIndex, null, intValue); return intValue; } private void checkForIntegerTruncation(int columnIndex, byte[] valueAsBytes, int intValue) throws SQLException { if (this.jdbcCompliantTruncationForReads) { if (intValue == Integer.MIN_VALUE || intValue == Integer.MAX_VALUE) { String valueAsString = null; if (valueAsBytes == null) { valueAsString = this.thisRow.getString(columnIndex, this.fields[columnIndex].getEncoding(), this.connection); } long valueAsLong = Long.parseLong(valueAsString == null ? StringUtils.toString(valueAsBytes) : valueAsString); if (valueAsLong < Integer.MIN_VALUE || valueAsLong > Integer.MAX_VALUE) { throwRangeException(valueAsString == null ? StringUtils.toString(valueAsBytes) : valueAsString, columnIndex + 1, Types.INTEGER); } } } } private long parseLongAsDouble(int columnIndexZeroBased, String val) throws NumberFormatException, SQLException { if (val == null) { return 0; } double valueAsDouble = Double.parseDouble(val); if (this.jdbcCompliantTruncationForReads) { if (valueAsDouble < Long.MIN_VALUE || valueAsDouble > Long.MAX_VALUE) { throwRangeException(val, columnIndexZeroBased + 1, Types.BIGINT); } } return (long) valueAsDouble; } private long getLongWithOverflowCheck(int columnIndexZeroBased, boolean doOverflowCheck) throws SQLException { long longValue = this.thisRow.getLong(columnIndexZeroBased); if (doOverflowCheck) { checkForLongTruncation(columnIndexZeroBased, null, longValue); } return longValue; } private long parseLongWithOverflowCheck(int columnIndexZeroBased, byte[] valueAsBytes, String valueAsString, boolean doCheck) throws NumberFormatException, SQLException { long longValue = 0; if (valueAsBytes == null && valueAsString == null) { return 0; } if (valueAsBytes != null) { longValue = StringUtils.getLong(valueAsBytes); } else { // // JDK-6 doesn't like trailing whitespace // // Note this isn't a performance issue, other than the iteration over the string, as String.trim() will return a new string only if whitespace is // present // valueAsString = valueAsString.trim(); longValue = Long.parseLong(valueAsString); } if (doCheck && this.jdbcCompliantTruncationForReads) { checkForLongTruncation(columnIndexZeroBased, valueAsBytes, longValue); } return longValue; } private void checkForLongTruncation(int columnIndexZeroBased, byte[] valueAsBytes, long longValue) throws SQLException { if (longValue == Long.MIN_VALUE || longValue == Long.MAX_VALUE) { String valueAsString = null; if (valueAsBytes == null) { valueAsString = this.thisRow.getString(columnIndexZeroBased, this.fields[columnIndexZeroBased].getEncoding(), this.connection); } double valueAsDouble = Double.parseDouble(valueAsString == null ? StringUtils.toString(valueAsBytes) : valueAsString); if (valueAsDouble < Long.MIN_VALUE || valueAsDouble > Long.MAX_VALUE) { throwRangeException(valueAsString == null ? StringUtils.toString(valueAsBytes) : valueAsString, columnIndexZeroBased + 1, Types.BIGINT); } } } private short parseShortAsDouble(int columnIndex, String val) throws NumberFormatException, SQLException { if (val == null) { return 0; } double valueAsDouble = Double.parseDouble(val); if (this.jdbcCompliantTruncationForReads) { if (valueAsDouble < Short.MIN_VALUE || valueAsDouble > Short.MAX_VALUE) { throwRangeException(String.valueOf(valueAsDouble), columnIndex, Types.SMALLINT); } } return (short) valueAsDouble; } 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 { // // JDK-6 doesn't like trailing whitespace // // Note this isn't a performance issue, other than the iteration over the string, as String.trim() will return a new string only if whitespace is // present // valueAsString = valueAsString.trim(); shortValue = Short.parseShort(valueAsString); } if (this.jdbcCompliantTruncationForReads) { if (shortValue == Short.MIN_VALUE || shortValue == Short.MAX_VALUE) { long valueAsLong = Long.parseLong(valueAsString == null ? StringUtils.toString(valueAsBytes) : valueAsString); if (valueAsLong < Short.MIN_VALUE || valueAsLong > Short.MAX_VALUE) { throwRangeException(valueAsString == null ? StringUtils.toString(valueAsBytes) : valueAsString, columnIndex, Types.SMALLINT); } } } return shortValue; } // --------------------------JDBC 2.0----------------------------------- // --------------------------------------------------------------------- // Getter's and Setter's // --------------------------------------------------------------------- /** * 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. * *

* 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 *

* * @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 */ public boolean prev() throws java.sql.SQLException { synchronized (checkClosed().getConnectionMutex()) { int rowIndex = this.rowData.getCurrentRowNumber(); if (this.thisRow != null) { this.thisRow.closeOpenStreams(); } boolean b = true; if ((rowIndex - 1) >= 0) { rowIndex--; this.rowData.setCurrentRow(rowIndex); this.thisRow = this.rowData.getAt(rowIndex); b = true; } else if ((rowIndex - 1) == -1) { rowIndex--; this.rowData.setCurrentRow(rowIndex); this.thisRow = null; b = false; } else { b = false; } setRowPositionValidity(); return b; } } /** * JDBC 2.0 * *

* Moves to the previous row in the result set. *

* *

* Note: previous() is not the same as relative(-1) since it makes sense to call previous() when there is no current row. *

* * @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. */ public boolean previous() throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if (this.onInsertRow) { this.onInsertRow = false; } if (this.doingUpdates) { this.doingUpdates = false; } return prev(); } } /** * Closes this ResultSet and releases resources. * * @param calledExplicitly * was realClose called by the standard ResultSet.close() method, or was it closed internally by the * driver? * * @throws SQLException * if an error occurs */ public void realClose(boolean calledExplicitly) throws SQLException { MySQLConnection locallyScopedConn = this.connection; if (locallyScopedConn == null) { return; // already closed } synchronized (locallyScopedConn.getConnectionMutex()) { // additional check in case ResultSet was closed // while current thread was waiting for lock if (this.isClosed) { return; } try { if (this.useUsageAdvisor) { // Report on result set closed by driver instead of application if (!calledExplicitly) { this.eventSink.consumeEvent(new ProfilerEvent(ProfilerEvent.TYPE_WARN, "", (this.owningStatement == null) ? "N/A" : this.owningStatement.currentCatalog, this.connectionId, (this.owningStatement == null) ? (-1) : this.owningStatement.getId(), this.resultId, System.currentTimeMillis(), 0, Constants.MILLIS_I18N, null, this.pointOfOrigin, Messages.getString("ResultSet.ResultSet_implicitly_closed_by_driver"))); } if (this.rowData instanceof RowDataStatic) { // Report on possibly too-large result sets if (this.rowData.size() > this.connection.getResultSetSizeThreshold()) { this.eventSink.consumeEvent(new ProfilerEvent(ProfilerEvent.TYPE_WARN, "", (this.owningStatement == null) ? Messages.getString("ResultSet.N/A_159") : this.owningStatement.currentCatalog, this.connectionId, (this.owningStatement == null) ? (-1) : this.owningStatement.getId(), this.resultId, System.currentTimeMillis(), 0, Constants.MILLIS_I18N, null, this.pointOfOrigin, Messages.getString("ResultSet.Too_Large_Result_Set", new Object[] { Integer.valueOf(this.rowData.size()), Integer.valueOf(this.connection.getResultSetSizeThreshold()) }))); } if (!isLast() && !isAfterLast() && (this.rowData.size() != 0)) { this.eventSink.consumeEvent(new ProfilerEvent(ProfilerEvent.TYPE_WARN, "", (this.owningStatement == null) ? Messages.getString("ResultSet.N/A_159") : this.owningStatement.currentCatalog, this.connectionId, (this.owningStatement == null) ? (-1) : this.owningStatement.getId(), this.resultId, System.currentTimeMillis(), 0, Constants.MILLIS_I18N, null, this.pointOfOrigin, Messages.getString("ResultSet.Possible_incomplete_traversal_of_result_set", new Object[] { Integer.valueOf(getRow()), Integer.valueOf(this.rowData.size()) }))); } } // // Report on any columns that were selected but not referenced // if (this.columnUsed.length > 0 && !this.rowData.wasEmpty()) { StringBuilder buf = new StringBuilder(Messages.getString("ResultSet.The_following_columns_were_never_referenced")); 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.connectionId, (this.owningStatement == null) ? (-1) : this.owningStatement.getId(), 0, System.currentTimeMillis(), 0, Constants.MILLIS_I18N, null, this.pointOfOrigin, buf.toString())); } } } } finally { if (this.owningStatement != null && calledExplicitly) { this.owningStatement.removeOpenResultSet(this); } SQLException exceptionDuringClose = null; if (this.rowData != null) { try { this.rowData.close(); } catch (SQLException sqlEx) { exceptionDuringClose = sqlEx; } } if (this.statementUsedForFetchingRows != null) { try { this.statementUsedForFetchingRows.realClose(true, false); } catch (SQLException sqlEx) { if (exceptionDuringClose != null) { exceptionDuringClose.setNextException(sqlEx); } else { exceptionDuringClose = sqlEx; } } } this.rowData = null; this.fields = null; this.columnLabelToIndex = null; this.fullColumnNameToIndex = null; this.columnToIndexCache = null; this.eventSink = null; this.warningChain = null; if (!this.retainOwningStatement) { this.owningStatement = null; } this.catalog = null; this.serverInfo = null; this.thisRow = null; this.fastDefaultCal = null; this.fastClientCal = null; this.connection = null; this.isClosed = true; if (exceptionDuringClose != null) { throw exceptionDuringClose; } } } } /** * Returns true if this ResultSet is closed. */ public boolean isClosed() throws SQLException { return this.isClosed; } public boolean reallyResult() { if (this.rowData != null) { return true; } return this.reallyResult; } /** * 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 */ public void refreshRow() throws SQLException { throw new NotUpdatable(); } /** * JDBC 2.0 * *

* 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. *

* *

* 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. *

* * @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. */ public boolean relative(int rows) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if (this.rowData.size() == 0) { setRowPositionValidity(); return false; } if (this.thisRow != null) { this.thisRow.closeOpenStreams(); } this.rowData.moveRowRelative(rows); this.thisRow = this.rowData.getAt(this.rowData.getCurrentRowNumber()); setRowPositionValidity(); 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 * * @see DatabaseMetaData#deletesAreDetected */ public boolean rowDeleted() throws SQLException { throw SQLError.createSQLFeatureNotSupportedException(); } /** * 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 * * @see DatabaseMetaData#insertsAreDetected */ public boolean rowInserted() throws SQLException { throw SQLError.createSQLFeatureNotSupportedException(); } /** * 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 * * @see DatabaseMetaData#updatesAreDetected */ public boolean rowUpdated() throws SQLException { throw SQLError.createSQLFeatureNotSupportedException(); } /** * Flag that this result set is 'binary' encoded (from a PreparedStatement), * not stored as strings. */ protected void setBinaryEncoded() { this.isBinaryEncoded = true; } /** * 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. */ public void setFetchDirection(int direction) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if ((direction != FETCH_FORWARD) && (direction != FETCH_REVERSE) && (direction != FETCH_UNKNOWN)) { throw SQLError.createSQLException(Messages.getString("ResultSet.Illegal_value_for_fetch_direction_64"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } this.fetchDirection = direction; } } /** * 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. */ public void setFetchSize(int rows) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if (rows < 0) { /* || rows > getMaxRows() */ throw SQLError.createSQLException(Messages.getString("ResultSet.Value_must_be_between_0_and_getMaxRows()_66"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } this.fetchSize = rows; } } /** * Sets the first character of the query that this result set was created * from. * * @param c * the first character of the query...uppercased */ public void setFirstCharOfQuery(char c) { try { synchronized (checkClosed().getConnectionMutex()) { this.firstCharOfQuery = c; } } catch (SQLException e) { throw new RuntimeException(e); // FIXME: Need to evolve public interface } } /** * @param nextResultSet * Sets the next result set in the result set chain for multiple * result sets. */ protected synchronized void setNextResultSet(ResultSetInternalMethods nextResultSet) { this.nextResultSet = nextResultSet; } public void setOwningStatement(com.mysql.jdbc.StatementImpl owningStatement) { try { synchronized (checkClosed().getConnectionMutex()) { this.owningStatement = owningStatement; } } catch (SQLException e) { throw new RuntimeException(e); // FIXME: Need to evolve public interface } } /** * Sets the concurrency (JDBC2) * * @param concurrencyFlag * CONCUR_UPDATABLE or CONCUR_READONLY */ protected synchronized void setResultSetConcurrency(int concurrencyFlag) { try { synchronized (checkClosed().getConnectionMutex()) { this.resultSetConcurrency = concurrencyFlag; } } catch (SQLException e) { throw new RuntimeException(e); // FIXME: Need to evolve public interface } } /** * Sets the result set type for (JDBC2) * * @param typeFlag * SCROLL_SENSITIVE or SCROLL_INSENSITIVE (we only support * SCROLL_INSENSITIVE) */ protected synchronized void setResultSetType(int typeFlag) { try { synchronized (checkClosed().getConnectionMutex()) { this.resultSetType = typeFlag; } } catch (SQLException e) { throw new RuntimeException(e); // FIXME: Need to evolve public interface } } /** * Sets server info (if any) * * @param info * the server info message */ protected void setServerInfo(String info) { try { synchronized (checkClosed().getConnectionMutex()) { this.serverInfo = info; } } catch (SQLException e) { throw new RuntimeException(e); // FIXME: Need to evolve public interface } } public synchronized void setStatementUsedForFetchingRows(PreparedStatement stmt) { try { synchronized (checkClosed().getConnectionMutex()) { this.statementUsedForFetchingRows = stmt; } } catch (SQLException e) { throw new RuntimeException(e); // FIXME: Need to evolve public interface } } /** * @param wrapperStatement * The wrapperStatement to set. */ public synchronized void setWrapperStatement(java.sql.Statement wrapperStatement) { try { synchronized (checkClosed().getConnectionMutex()) { this.wrapperStatement = wrapperStatement; } } catch (SQLException e) { throw new RuntimeException(e); // FIXME: Need to evolve public interface } } 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 SQLError.createSQLException("'" + valueAsString + "' in column '" + columnIndex + "' is outside valid range for the datatype " + datatype + ".", SQLError.SQL_STATE_NUMERIC_VALUE_OUT_OF_RANGE, getExceptionInterceptor()); } @Override public String toString() { if (this.reallyResult) { return super.toString(); } return "Result set representing update count of " + this.updateCount; } /** * @see ResultSetInternalMethods#updateArray(int, Array) */ public void updateArray(int arg0, Array arg1) throws SQLException { throw SQLError.createSQLFeatureNotSupportedException(); } /** * @see ResultSetInternalMethods#updateArray(String, Array) */ public void updateArray(String arg0, Array arg1) throws SQLException { throw SQLError.createSQLFeatureNotSupportedException(); } /** * 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ public void updateBinaryStream(String columnName, java.io.InputStream x, int length) throws SQLException { updateBinaryStream(findColumn(columnName), x, length); } /** * @see ResultSetInternalMethods#updateBlob(int, Blob) */ public void updateBlob(int arg0, java.sql.Blob arg1) throws SQLException { throw new NotUpdatable(); } /** * @see ResultSetInternalMethods#updateBlob(String, Blob) */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ public void updateCharacterStream(String columnName, java.io.Reader reader, int length) throws SQLException { updateCharacterStream(findColumn(columnName), reader, length); } /** * @see ResultSetInternalMethods#updateClob(int, Clob) */ public void updateClob(int arg0, java.sql.Clob arg1) throws SQLException { throw SQLError.createSQLFeatureNotSupportedException(); } /** * @see ResultSetInternalMethods#updateClob(String, Clob) */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 * * @exception SQLException * if a database-access error occurs * @throws NotUpdatable */ 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 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 */ 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 columnName * the name of the column * @param x * the new column value * * @exception SQLException * if a database-access error occurs */ public void updateObject(String columnName, Object x) 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 * @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 */ public void updateObject(String columnName, Object x, int scale) throws SQLException { updateObject(findColumn(columnName), x); } /** * @see ResultSetInternalMethods#updateRef(int, Ref) */ public void updateRef(int arg0, Ref arg1) throws SQLException { throw SQLError.createSQLFeatureNotSupportedException(); } /** * @see ResultSetInternalMethods#updateRef(String, Ref) */ public void updateRef(String arg0, Ref arg1) throws SQLException { throw SQLError.createSQLFeatureNotSupportedException(); } /** * 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ public boolean wasNull() throws SQLException { return this.wasNullFlag; } protected Calendar getGmtCalendar() { // Worst case we allocate this twice and the other gets GC'd, // however prevents deadlock if (this.gmtCalendar == null) { this.gmtCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); } return this.gmtCalendar; } protected ExceptionInterceptor getExceptionInterceptor() { return this.exceptionInterceptor; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy