📄 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.48 2005/06/15 14:56:58 alin_sinpalean 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); /** 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 = 100; /** 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() { 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"); } } /** * 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); } /** * This method should be over-ridden by any sub-classes that place values * other than <code>String</code>s into the <code>batchValues</code> list * to handle execution properly. * * @param value SQL <code>String</code> or list of parameters to execute * @param last <code>true</code> if this is the last query/parameter list * in the batch */ protected void executeBatchOther(Object value, boolean last) throws SQLException { throw new SQLException( Messages.get("error.statement.badbatch", value.toString()), "HYC00"); } /** * Executes SQL to obtain a result set. * * @param sql the SQL statement to execute * @param spName optional stored procedure name * @param params optional parameters * @param useCursor whether a cursor should be created for the SQL * @return the result set generated by the query */ protected ResultSet executeSQLQuery(String sql, String spName, ParamInfo[] params, boolean useCursor) throws SQLException { String warningMessage = null; // // Try to open a cursor result set if required // if (useCursor) { try { if (connection.getServerType() == Driver.SQLSERVER) { currentResult = new MSCursorResultSet(this, sql, spName, params, resultSetType, resultSetConcurrency); return currentResult; } else { // Use client side cursor for Sybase currentResult = new CachedResultSet(this, sql, spName, params, resultSetType, resultSetConcurrency); return currentResult; } } catch (SQLException e) { if (connection == null || connection.isClosed() || "HYT00".equals(e.getSQLState())) { // Serious error or timeout so return exception to caller throw e; } warningMessage = '[' + e.getSQLState() + "] " + e.getMessage(); } } // // Could not open a cursor (or was not requested) so try a direct select // if (spName != null && connection.getUseMetadataCache() && connection.getPrepareSql() == TdsCore.PREPARE && colMetaData != null && connection.getServerType() == Driver.SQLSERVER) { // There is cached meta data available for this // prepared statement tds.setColumns(colMetaData); tds.executeSQL(sql, spName, params, true, queryTimeout, maxRows, maxFieldSize, true); } else { tds.executeSQL(sql, spName, params, false, queryTimeout, maxRows, maxFieldSize, true); } // Update warning chain if cursor was downgraded before processing results if (warningMessage != null) { addWarning(new SQLWarning( Messages.get("warning.cursordowngraded", warningMessage), "01000")); } // Ignore update counts preceding the result set. All drivers seem to // do this. while (!tds.getMoreResults() && !tds.isEndOfResponse()); // check for server side errors messages.checkErrors(); if (tds.isResultSet()) { currentResult = new JtdsResultSet(this, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, tds.getColumns()); } else { throw new SQLException( Messages.get("error.statement.noresult"), "24000"); } return currentResult; } /** * Executes any type of SQL. * * @param sql the SQL statement to execute
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -