📄 jtdsresultset.java
字号:
// jTDS JDBC Driver for Microsoft SQL Server and Sybase
// Copyright (C) 2004 The jTDS Project
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
package net.sourceforge.jtds.jdbc;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.net.MalformedURLException;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.ArrayList;
import java.text.NumberFormat;
import java.io.UnsupportedEncodingException;
import java.io.InputStreamReader;
/**
* jTDS Implementation of the java.sql.ResultSet interface supporting forward read
* only result sets.
* <p>
* Implementation notes:
* <ol>
* <li>This class is also the base for more sophisticated result sets and
* incorporates the update methods required by them.
* <li>The class supports the BLOB/CLOB objects added by Brian.
* </ol>
*
* @author Mike Hutchinson
* @version $Id: JtdsResultSet.java,v 1.46 2005/09/26 18:21:09 ddkilzer Exp $
*/
public class JtdsResultSet implements ResultSet {
/*
* Constants for backwards compatibility with JDK 1.3
*/
static final int HOLD_CURSORS_OVER_COMMIT = 1;
static final int CLOSE_CURSORS_AT_COMMIT = 2;
protected static final int POS_BEFORE_FIRST = 0;
protected static final int POS_AFTER_LAST = -1;
/** Initial size for row array. */
protected static final int INITIAL_ROW_COUNT = 1000;
/*
* Protected Instance variables.
*/
/** The current row number. */
protected int pos = POS_BEFORE_FIRST;
/** The number of rows in the result. */
protected int rowsInResult;
/** The fetch direction. */
protected int direction = FETCH_FORWARD;
/** The result set type. */
protected int resultSetType;
/** The result set concurrency. */
protected int concurrency;
/** Number of visible columns in row. */
protected int columnCount;
/** The array of column descriptors. */
protected ColInfo[] columns;
/** The current result set row. */
protected Object[] currentRow;
/** Cached row data for forward only result set. */
protected ArrayList rowData;
/** Index of current row in rowData. */
protected int rowPtr;
/** True if last column retrieved was null. */
protected boolean wasNull;
/** The parent statement. */
protected JtdsStatement statement;
/** True if this result set is closed. */
protected boolean closed;
/** True if the query has been cancelled by another thread. */
protected boolean cancelled;
/** The fetch direction. */
protected int fetchDirection = FETCH_FORWARD;
/** The fetch size (only applies to cursor <code>ResultSet</code>s). */
protected int fetchSize;
/** The cursor name to be used for positioned updates. */
protected String cursorName;
/** Cache to optimize findColumn(String) lookups */
private HashMap columnMap;
/*
* Private instance variables.
*/
/** Used to format numeric values when scale is specified. */
private static NumberFormat f = NumberFormat.getInstance();
/**
* Construct a simple result set from a statement, metadata or generated keys.
*
* @param statement The parent statement object or null.
* @param resultSetType one of FORWARD_ONLY, SCROLL_INSENSITIVE, SCROLL_SENSITIVE.
* @param concurrency One of CONCUR_READ_ONLY, CONCUR_UPDATE.
* @param columns The array of column descriptors for the result set row.
* @throws SQLException
*/
JtdsResultSet(JtdsStatement statement,
int resultSetType,
int concurrency,
ColInfo[] columns)
throws SQLException {
if (statement == null) {
throw new IllegalArgumentException("Statement parameter must not be null");
}
this.statement = statement;
this.resultSetType = resultSetType;
this.concurrency = concurrency;
this.columns = columns;
this.fetchSize = statement.fetchSize;
this.fetchDirection = statement.fetchDirection;
this.cursorName = statement.cursorName;
if (columns != null) {
columnCount = getColumnCount(columns);
rowsInResult = (statement.getTds().isDataInResultSet()) ? 1 : 0;
}
}
/**
* Retrieve the column count excluding hidden columns
*
* @param columns The columns array
* @return The new column count as an <code>int</code>.
*/
protected static int getColumnCount(ColInfo[] columns) {
// MJH - Modified to cope with more than one hidden column
int i;
for (i = columns.length - 1; i >= 0 && columns[i].isHidden; i--);
return i + 1;
}
/**
* Retrieve the column descriptor array.
*
* @return The column descriptors as a <code>ColInfo[]</code>.
*/
protected ColInfo[] getColumns() {
return this.columns;
}
/**
* Set the specified column's name.
*
* @param colIndex The index of the column in the row.
* @param name The new name.
*/
protected void setColName(int colIndex, String name) {
if (colIndex < 1 || colIndex > columns.length) {
throw new IllegalArgumentException("columnIndex "
+ colIndex + " invalid");
}
columns[colIndex - 1].realName = name;
}
/**
* Set the specified column's label.
*
* @param colIndex The index of the column in the row.
* @param name The new label.
*/
protected void setColLabel(int colIndex, String name) {
if (colIndex < 1 || colIndex > columns.length) {
throw new IllegalArgumentException("columnIndex "
+ colIndex + " invalid");
}
columns[colIndex - 1].name = name;
}
/**
* Set the specified column's JDBC type.
*
* @param colIndex The index of the column in the row.
* @param jdbcType The new type value.
*/
protected void setColType(int colIndex, int jdbcType) {
if (colIndex < 1 || colIndex > columns.length) {
throw new IllegalArgumentException("columnIndex "
+ colIndex + " invalid");
}
columns[colIndex - 1].jdbcType = jdbcType;
}
/**
* Set the specified column's data value.
*
* @param colIndex index of the column
* @param value new column value
* @param length the length of a stream parameter
* @return the value, possibly converted to an internal type
*/
protected Object setColValue(int colIndex, int jdbcType, Object value, int length)
throws SQLException {
checkOpen();
checkUpdateable();
if (colIndex < 1 || colIndex > columnCount) {
throw new SQLException(Messages.get("error.resultset.colindex",
Integer.toString(colIndex)),
"07009");
}
//
// Convert java date/time objects to internal DateTime objects
//
if (value instanceof java.sql.Timestamp) {
value = new DateTime((java.sql.Timestamp) value);
} else if (value instanceof java.sql.Date) {
value = new DateTime((java.sql.Date) value);
} else if (value instanceof java.sql.Time) {
value = new DateTime((java.sql.Time) value);
}
return value;
}
/**
* Set the current row's column count.
*
* @param columnCount The number of visible columns in the row.
*/
protected void setColumnCount(int columnCount) {
if (columnCount < 1 || columnCount > columns.length) {
throw new IllegalArgumentException("columnCount "
+ columnCount + " is invalid");
}
this.columnCount = columnCount;
}
/**
* Get the specified column's data item.
*
* @param index the column index in the row
* @return the column value as an <code>Object</code>
* @throws SQLException if the connection is closed;
* if <code>index</code> is less than <code>1</code>;
* if <code>index</code> is greater that the number of columns;
* if there is no current row
*/
protected Object getColumn(int index) throws SQLException {
checkOpen();
if (index < 1 || index > columnCount) {
throw new SQLException(Messages.get("error.resultset.colindex",
Integer.toString(index)),
"07009");
}
if (currentRow == null) {
throw new SQLException(Messages.get("error.resultset.norow"), "24000");
}
Object data = currentRow[index - 1];
wasNull = data == null;
return data;
}
/**
* Check that this connection is still open.
*
* @throws SQLException if connection closed.
*/
protected void checkOpen() throws SQLException {
if (closed) {
throw new SQLException(Messages.get("error.generic.closed", "ResultSet"),
"HY010");
}
if (cancelled) {
throw new SQLException(Messages.get("error.generic.cancelled", "ResultSet"),
"HY010");
}
}
/**
* Check that this resultset is scrollable.
*
* @throws SQLException if connection closed.
*/
protected void checkScrollable() throws SQLException {
if (resultSetType == ResultSet.TYPE_FORWARD_ONLY) {
throw new SQLException(Messages.get("error.resultset.fwdonly"), "24000");
}
}
/**
* Check that this resultset is updateable.
*
* @throws SQLException if connection closed.
*/
protected void checkUpdateable() throws SQLException {
if (concurrency == ResultSet.CONCUR_READ_ONLY) {
throw new SQLException(Messages.get("error.resultset.readonly"), "24000");
}
}
/**
* Report that user tried to call a method which has not been implemented.
*
* @param method The method name to report in the error message.
* @throws SQLException
*/
protected static void notImplemented(String method) throws SQLException {
throw new SQLException(Messages.get("error.generic.notimp", method), "HYC00");
}
/**
* Create a new row containing empty data items.
*
* @return the new row as an <code>Object</code> array
*/
protected Object[] newRow() {
Object row[] = new Object[columns.length];
return row;
}
/**
* Copy an existing result set row.
*
* @param row the result set row to copy
* @return the new row as an <code>Object</code> array
*/
protected Object[] copyRow(Object[] row) {
Object copy[] = new Object[columns.length];
System.arraycopy(row, 0, copy, 0, row.length);
return copy;
}
/**
* Copy an existing result set column descriptor array.
*
* @param info The result set column descriptors to copy.
* @return The new descriptors as a <code>ColInfo[]</code>.
*/
protected ColInfo[] copyInfo(ColInfo[] info) {
ColInfo copy[] = new ColInfo[info.length];
System.arraycopy(info, 0, copy, 0, info.length);
return copy;
}
/**
* Retrieve the current row data.
* @return The current row data as an <code>Object[]</code>.
*/
protected Object[] getCurrentRow()
{
return this.currentRow;
}
/**
* Cache the remaining results to free up connection.
* @throws SQLException
*/
protected void cacheResultSetRows() throws SQLException {
if (rowData == null) {
rowData = new ArrayList(INITIAL_ROW_COUNT);
}
if (currentRow != null) {
// Need to create local copy of currentRow
// as this is currently a reference to the
// row defined in TdsCore
currentRow = copyRow(currentRow);
}
//
// Now load the remaining result set rows into memory
//
while (statement.getTds().getNextRow()) {
rowData.add(copyRow(statement.getTds().getRowData()));
}
// Allow statement to process output vars etc
statement.cacheResults();
}
/**
* Returns the {@link ConnectionJDBC2} object referenced by the
* {@link #statement} instance variable.
*
* @return {@link ConnectionJDBC2} object.
* @throws SQLException on error.
*/
private ConnectionJDBC2 getConnection() throws SQLException {
return (ConnectionJDBC2) statement.getConnection();
}
//
// -------------------- java.sql.ResultSet methods -------------------
//
public int getConcurrency() throws SQLException {
checkOpen();
return this.concurrency;
}
public int getFetchDirection() throws SQLException {
checkOpen();
return this.fetchDirection;
}
public int getFetchSize() throws SQLException {
checkOpen();
return fetchSize;
}
public int getRow() throws SQLException {
checkOpen();
return pos > 0 ? pos : 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -