📄 jtdsstatement.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.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Types;
import java.util.ArrayList;
import java.util.LinkedList;
/**
* jTDS implementation of the java.sql.Statement interface.<p>
* NB. As allowed by the JDBC standard and like most other drivers,
* this implementation only allows one open result set at a time.
* <p>
* Implementation notes:
* <p>
* I experimented with allowing multiple open result sets as supported
* by the origianal jTDS but rejected this approach for the following
* reasons:
* <ol>
* <li>It is more difficult to ensure that there are no memory leaks and that
* cursors are closed if multiple open sets are allowed.
* <li>The use of one result set allows cursor and non cursor result sets to
* be derived from exeuteQuery() or execute() and getResultSet() in the
* same way that other drivers do.
* </ol>
* In the event of an IO failure the setClosed() method forces this statement
* and associated result set to close preventing the propogation of errors.
* This class includes a finalize method which increases the chances of the
* statement being closed tidly in a pooled environment where the user has
* forgotten to explicitly close the statement before it goes out of scope.
*
* @see java.sql.Statement
* @see java.sql.Connection#createStatement()
* @see java.sql.ResultSet
*
* @author Mike Hutchinson
* @version $Id: JtdsStatement.java,v 1.64 2007/07/12 21:03:23 bheineman Exp $
*/
public class JtdsStatement implements java.sql.Statement {
/*
* Constants used for backwards compatibility with JDK 1.3
*/
static final int RETURN_GENERATED_KEYS = 1;
static final int NO_GENERATED_KEYS = 2;
static final int CLOSE_CURRENT_RESULT = 1;
static final int KEEP_CURRENT_RESULT = 2;
static final int CLOSE_ALL_RESULTS = 3;
static final int BOOLEAN = 16;
static final int DATALINK = 70;
static final Integer SUCCESS_NO_INFO = new Integer(-2);
static final Integer EXECUTE_FAILED = new Integer(-3);
static final int DEFAULT_FETCH_SIZE = 100;
/** The connection owning this statement object. */
protected ConnectionJDBC2 connection;
/** The TDS object used for server access. */
protected TdsCore tds;
/** The read query timeout in seconds */
protected int queryTimeout;
/** The current <code>ResultSet</code>. */
protected JtdsResultSet currentResult;
/** The current update count. */
private int updateCount = -1;
/** The fetch direction for result sets. */
protected int fetchDirection = ResultSet.FETCH_FORWARD;
/** The type of result sets created by this statement. */
protected int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
/** The concurrency of result sets created by this statement. */
protected int resultSetConcurrency = ResultSet.CONCUR_READ_ONLY;
/** The fetch size (default 100, only used by cursor
* <code>ResultSet</code>s).
*/
protected int fetchSize = DEFAULT_FETCH_SIZE;
/** The cursor name to be used for positioned updates. */
protected String cursorName;
/** True if this statement is closed. */
protected boolean closed;
/** The maximum field size (not used at present). */
protected int maxFieldSize;
/** The maximum number of rows to return (not used at present). */
protected int maxRows;
/** True if SQL statements should be preprocessed. */
protected boolean escapeProcessing = true;
/** SQL Diagnostic exceptions and warnings. */
protected final SQLDiagnostic messages;
/** Batched SQL Statement array. */
protected ArrayList batchValues;
/** Dummy result set for getGeneratedKeys. */
protected JtdsResultSet genKeyResultSet;
/**
* List of queued results (update counts, possibly followed by a
* <code>ResultSet</code>).
*/
protected final LinkedList resultQueue = new LinkedList();
/** List of open result sets. */
protected ArrayList openResultSets;
/** The cached column meta data. */
protected ColInfo[] colMetaData;
/**
* Construct a new Statement object.
*
* @param connection The parent connection.
* @param resultSetType The result set type for example TYPE_FORWARD_ONLY.
* @param resultSetConcurrency The concurrency for example CONCUR_READ_ONLY.
*/
JtdsStatement(ConnectionJDBC2 connection,
int resultSetType,
int resultSetConcurrency) throws SQLException {
//
// This is a good point to do common validation of the result set type
//
if (resultSetType < ResultSet.TYPE_FORWARD_ONLY
|| resultSetType > ResultSet.TYPE_SCROLL_SENSITIVE + 1) {
String method;
if (this instanceof JtdsCallableStatement) {
method = "prepareCall";
} else if (this instanceof JtdsPreparedStatement) {
method = "prepareStatement";
} else {
method = "createStatement";
}
throw new SQLException(
Messages.get("error.generic.badparam",
"resultSetType",
method),
"HY092");
}
//
// Ditto for the result set concurrency
//
if (resultSetConcurrency < ResultSet.CONCUR_READ_ONLY
|| resultSetConcurrency > ResultSet.CONCUR_UPDATABLE + 2) {
String method;
if (this instanceof JtdsCallableStatement) {
method = "prepareCall";
} else if (this instanceof JtdsPreparedStatement) {
method = "prepareStatement";
} else {
method = "createStatement";
}
throw new SQLException(
Messages.get("error.generic.badparam",
"resultSetConcurrency",
method),
"HY092");
}
this.connection = connection;
this.resultSetType = resultSetType;
this.resultSetConcurrency = resultSetConcurrency;
this.tds = connection.getCachedTds();
if (this.tds == null) {
this.messages = new SQLDiagnostic(connection.getServerType());
this.tds = new TdsCore(this.connection, messages);
} else {
this.messages = tds.getMessages();
}
}
/**
* Called when this object goes out of scope to close any
* <code>ResultSet</code> object and this statement.
*/
protected void finalize() throws Throwable {
super.finalize();
try {
close();
} catch (SQLException e) {
// Ignore errors
}
}
/**
* Get the Statement's TDS object.
*
* @return The TDS support as a <code>TdsCore</core> Object.
*/
TdsCore getTds() {
return tds;
}
/**
* Get the statement's warnings list.
*
* @return The warnings list as a <code>SQLDiagnostic</code>.
*/
SQLDiagnostic getMessages() {
return messages;
}
/**
* Check that this statement is still open.
*
* @throws SQLException if statement closed.
*/
protected void checkOpen() throws SQLException {
if (closed || connection == null || connection.isClosed()) {
throw new SQLException(
Messages.get("error.generic.closed", "Statement"), "HY010");
}
}
/**
* Check that the exception is caused by the failure to open a
* cursor and not by a more serious SQL error.
*
* @param e the exception returned by the cursor class
* @throws SQLException if exception is not due to a cursor error
*/
protected void checkCursorException(SQLException e) throws SQLException{
if (connection == null
|| connection.isClosed()
|| "HYT00".equals(e.getSQLState())
|| "HY008".equals(e.getSQLState())) {
// Serious error or timeout so return exception to caller
throw e;
}
if (connection.getServerType() == Driver.SYBASE) {
// Allow retry for Sybase
return;
}
//
// Check cursor specific errors and ranges for SQL Server
//
int error = e.getErrorCode();
if (error >= 16900 && error <= 16999) {
// Errors in this range are all related to the cursor API.
// This is true for all versions of SQL Server.
return;
}
if (error == 6819) {
// A FOR XML clause was found
return;
}
if (error == 8654) {
// A inrow textptr exists
return;
}
if (error == 8162) {
// Formal parameter '%.*ls' was defined as OUTPUT but the actual
// parameter not declared OUTPUT. This happens when trying to
// execute a stored procedure with output parameters via a cursor.
return;
}
//
// More serious error we should rethrow the error and
// not allow the driver to re-execute sql.
//
throw e;
}
/**
* 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
*/
static void notImplemented(String method) throws SQLException {
throw new SQLException(
Messages.get("error.generic.notimp", method), "HYC00");
}
/**
* Close current result set (if any).
*/
void closeCurrentResultSet() throws SQLException {
try {
if (currentResult != null) {
currentResult.close();
}
// } catch (SQLException e) {
// Ignore
} finally {
currentResult = null;
}
}
/**
* Close all result sets.
*/
void closeAllResultSets() throws SQLException {
try {
if (openResultSets != null) {
for (int i = 0; i < openResultSets.size(); i++) {
JtdsResultSet rs = (JtdsResultSet) openResultSets.get(i);
if (rs != null) {
rs.close();
}
}
}
closeCurrentResultSet();
} finally {
openResultSets = null;
}
}
/**
* Add an SQLWarning object to the statment warnings list.
*
* @param w The SQLWarning to add.
*/
void addWarning(SQLWarning w) {
messages.addWarning(w);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -