📄 resultsetimpl.java
字号:
/* Copyright 2002-2007 MySQL AB, 2008 Sun Microsystems This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. There are special exceptions to the terms and conditions of the GPL as it is applied to this software. View the full text of the exception in file EXCEPTIONS-CONNECTOR-J in the directory of this software distribution. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package com.mysql.jdbc;import 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.Locale;import java.util.Map;import java.util.StringTokenizer;import java.util.TimeZone;import java.util.TreeMap;import com.mysql.jdbc.profiler.ProfilerEvent;import com.mysql.jdbc.profiler.ProfilerEventHandler;import com.mysql.jdbc.profiler.ProfilerEventHandlerFactory;/** * A ResultSet provides access to a table of data generated by executing a * Statement. The table rows are retrieved in sequence. Within a row its column * values can be accessed in any order. * * <P> * A ResultSet maintains a cursor pointing to its current row of data. Initially * the cursor is positioned before the first row. The 'next' method moves the * cursor to the next row. * </p> * * <P> * The getXXX methods retrieve column values for the current row. You can * retrieve values either using the index number of the column, or by using the * name of the column. In general using the column index will be more efficient. * Columns are numbered from 1. * </p> * * <P> * For maximum portability, ResultSet columns within each row should be read in * left-to-right order and each column should be read only once. * </p> * * <P> * For the getXXX methods, the JDBC driver attempts to convert the underlying * data to the specified Java type and returns a suitable Java value. See the * JDBC specification for allowable mappings from SQL types to Java types with * the ResultSet getXXX methods. * </p> * * <P> * Column names used as input to getXXX methods are case insenstive. When * performing a getXXX using a column name, if several columns have the same * name, then the value of the first matching column will be returned. The * column name option is designed to be used when column names are used in the * SQL Query. For columns that are NOT explicitly named in the query, it is best * to use column numbers. If column names were used there is no way for the * programmer to guarentee that they actually refer to the intended columns. * </p> * * <P> * A ResultSet is automatically closed by the Statement that generated it when * that Statement is closed, re-executed, or is used to retrieve the next result * from a sequence of multiple results. * </p> * * <P> * The number, types and properties of a ResultSet's columns are provided by the * ResultSetMetaData object returned by the getMetaData method. * </p> * * @author Mark Matthews * @version $Id$ * * @see ResultSetMetaData * @see java.sql.ResultSet */public class ResultSetImpl implements ResultSetInternalMethods { private static final Constructor JDBC_4_RS_4_ARG_CTOR; private static final Constructor JDBC_4_RS_6_ARG_CTOR;; private static final Constructor JDBC_4_UPD_RS_6_ARG_CTOR; static { if (Util.isJdbc4()) { try { JDBC_4_RS_4_ARG_CTOR = Class.forName( "com.mysql.jdbc.JDBC4ResultSet").getConstructor( new Class[] { Long.TYPE, Long.TYPE, ConnectionImpl.class, com.mysql.jdbc.StatementImpl.class }); JDBC_4_RS_6_ARG_CTOR = Class.forName( "com.mysql.jdbc.JDBC4ResultSet").getConstructor( new Class[] { String.class, Field[].class, RowData.class, ConnectionImpl.class, com.mysql.jdbc.StatementImpl.class }); JDBC_4_UPD_RS_6_ARG_CTOR = Class.forName( "com.mysql.jdbc.JDBC4UpdatableResultSet") .getConstructor( new Class[] { String.class, Field[].class, RowData.class, ConnectionImpl.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_6_ARG_CTOR = null; JDBC_4_UPD_RS_6_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. */ protected 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 ConnectionImpl 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; TimeZone defaultTimeZone; /** Are we in the middle of doing updates to the current row? */ protected boolean doingUpdates = false; protected ProfilerEventHandler eventSink = null; Calendar fastDateCal = 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 Throwable 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; protected 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, ConnectionImpl 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[] { Constants.longValueOf(updateCount), Constants.longValueOf(updateID), conn, creatorStmt }); } /** * 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, ConnectionImpl 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_6_ARG_CTOR, new Object[] { catalog, fields, tuples, conn, creatorStmt }); } return (ResultSetImpl) Util.handleNewInstance(JDBC_4_UPD_RS_6_ARG_CTOR, new Object[] { catalog, fields, tuples, conn, creatorStmt }); } /** * Create a result set for an executeUpdate statement. * * @param updateCount * the number of rows affected by the update * @param updateID * the autoincrement value (if any) * @param conn * DOCUMENT ME! * @param creatorStmt * DOCUMENT ME! */ public ResultSetImpl(long updateCount, long updateID, ConnectionImpl 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.retainOwningStatement = this.connection.getRetainStatementAfterResultSetClose(); this.connectionId = this.connection.getId(); this.serverTimeZoneTz = this.connection.getServerTimezoneTZ(); } 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 * DOCUMENT ME! * * @throws SQLException * if an error occurs */ public ResultSetImpl(String catalog, Field[] fields, RowData tuples, ConnectionImpl conn, StatementImpl creatorStmt) throws SQLException { this.connection = conn; this.retainOwningStatement = false; if (this.connection != null) { this.useStrictFloatingPoint = this.connection .getStrictFloatingPoint(); this.setDefaultTimeZone(this.connection.getDefaultTimeZone()); 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.owningStatement = creatorStmt; this.catalog = catalog; this.fields = fields; this.rowData = tuples; this.updateCount = this.rowData.size(); if (Driver.DEBUG) { System.out.println(Messages.getString("ResultSet.Retrieved__1") + this.updateCount + " rows"); //$NON-NLS-1$ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -