📄 tdsstatement.java
字号:
//
// Copyright 1998 CDS Networks, Inc., Medford Oregon
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. All advertising materials mentioning features or use of this software
// must display the following acknowledgement:
// This product includes software developed by CDS Networks, Inc.
// 4. The name of CDS Networks, Inc. may not be used to endorse or promote
// products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY CDS NETWORKS, INC. ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL CDS NETWORKS, INC. BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
/**
* A Statement object is used for executing a static SQL statement and
* obtaining the results produced by it.
*
* <p>Only one ResultSet per Statement can be open at any point in time.
* Therefore, if the reading of one ResultSet is interleaved with the
* reading of another, each must have been generated by different
* Statements. All statement execute methods implicitly close a
* statement's current ResultSet if an open one exists.
*
* @see java.sql.Statement
* @see ResultSet
* @version $Id: TdsStatement.java,v 1.4 2002/10/22 11:22:51 alin_sinpalean Exp $
*/
package net.sourceforge.jtds.jdbc;
import java.sql.*;
public class TdsStatement implements java.sql.Statement
{
public static final String cvsVersion = "$Id: TdsStatement.java,v 1.4 2002/10/22 11:22:51 alin_sinpalean Exp $";
private TdsConnection connection; // The connection that created us
SQLWarningChain warningChain; // The warning chain
TdsResultSet results = null;
private Tds actTds = null;
private boolean escapeProcessing = true;
private int updateCount = -1;
private int maxFieldSize = (1<<31)-1;
private int maxRows = 0;
private int timeout = 0; // The timeout for a query
private int fetchSize = AbstractResultSet.DEFAULT_FETCH_SIZE;
private int fetchDir = ResultSet.FETCH_FORWARD;
private int type = ResultSet.TYPE_FORWARD_ONLY;
private int concurrency = ResultSet.CONCUR_READ_ONLY;
private boolean isClosed = false;
public TdsStatement(TdsConnection con, int type, int concurrency)
throws SQLException
{
this.connection = con;
this.warningChain = new SQLWarningChain();
this.type = type;
this.concurrency = concurrency;
}
/**
* Constructor for a Statement. It simply sets the connection
* that created us.
*
* @param con the Connection instance that creates us
*/
public TdsStatement(TdsConnection con)
throws SQLException
{
this(con, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
}
/**
* Releases <code>actTds</code> IF there are no outstanding results.
*/
protected synchronized void releaseTds() throws SQLException
{
// MJH remove test of autoCommit
if( actTds == null )
return;
// Don't free the Tds if there are any results left.
/** @todo Check if this is correct in case an IOException occurs */
if( actTds.moreResults() )
return;
try
{
connection.freeTds(actTds);
actTds = null;
}
catch (TdsException e)
{
throw new SQLException("Confusion in freeing Tds: " + e);
}
}
private void NotImplemented() throws java.sql.SQLException
{
throw new SQLException("Not Implemented");
}
/**
* Execute an SQL statement that returns a single <code>ResultSet</code>.
*
* @param sql typically a static SQL SELECT statement
* @return a <code>ResultSet</code> that contains the data produced by
* the query; never <code>null</code>
* @exception SQLException if a database access error occurs
*/
public synchronized ResultSet executeQuery(String sql) throws SQLException
{
checkClosed();
if( type == ResultSet.TYPE_FORWARD_ONLY &&
concurrency == ResultSet.CONCUR_READ_ONLY )
{
if( internalExecute(sql) )
return results;
else
throw new SQLException("No ResultSet was produced.");
}
else
return new CursorResultSet(this, sql, fetchDir);
}
/**
* This is the internal function that all subclasses should call.
* It is not executeQuery() to allow subclasses (in particular
* CursorResultSet) to override that functionality without
* breaking the internal methods.
*
* @param sql any SQL statement
* @return true if the next result is a ResulSet, false if it is
* an update count or there are no more results
* @exception SQLException if a database access error occurs
*/
public final synchronized boolean internalExecute(String sql) throws SQLException
{
checkClosed();
return executeImpl(getTds(false), sql, warningChain);
}
public final synchronized boolean internalExecute(String sql, Tds tds, SQLWarningChain wChain) throws SQLException
{
checkClosed();
return executeImpl(tds, sql, wChain);
}
private final boolean executeImpl(Tds tds, String sql, SQLWarningChain wChain)
throws SQLException
{
// Clear warnings, otherwise the last exception will be thrown.
wChain.clearWarnings();
updateCount = -1;
// Consume all outstanding results. Otherwise it will either deadlock,
// crash or return results from the previous query.
skipToEnd();
try
{
if( escapeProcessing )
sql = Tds.toNativeSql(sql, tds.getServerType());
tds.executeQuery(sql, this, wChain, timeout);
}
catch(java.io.IOException e)
{
throw new SQLException("Network error: " + e.getMessage());
}
catch(net.sourceforge.jtds.jdbc.TdsException e)
{
throw new SQLException("TDS error: " + e.getMessage());
}
// SAfe We must do this to ensure we throw SQLExceptions on timed out
// statements
wChain.checkForExceptions();
return getMoreResults(tds, wChain, true);
}
public final synchronized boolean internalExecuteCall(String name, ParameterListItem[] formalParameterList,
ParameterListItem[] actualParameterList, Tds tds, SQLWarningChain wChain) throws SQLException
{
checkClosed();
return executeCallImpl(tds, name, formalParameterList, actualParameterList, wChain);
}
private boolean executeCallImpl(Tds tds, String name, ParameterListItem[] formalParameterList,
ParameterListItem[] actualParameterList, SQLWarningChain wChain) throws SQLException
{
wChain.clearWarnings();
// SAfe This is where all outstanding results must be skipped, to make
// sure they don't interfere with the the current ones.
skipToEnd();
boolean result;
try {
// execute the stored procedure.
tds.executeProcedure(name, formalParameterList, actualParameterList, this, wChain, getQueryTimeout());
result = getMoreResults(tds, warningChain, true);
}
catch ( TdsException e ) {
throw new SQLException( e.toString() );
}
catch ( java.io.IOException e ) {
throw new SQLException( e.toString() );
}
finally {
tds.comm.packetType = 0;
}
return result;
}
/**
* Execute a SQL INSERT, UPDATE or DELETE statement. In addition
* SQL statements that return nothing such as SQL DDL statements
* can be executed
*
* Any IDs generated for AUTO_INCREMENT fields can be retrieved
* by looking through the SQLWarning chain of this statement
* for warnings of the form "LAST_INSERTED_ID = 'some number',
* COMMAND = 'your sql'".
*
* @param sql an SQL statement
* @return either a row count, or 0 for SQL commands
* @exception SQLException if a database access error occurs
*/
public synchronized int executeUpdate(String sql) throws SQLException
{
checkClosed();
if( internalExecute(sql) )
{
skipToEnd();
throw new SQLException("executeUpdate can't return a result set");
}
else
{
int res = getUpdateCount();
// We should return 0 (at least that's what the javadoc above says)
return res==-1 ? 0 : res;
}
}
protected synchronized void closeResults(boolean allowTdsRelease)
throws java.sql.SQLException
{
if( results != null )
{
results.close(allowTdsRelease);
results = null;
}
}
/**
* Eats all available input from the server. Not very efficient (since it
* reads in all data by creating <code>ResultSets</code> and processing
* them), but at least it works (the old version would crash when reading in
* a row because it didn't have any information about the row's Context).
* <p>
* This could be changed to use the <code>TdsComm</code> to read in all the
* server response without processing it, but that requires some changes in
* <code>TdsComm</code>, too.
*/
protected synchronized void skipToEnd() throws java.sql.SQLException
{
if( actTds != null )
{
// SAfe This is the only place we should send a CANCEL packet
// ourselves. We can't do that in Tds.discardResultSet because
// we could cancel other results when what we want is to only
// close the ResultSet in order to get the other results.
// SAfe On a second thought, we'd better not cancel the execution.
// Someone could run a big update script and not process all
// the results, thinking that as long as there were no
// exceptions, all went right, but we would cancel the script.
// Anyway, this was a good test for the cancel mechanism. :o)
// try
// {
// if( actTds.moreResults() )
// actTds.cancel();
// }
// catch( java.io.IOException ex )
// {
// throw new SQLException(ex.toString());
// }
// catch( TdsException ex )
// {
// throw new SQLException(ex.toString());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -