com.mysql.jdbc.ResultSetImpl Maven / Gradle / Ivy
Show all versions of mysql-connector-java
/*
Copyright (c) 2002, 2018, 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,
boolean useGmtMillis) 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();
}
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