src.com.ibm.as400.access.AS400JDBCStatement Maven / Gradle / Ivy
Show all versions of jt400-jdk8 Show documentation
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: AS400JDBCStatement.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 1997-2018 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.math.BigDecimal;
import java.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.Vector;
// @E6C - Changed javadoc paragraph about thread-safety.
/**
The AS400JDBCStatement class provides a mechanism for
executing static SQL statements. Use Connection.createStatement()
to create new Statement objects.
Only one result set per statement can be open at any point in time.
Therefore, if an application needs to read from multiple result sets,
then each must be generated by a different statement.
AS400JDBCStatements are thread-safe.
Note that the connection keeps a reference to each statement that
it creates. This means that statements will not get garbage collected
until the connection gets garbage collected. It is best to
explicitly close statements rather than counting on garbage collection.
**/
//
// Implementation notes:
//
// 1. The RPB is used to provide parameters for requests.
// If we make a request without specifying some of the
// parameters, then the system will look in the RPB.
//
// Specifically, we use an RPB for each statement object to
// store parameters that do not depend on the SQL statement:
//
// * cursor name
// * statement name
//
// 2. There are many package-scope members in this class
// heirarchy which really should be "private protected".
// However, that is no longer allowed in Java, so we
// at least limit access out the the package. They
// are not intended to be used outside of the class
// hierarchy.
//
public class AS400JDBCStatement
/* ifdef JDBC40
extends ToolboxWrapper
endif */
implements Statement
{
static final String copyright = "Copyright (C) 1997-2018 International Business Machines Corporation and others.";
// Constants.
static final int MAX_CURSOR_NAME_LENGTH_PRE_V6R1 = 18; //@550C
static final int MAX_CURSOR_NAME_LENGTH = 128; //@550A
// Constants for generated key support
static final int RETURN_GENERATED_KEYS = 1; //@G4A
static final int NO_GENERATED_KEYS = 2; //@G4A
static final int GENERATED_KEYS_NOT_SPECIFIED = -9999; //@G4A
// Private data.
boolean allowImmediate_; // private protected
private int autoGeneratedKeys_; // @G4A
Vector batch_; // private protected
private String blockCriteria_;
private int blockSize_;
boolean cancelled_;
private boolean closed_;
private boolean closeOnCompletion_; //@D7A
AS400JDBCConnection connection_; // private protected
boolean connectionReset_; // Connection is reset and must be reprepared
JDCursor cursor_; // private protected
private String cursorDefaultName_;
private boolean escapeProcessing_;
protected DBExtendedColumnDescriptors extendedColumnDescriptors_; // @F3A@P6C
private int fetchDirection_;
private int fetchSize_;
private AS400JDBCResultSet generatedKeys_; // @G4A
int id_; // private protected
AS400JDBCStatementLock internalLock_; // private protected // @E6A@C7C
/* private boolean lastPrepareContainsLocator_; // @B2A @Z5D*/
private int maxFieldSize_;
private int maxRows_;
private long longMaxRows_;
int rowsInserted_; // for block insert @G5A
private String name_;
private String nameOverride_;
private int numberOfResults_; // private protected
private int positionOfSyntaxError_; //@F10A
private boolean prefetch_; // private protected
int queryTimeout_; /*@D4A*/
private boolean queryTimeoutSet_ = false; /*@B2A*/
AS400JDBCResultSet resultSet_; // private protected
private int rowCountEstimate_; // @ECA
private boolean rpbCreated_;
private boolean rpbQueryTimeoutChanged_; //@EFA
private boolean rpbSyncNeeded_;
JDPackageManager packageManager_; // private protected
int resultSetConcurrency_; // private protected
private int resultSetHoldability_; //@G4A
private int resultSetType_;
SQLConversionSettings settings_; // private protected
private SQLWarning sqlWarning_;
JDTransactionManager transactionManager_; // private protected
int updateCount_; // private protected
private String packageCriteria_; // @A1A
int behaviorOverride_ = 0; // @F9a
private boolean associatedWithLocators_ = false; //@KBL set to true, if this statement was used to access a locator
private boolean holdStatement_ = false; //@KBL set to true, if rpb and ors for this statement should be left open until a transaction boundary
boolean useVariableFieldCompression_ = false; //@K54 does connection allow compression
boolean useVariableFieldInsertCompression_ = false; //@K54 does connection allow compressions
private boolean isPoolable_ = false; //@PDA jdbc40
JDServerRow parameterRow_; // private protected //@re-prep moved from preparedStatement so that it has visibility here
private boolean threadInterrupted = false;
private DBReplyRequestedDS commonExecuteReply = null; // reply from commonExecute. Note: This cannot be returned to the pool until it is
// no longer being used. The data_ pointer from this reply is shared with
// all kinds of objects.
// Note: Because of the current structure, this can be returned after it is used. The data_
// pointer from the reply was created by ClientAccessDataStream.construct. The returnToPool
// method for the reply has been corrected to set the data_ pointer back to DBStorage_.data.
// @B5A
private DBReplyRequestedDS connectReply = null;
private DBReplyRequestedDS execImmediateReply = null;
private DBReplyRequestedDS normalPrepareReply = null;
private DBReplyRequestedDS getMoreResultsReply = null;
private boolean queryRunning_; // Used to determine whether or not we need to track}
// a QueryCancelThread. @D4A
private AS400JDBCQueryCancelThread cancelThread_; /*@D4A*/
boolean disableRllCompression_ = false; //@L9A
JDSQLStatement currentJDSQLStatement_ = null;
Exception creationLocation_;
/**
Constructs an AS400JDBCStatement object.
@param connection The connection to the system.
@param id The id.
@param transactionManager The transaction manager for the connection.
@param packageManager The package manager for the connection.
@param blockCriteria The block criteria.
@param blockSize The block size (in KB).
@param prefetch Indicates if prefetching data.
@param packageCriteria The package criteria.
@param resultSetType The result set type.
@param resultSetConcurrency The result set concurrency.
@param resultSetHoldability The result set holdability.
@param autoGeneratedKeys Indicates if auto generated keys were requested.
@exception SQLException If an error occurs.
**/
AS400JDBCStatement (AS400JDBCConnection connection,
int id,
JDTransactionManager transactionManager,
JDPackageManager packageManager,
String blockCriteria,
int blockSize,
boolean prefetch,
String packageCriteria, // @A1C
int resultSetType,
int resultSetConcurrency,
int resultSetHoldability, // @G4A
int autoGeneratedKeys) // @G4A
throws SQLException
{
// Initialization.
allowImmediate_ = true;
autoGeneratedKeys_ = autoGeneratedKeys; // @G4A
//@P0Dbatch_ = new Vector ();
blockCriteria_ = blockCriteria;
blockSize_ = blockSize;
cancelled_ = false;
closed_ = false;
connection_ = connection;
escapeProcessing_ = true;
fetchDirection_ = ResultSet.FETCH_FORWARD;
fetchSize_ = 0;
id_ = id;
internalLock_ = new AS400JDBCStatementLock(); // @E6A
maxFieldSize_ = 0;
maxRows_ = 0;
longMaxRows_ = 0;
numberOfResults_ = 0;
prefetch_ = prefetch;
queryTimeout_ = 0;
resultSet_ = null;
transactionManager_ = transactionManager;
updateCount_ = -1;
packageManager_ = packageManager;
resultSetConcurrency_ = resultSetConcurrency;
resultSetHoldability_ = resultSetHoldability; //@G4A
resultSetType_ = resultSetType;
rpbCreated_ = false;
rpbQueryTimeoutChanged_ = false; //@EFA
rpbSyncNeeded_ = true;
settings_ = SQLConversionSettings.getConversionSettings (connection_);
sqlWarning_ = null;
packageCriteria_ = packageCriteria; // @A1A
// By default, the statement name and cursor name are
// based on the id.
String idString = "0000" + id;
String idString4 = idString.substring (idString.length() - 4);
name_ = "STMT" + idString4;
useVariableFieldInsertCompression_ = connection_.useVariableFieldInsertCompression();
if(resultSetType_ == ResultSet.TYPE_FORWARD_ONLY) // @B1A
{
cursorDefaultName_ = "CRSR" + idString4;
if(connection_.useVariableFieldCompression()) //@K54
useVariableFieldCompression_ = true; //@K54
}
else // @B1A
cursorDefaultName_ = "SCRSR" + idString4; // @B1A
// @E4D // Use lazy close only when the "lazy close" property @E4A
// @E4D // has been set AND the old auto-commit support is @E4A
// @E4D // still in effect. @E4A
// @E4D boolean lazyClose = connection_.getProperties().getBoolean(JDProperties.LAZY_CLOSE) // @E4A
// @E4D && transactionManager_.isNewAutoCommitSupport(); // @E4A
cursor_ = new JDCursor (connection_, id_, cursorDefaultName_, resultSetConcurrency_); // @E4C @EAC
//@F4 If the user specified a holdability, then we must check the holdability of
//@F4 statements on a Connection.commit or Connection.rollback. Thought about just
//@F4 setting this flag to true if the holdability was different than the connection
//@F4 holdability, but the connection holdability can change above us.
if(resultSetHoldability != AS400JDBCResultSet.HOLDABILITY_NOT_SPECIFIED) //@F4A
{
//@F4A
connection.setCheckStatementHoldability(true); //@F4A
} //@F4A
try // @F9a
{
// @F9a
behaviorOverride_ = connection_.getProperties().getInt(JDProperties.BEHAVIOR_OVERRIDE); // @F9a
} // @F9a
catch(Throwable t)
{
} // @F9a
// Trace messages.
if(JDTrace.isTraceOn())
{
JDTrace.logOpen (this, connection_); // @J33c
JDTrace.logProperty (this, "AS400JDBCStatement.init", "Escape processing", escapeProcessing_);
JDTrace.logProperty (this, "AS400JDBCStatement.init", "Fetch direction", fetchDirection_);
JDTrace.logProperty (this, "AS400JDBCStatement.init", "Fetch size", fetchSize_);
JDTrace.logProperty (this, "AS400JDBCStatement.init", "Max field size", maxFieldSize_);
JDTrace.logProperty (this, "AS400JDBCStatement.init", "Max rows", maxRows_);
JDTrace.logProperty (this, "AS400JDBCStatement.init", "Query timeout", queryTimeout_);
JDTrace.logProperty (this, "AS400JDBCStatement.init", "Result set concurrency", resultSetConcurrency_);
JDTrace.logProperty (this, "AS400JDBCStatement.init", "Result set holdability", resultSetHoldability_); //@F4A
JDTrace.logProperty (this, "AS400JDBCStatement.init", "Result set type", resultSetType_);
JDTrace.logProperty (this, "AS400JDBCStatement.init", "Behavior Override", behaviorOverride_); // @F9a
String cursorAsString = JDTrace.objectToString(cursor_); // @J33a
JDTrace.logInformation(this, "Data to correlate statement with cursor " + cursorAsString); // @J33a
creationLocation_ = new Exception("creationLocation_");
}
}
// Constructor for wrapper
protected AS400JDBCStatement() {
}
// JDBC 2.0
/**
Adds an SQL statement to the current batch of SQL statements.
@param sql The SQL statement to be added to the current batch.
This can be any SQL statement that does not return
a result set.
@exception SQLException If the statement is not open or
the SQL statement contains a syntax
error.
**/
public void addBatch (String sql)
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
settings_.getDecimalSeparator (), escapeProcessing_,
packageCriteria_, connection_); //@G4C
currentJDSQLStatement_ = sqlStatement;
// Validate that no parameters are set, since parameters
// imply the need for a PreparedStatement.
if(sqlStatement.countParameters () > 0)
JDError.throwSQLException (JDError.EXC_PARAMETER_COUNT_MISMATCH);
if(batch_ == null) batch_ = new Vector(); //@P0A
batch_.addElement (sqlStatement);
}
}
/**
Cancels the statement. This is useful when one thread
needs to cancel a statement that is being executed by another
thread. This will close the current result set.
@exception SQLException If the statement is not open or
an error occurs.
**/
public void cancel ()
throws SQLException
{
// Don't synchronize this method... it needs to be callable // @E6A
// even when the statement is busy. // @E6A
checkOpen ();
connection_.cancel(id_); // @E5A
cancelled_ = true;
closeResultSet (JDCursor.REUSE_YES);
}
/**
Checks that the statement is open. Public methods
that require an open statement should call this first.
@exception SQLException If the statement is not open.
**/
void checkOpen ()
throws SQLException
{
connection_.checkOpen ();
if(closed_)
JDError.throwSQLException (JDError.EXC_FUNCTION_SEQUENCE);
}
// JDBC 2.0
/**
Clears the current batch of SQL statements.
@exception SQLException If the statement is not open.
**/
public void clearBatch ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
if(batch_ == null) batch_ = new Vector(); //@P0A
batch_.removeAllElements ();
}
}
/**
Clears all warnings that have been reported for the statement.
After this call, getWarnings() returns null until a new warning
is reported for the statement.
@exception SQLException If an error occurs.
**/
public void clearWarnings ()
throws SQLException
{
sqlWarning_ = null;
}
/**
Releases the statement's resources immediately instead of waiting
for them to be automatically released. This closes the current
result set.
@exception SQLException If an error occurs.
**/
//
// Implementation note:
//
// It is a requirement to not get replies during a finalize()
// method. Since finalize() calls this method, this requirement
// applies here, too.
//
public void close ()
throws SQLException
{
synchronized(connection_) { /* lock the connection to prevent deadlock with connection.rollback */
synchronized(internalLock_)
{ // @E6A
// If this is already closed, then just do nothing.
//
// The spec does not define what happens when a connection
// is closed multiple times. The official word from the Sun
// JDBC team is that "the driver's behavior in this case
// is implementation defined. Applications that do this are
// non-portable."
if(isClosed ())
return;
// Close the current result set. (Note: This has no
// effect if the user explicitly closed the result set
// before closing the statement.
//@PDA perf2 comment: if we get back 700,2 from fetch, then cursor is already closed, but resultSet_ is still usable
//if(! cursor_.isClosed()) //@perf3 cursor can be closed, but resultset still needs to be closed. closeResultSet checks for closed cursor before closing cursor.
//{ // @B3A //@perf3
closeResultSet (JDCursor.REUSE_NO);
//} // @B3A //@perf3
// If, even after closing the current result set,
// there are more result sets that were returned, we
// need to close them, too. At first I though we
// would have to Open/Describe and Close each one
// in turn, but the database host server allows us to
// close the current cursor with REUSE_NO to close
// all remaining result sets. The catch is that we
// need to have an open cursor before closing it, so
// we open the next cursor, then close it again.
// This closes all remaining result sets.
if(numberOfResults_ > 1)
{
getMoreResults ();
cursor_.close (JDCursor.REUSE_NO);
}
if(generatedKeys_ != null) //@PDA genkeys
{
generatedKeys_.close();
generatedKeys_ = null;
}
//@KBL If the user specified to keep statements open until a transaction boundary and locators are associated
// with the statement, do not close the RPB or ORS until a transaction boundary is reached.
if(isAssociatedWithLocators() && (connection_.getProperties().getBoolean(JDProperties.HOLD_STATEMENTS)) && (connection_.getAutoCommit() == false))
{
setHoldStatement(true);
closed_ = true; // Want the statement to only be available for use internally, user should not be able to use the statement.
if (commonExecuteReply != null) { commonExecuteReply.returnToPool(); commonExecuteReply = null; }
if (connectReply != null) { connectReply.returnToPool(); connectReply = null; }
if (execImmediateReply != null) { execImmediateReply.returnToPool(); execImmediateReply = null; }
if (normalPrepareReply != null) { normalPrepareReply.returnToPool(); normalPrepareReply = null; }
if (getMoreResultsReply != null) { getMoreResultsReply.returnToPool(); getMoreResultsReply = null; }
return; // Mark the statement as closed, but don't notify the connection it has been closed or delete the RPB and ORS.
}
// Delete the RPB. Remember the error information @EDC
// in order to report later... @EDC
SQLException e = null; // @EDA
if(rpbCreated_ && !connectionReset_)
{ // @EDA
DBSQLRPBDS request3 = null; //@P0A
DBReplyRequestedDS closeReply = null; //@P0A
try
{ //@P0A
request3 = DBDSPool.getDBSQLRPBDS(DBSQLRPBDS.FUNCTIONID_DELETE_RPB, id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA, 0); //@P0C
closeReply = connection_.sendAndReceive(request3, id_); // @EDC @P0C
int errorClass = closeReply.getErrorClass(); // @EDA
int returnCode = closeReply.getReturnCode(); // @EDA
if(errorClass != 0)
{ // @EDA
if(returnCode < 0)
{ // @EDA
try
{ // @EDA
JDError.throwSQLException(this, connection_, id_, errorClass, returnCode); // @EDA
} // @EDA
catch(SQLException e2)
{ // @EDA
e = e2; // @EDA
} // @EDA
} // @EDA
else
{ // @EDA
postWarning (JDError.getSQLWarning(connection_, id_, errorClass, returnCode)); // @EDA
} // @EDA
} // @EDA
}
finally
{ //@P0A
if(request3 != null) {
request3.returnToPool(); request3=null;
}
if(closeReply != null) {
closeReply.returnToPool();closeReply=null;
}
}
} // @EDA
// Delete the ORS.
//
// @EDD // We must use get a reply here even though we do not
// @EDD // need any information from it. Otherwise the next
// @EDD // flow would be based on this ORS, which gets deleted.
// @EDD // In that case, we would always get an "ORS not found"
// @EDD // error.
// @EDD //
// @EDD // In this case, we also need it to force a send of
// @EDD // all of the previous datastreams, since this is the
// @EDD // last one for this statement.
//
// Make sure not to base future requests on this ORS. // @EDA
//
//@P0DDBSQLResultSetDS request2 = new DBSQLResultSetDS (
//@P0D DBSQLResultSetDS.FUNCTIONID_DELETE_RESULTS_SET,
//@P0D id_, 0, 0); // @EDC
DBSQLResultSetDS request2 = null; //@P0A
try
{ //@P0A
request2 = DBDSPool.getDBSQLResultSetDS(DBSQLResultSetDS.FUNCTIONID_DELETE_RESULTS_SET, id_, 0, 0); //@P0C
if (!connectionReset_) {
connection_.send(request2, id_, false); // @EDC
}
}
finally
{ //@P0A
if(request2 != null) {
request2.returnToPool(); request2=null;
}
}
// Ignore errors, since we would not be able to get
// the message text anyway (because the ORS is gone.)
// free the pooled commonExecuteReply
if (commonExecuteReply != null) { commonExecuteReply.returnToPool(); commonExecuteReply = null; }
if (connectReply != null) { connectReply.returnToPool(); connectReply = null; }
if (execImmediateReply != null) { execImmediateReply.returnToPool(); execImmediateReply = null; }
if (normalPrepareReply != null) { normalPrepareReply.returnToPool(); normalPrepareReply = null; }
if (getMoreResultsReply != null) { getMoreResultsReply.returnToPool(); getMoreResultsReply = null; }
closed_ = true;
connection_.notifyClose (this, id_);
if(JDTrace.isTraceOn())
JDTrace.logClose (this);
// Rethrow any exception that surfaced when deleting the RPB. @EDA
if(e != null) // @EDA
throw e; // @EDA
}
}
}
//@KBL
/*
Finish releasing a partially-closed statement's resources. A statement may become partially closed if, for example,
the user called close on the statement and it was associated with a locator.
This method will delete any RPB and ORS associated with the statement.".
@exception SQLException if an error occurs
*/
void finishClosing()
throws SQLException
{
synchronized(internalLock_)
{
// Delete the RPB. Remember the error information
// in order to report later...
SQLException e = null;
if(rpbCreated_)
{
DBSQLRPBDS request3 = null;
DBReplyRequestedDS finishClosingReply = null;
try
{
request3 = DBDSPool.getDBSQLRPBDS(DBSQLRPBDS.FUNCTIONID_DELETE_RPB, id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA, 0); //@P0C
finishClosingReply = connection_.sendAndReceive(request3, id_);
int errorClass = finishClosingReply.getErrorClass();
int returnCode = finishClosingReply.getReturnCode();
if(errorClass != 0)
{
if(returnCode < 0)
{
try
{
JDError.throwSQLException(this, connection_, id_, errorClass, returnCode);
}
catch(SQLException e2)
{
e = e2;
}
}
else
{
postWarning (JDError.getSQLWarning(connection_, id_, errorClass, returnCode));
}
}
}
finally
{
if(request3 != null) { request3.returnToPool(); request3=null; }
if(finishClosingReply != null) { finishClosingReply.returnToPool(); finishClosingReply = null; }
}
}
// Delete the ORS.
//
// We must use get a reply here even though we do not
// need any information from it. Otherwise the next
// flow would be based on this ORS, which gets deleted.
// In that case, we would always get an "ORS not found"
// error.
// In this case, we also need it to force a send of
// all of the previous datastreams, since this is the
// last one for this statement.
//
// Make sure not to base future requests on this ORS.
DBSQLResultSetDS request2 = null;
try
{
request2 = DBDSPool.getDBSQLResultSetDS(DBSQLResultSetDS.FUNCTIONID_DELETE_RESULTS_SET, id_, 0, 0);
connection_.send(request2, id_, false);
}
finally
{
if(request2 != null) {
request2.returnToPool(); request2 = null;
}
}
// Ignore errors, since we would not be able to get
// the message text anyway (because the ORS is gone.)
closed_ = true;
setHoldStatement(false); //the statement is no longer left open
connection_.notifyClose (this, id_);
if(JDTrace.isTraceOn())
JDTrace.logClose (this);
// Rethrow any exception that surfaced when deleting the RPB.
if(e != null)
throw e;
}
}
/**
Closes the result set and cursor.
@param reuseFlag Either JDCursor.REUSE_NO,
JDCursor.REUSE_YES, or
JDCursor.REUSE_RESULT_SET.
@exception SQLException If an error occurs.
**/
void closeResultSet (int reuseFlag) // private protected
throws SQLException
{
synchronized(internalLock_) {
if(resultSet_ != null)
{
if(! resultSet_.isClosed ())
resultSet_.close ();
resultSet_ = null;
}
}
if (threadInterrupted) {
// Force a close to be flowed
try {
cursor_.setState(false);
cursor_.close (reuseFlag);
} catch (Exception e) {
}
} else {
if(! cursor_.isClosed ())
cursor_.close (reuseFlag);
}
updateCount_ = -1;
}
/**
Executes an SQL statement on the IBM i system.
@param sqlStatement The SQL statement.
@param resultRow The result row or null if none.
@exception SQLException If the query timeout limit is
exceeded or an error occurs.
**/
//
// Do not override this method. Instead, override
// commonExecuteBefore() and commonExecuteAfter() as needed.
//
final void commonExecute (JDSQLStatement sqlStatement,
JDServerRow resultRow) // private protected
throws SQLException
{
SQLException savedException = null; /*@F3A*/
currentJDSQLStatement_ = sqlStatement;
try {
cancelled_ = false;
/*@D4A*/
if (connection_.isQueryTimeoutMechanismCancel()) {
startCancelThread();
}
/* If the connect statement has not been executed, then do it now */
/* @W4A*/
if(sqlStatement.getNativeType() == JDSQLStatement.TYPE_CONNECT && (!allowImmediate_))
{
executeConnectStatement(sqlStatement);
} else
// If the statement is not immediately executable, then
// we still need to do the execute. Otherwise, the execute
// was already done as part of the prepare.
if((! allowImmediate_) || (! sqlStatement.isImmediatelyExecutable ()))
{
//
// If using generated keys, make sure that the prefetch
// operation is disabled. If the prefetch option is not
// disabled, then it is not possible to the the updated row
// count from the insert.
// @E5
if (autoGeneratedKeys_ == RETURN_GENERATED_KEYS && prefetch_) {
prefetch_ = false;
}
// Also close the autogenerated key if it is open.
// Breaking the exec into two pieces causes this to be closed
// right after the exec if it already is open
// @E5
if (generatedKeys_ != null) {
if (!generatedKeys_.isClosed()) {
try {
generatedKeys_.close();
} catch (Exception e) {
}
}
}
// Sync up the RPB.
syncRPB ();
boolean usedNameOverride = false;
// This boolean is true when an Open is needed and
// false when an Execute is needed.
boolean openNeeded = (resultRow != null);
// If we are prefetching data and a row format
// was returned, then fetch the first block of data.
boolean fetchFirstBlock = ((prefetch_) && (openNeeded));
// Send the execute data stream.
try
{
// Determine the appropriate function id, based
// on whether we want to prefetch data, and on whether
// this is an Execute or an Open.
int functionId;
if(openNeeded)
{
if(fetchFirstBlock)
functionId = DBSQLRequestDS.FUNCTIONID_OPEN_DESCRIBE_FETCH;
else
functionId = DBSQLRequestDS.FUNCTIONID_OPEN_DESCRIBE;
}
else
functionId = DBSQLRequestDS.FUNCTIONID_EXECUTE;
DBSQLRequestDS request = null; //@P0A
// DBReplyRequestedDS replyX = null; //@P0A
int openAttributes = 0;
try
{
//@541 When running to a V5R4 or higher system, we can request to get extended column descriptors
// from a stored procedure result set. In order to do that, we need to set the extended column
// descriptor option on the execute of the statement.
boolean isCall = (sqlStatement.getNativeType () == JDSQLStatement.TYPE_CALL); //@541A moved up from farther below in code
//@F5D Send this on the prepare, not the execute
int requestedORS = DBSQLRequestDS.ORS_BITMAP_RETURN_DATA+DBSQLRequestDS.ORS_BITMAP_SQLCA; //@F3M //@541C undeleted
//@F5D //@F3A If we are on a system that supports extended column descriptors and if the //@F3A
//@F5D //@F3A user asked for them, send the extended column descriptors code point. //@F3A
boolean extendedMetaData = false; //@F3A //@541C undeleted
//@F5D if (connection_.getVRM() >= JDUtilities.vrm520) //@F3A
if(connection_.getVRM() >= JDUtilities.vrm540 && isCall) //@541A
{ //@F3A //@541C undeleted
extendedMetaData = connection_.getProperties().getBoolean(JDProperties.EXTENDED_METADATA); //@F3A //@541C undeleted
if (extendedMetaData) //@F3A //@541C undeleted
{ //@F3A //@541C undeleted
requestedORS = requestedORS + DBSQLRequestDS.ORS_BITMAP_EXTENDED_COLUMN_DESCRIPTORS; //@F3A //@541C undeleted
} //@F3A //@541C undeleted
} //@F3A //@541C undeleted
if(connection_.getVRM() >= JDUtilities.vrm610 ) { //@cur request cursor attributes //@isol
requestedORS = requestedORS + DBSQLRequestDS.ORS_BITMAP_CURSOR_ATTRIBUTES; //@cur
}
//@P0A
request = DBDSPool.getDBSQLRequestDS(functionId, id_, requestedORS, 0); //@P0C @F3C @F5C //@541C
openAttributes = cursor_.getOpenAttributes(sqlStatement, blockCriteria_); //@F7M
if(openNeeded)
{
//@F7D openAttributes = cursor_.getOpenAttributes (sqlStatement, blockCriteria_);
if((autoGeneratedKeys_ == RETURN_GENERATED_KEYS) && connection_.getVRM() >= JDUtilities.vrm610) //@GKA Wrapped INSERT WITH SELECT for generated keys. Result set should be read only, insensitive
request.setOpenAttributes(0x80); //@GKA
else //@GKA
request.setOpenAttributes(openAttributes);
}
else if(extendedMetaData){ //@541A Doing an execute. If running to V5R4 and higher, and the extendedMetaData property is true, set the extended column descriptor option
request.setExtendedColumnDescriptorOption((byte)0xF1);
}
ConvTable converter = connection_.getConverter();
if(nameOverride_.length() != 0)
{
request.setPrepareStatementName(nameOverride_, converter); //@P0C
usedNameOverride = true;
}
if(packageManager_.isEnabled() && sqlStatement.isPackaged())
{
request.setPackageName (packageManager_.getName (), converter); //@P0C
}
String cursorSensitivity = connection_.getProperties().getString(JDProperties.CURSOR_SENSITIVITY); //@H1A
// If we are prefetching data and a row format
// was returned, then set the blocking factor if a specific number of rows have been asked for
// or variable-length field compression is turned off, otherwise set the buffer size.
if(fetchFirstBlock)
{
request.addOperationResultBitmap(DBSQLRequestDS.ORS_BITMAP_RESULT_DATA);
if((functionId == DBSQLRequestDS.FUNCTIONID_OPEN_DESCRIBE_FETCH) && //@K54
(useVariableFieldCompression_)) //@K54
{
//Do not need to set the blocking factor if using variable-length field compression
//If both the buffer size and blocking factor were set, the buffer size will override
//the blocking factor and the number of rows that will fit in the buffer size will be returned
//regardless of the blocking factor value
request.setVariableFieldCompression(true);
request.setBufferSize(blockSize_ * 1024);
}
else { //@K54
if (resultRow != null) { // @B5A -- check for null pointer
request.setBlockingFactor(getBlockingFactor (cursorSensitivity, sqlStatement, resultRow.getRowLength())); //@K54 changed to just use resultRow.getRowLength() instead of fetchFirstBlock ? resultRow.getRowLength() : 0
} else {
request.setBlockingFactor(getBlockingFactor (cursorSensitivity, sqlStatement, 0)); //@K54 changed to just use resultRow.getRowLength() instead of fetchFirstBlock ? resultRow.getRowLength() : 0
}
}
}
//@K1D //@F8 If we are pre-V5R2, the user set the resultSetType to "TYPE_SCROLL_INSENSITIVE", or
//@K1D //@F8 the user did not change from the default of the "cursor sensitivity" property,
//@K1D //@F8 send what we always have.
//@K1D //@F8 Change in a future release to send CURSOR_SCROLLABLE_INSENSITIVE and
//@K1D //@F8 CURSOR_NOT_SCROLLABLE_INSENSITIVE if resultSetType_ ==
//@K1D //@F8 ResultSet.TYPE_SCROLL_INSENSITIVE to v5r1 or later hosts.
// String cursorSensitivity = connection_.getProperties().getString(JDProperties.CURSOR_SENSITIVITY); //@F8A
//@K1D if((connection_.getVRM() < JDUtilities.vrm520) //@F8A
//@K1D || (resultSetType_ == ResultSet.TYPE_SCROLL_INSENSITIVE) //@F8A
//@K1D || (cursorSensitivity.equalsIgnoreCase(JDProperties.CURSOR_SENSITIVITY_ASENSITIVE))) //@F8A
//@K1D {
//@K1D if(resultSetType_ == ResultSet.TYPE_FORWARD_ONLY)
//@K1D request.setScrollableCursorFlag (DBSQLRequestDS.CURSOR_NOT_SCROLLABLE_ASENSITIVE);
//@K1D else
//@K1D request.setScrollableCursorFlag (DBSQLRequestDS.CURSOR_SCROLLABLE_ASENSITIVE);
//@K1D }
//@K1D //@F8 If we are V5R2 or later, send new numbers based on what the user
//@K1D //@F8 set in "cursor sensitivity" property //@F8A
//@K1D else if(resultSetType_ == ResultSet.TYPE_FORWARD_ONLY)
//@K1D {
//@K1D if(cursorSensitivity.equalsIgnoreCase(JDProperties.CURSOR_SENSITIVITY_INSENSITIVE)) //@F8A
//@K1D request.setScrollableCursorFlag (DBSQLRequestDS.CURSOR_NOT_SCROLLABLE_INSENSITIVE); //@F8A
//@K1D else //else property set to sensitive //@F8A
//@K1D request.setScrollableCursorFlag (DBSQLRequestDS.CURSOR_NOT_SCROLLABLE_SENSITIVE); //@F8A
//@K1D }
//@K1D //@F8 Else, resultSetType_ is ResultSet.TYPE_CURSOR_SENSITIVE
//@K1D else
//@K1D {
//@K1D if(cursorSensitivity.equalsIgnoreCase(JDProperties.CURSOR_SENSITIVITY_INSENSITIVE)) //@F8A
//@K1D request.setScrollableCursorFlag (DBSQLRequestDS.CURSOR_SCROLLABLE_INSENSITIVE); //@F8A
//@K1D else //else property set to sensitive //@F8A
//@K1D request.setScrollableCursorFlag(DBSQLRequestDS.CURSOR_SCROLLABLE_SENSITIVE); //@F8A
//@K1D }
//If earlier than V5R2, do what we always have //@K1A
if(connection_.getVRM() < JDUtilities.vrm520) //@K1A
{
//@K1A
if(resultSetType_ == ResultSet.TYPE_FORWARD_ONLY) //@K1A
request.setScrollableCursorFlag (DBSQLRequestDS.CURSOR_NOT_SCROLLABLE_ASENSITIVE); //@K1A Option 0
else //@K1A
request.setScrollableCursorFlag (DBSQLRequestDS.CURSOR_SCROLLABLE_ASENSITIVE); //@K1A Option 1
} //@K1A
else if ((autoGeneratedKeys_ == RETURN_GENERATED_KEYS) && connection_.getVRM() >= JDUtilities.vrm610) //@GKA
{ //@GKA
// The user requested generated keys so we wrapped the INSERT with a SELECT //@GKA
// The result set returned will be for the generated keys and should be read-only, insensitive //@GKA
// We want to ignore any property or settings specified on the STATEMENT or CONNECTION //@GKA
request.setScrollableCursorFlag(DBSQLRequestDS.CURSOR_SCROLLABLE_INSENSITIVE); //@GKA
} //@GKA
else {
/* @H1A Use common routine to determine scrollability */
request.setScrollableCursorFlag(
AS400JDBCResultSet.getDBSQLRequestDSCursorType(cursorSensitivity, resultSetType_, resultSetConcurrency_));
}
// Check system level before sending new code point
if(connection_.getVRM() >= JDUtilities.vrm520) // @G4A
{
// @G4A
if(resultSetHoldability_ == AS400JDBCResultSet.CLOSE_CURSORS_AT_COMMIT) // @G4A
request.setResultSetHoldabilityOption((byte)0xD5); // @G4A
else if(resultSetHoldability_ == AS400JDBCResultSet.HOLD_CURSORS_OVER_COMMIT) // @G4A
request.setResultSetHoldabilityOption((byte)0xE8); // @G4A
// else resultSetHoldability_ == AS400JDBCResultSet.HOLDABILITY_NOT_SPECIFIED, // @G4A
// so don't send the code point because the user did not tell us to // @G4A
}
disableRllCompression_ = false; //@L9A
commonExecuteBefore(sqlStatement, request);
if (commonExecuteReply != null) { commonExecuteReply.returnToPool(); commonExecuteReply=null; }
if (disableRllCompression_) { //@L9A
connection_.setDisableCompression(true);
}
commonExecuteReply = connection_.sendAndReceive(request, id_); //@P0C
if (disableRllCompression_) { //@L9A
connection_.setDisableCompression(false);
}
// Gather information from the reply.
cursor_.processConcurrencyOverride(openAttributes, commonExecuteReply); // @E1A @EAC
cursor_.processCursorAttributes(commonExecuteReply); //@cur
transactionManager_.processCommitOnReturn(commonExecuteReply); // @E2A
Vector SQLCAs = commonExecuteReply.getSQLCAs();
DBReplySQLCA firstSqlca = null;
if (SQLCAs != null) {
firstSqlca = (DBReplySQLCA) SQLCAs.elementAt(0);
}
DBData resultData = null;
if(fetchFirstBlock) resultData = commonExecuteReply.getResultData();
// Note the number of rows inserted/updated
if (firstSqlca != null) {
rowsInserted_ = firstSqlca.getErrd(3); // @G5A
}
// Check for system errors. Take note on prefetch
// if the last block was fetched.
int errorClass = commonExecuteReply.getErrorClass();
int returnCode = commonExecuteReply.getReturnCode();
//
// Check for the case where the errorClass is zero, but there
// is truncation. If so, set the errorClass to 2 so the
// warning is processed.
// @S2A
if (errorClass == 0) {
Enumeration enumeration = SQLCAs.elements();
while (enumeration.hasMoreElements()) {
DBReplySQLCA thisSqlca = (DBReplySQLCA) enumeration
.nextElement();
String sqlState = thisSqlca.getSQLState(converter);
if ("01004".equals(sqlState)) {
errorClass = 2;
}
}
}
// NOTE: We currently do not have a good way to handle the case
// when the exit program rejects the request.
//
// Error Class: 0x0008 - Exit Program Error
// Error Return Code: -101 - User exit program rejected request.
//
// Currently, an empty SQLCA is returned which causes an
// array index out of bounds exception when calling
// DBReplySQLCA.getErrp below.
//
// Remember that a cursor is open even when most
// errors occur.
//
// Except:
// * When a query timeout occurs, the system
// does not leave a cursor open.
if(openNeeded && (errorClass != 1 || returnCode != -666)) cursor_.setState(false);
// Take note on prefetch if the last block was fetched.
boolean lastBlock = false;
if((((errorClass == 1) && (returnCode == 100))
|| ((errorClass == 2) && (returnCode == 701)))
&& functionId == DBSQLRequestDS.FUNCTIONID_OPEN_DESCRIBE_FETCH) // make sure we attempted to prefetch data, otherwise post a warning
{
lastBlock = true;
returnCode = firstSqlca.getSQLCode(); //@pda (issue 32120) get rc from SQLCA
String sqlState = firstSqlca.getSQLState (converter); //@issue 34500
}
else if((errorClass == 2) && (returnCode == 700)
&& (functionId == DBSQLRequestDS.FUNCTIONID_OPEN_DESCRIBE_FETCH)) //@pda perf2 - fetch/close
{
lastBlock = true;
cursor_.setState(true); //closed cursor already on system
returnCode = firstSqlca.getSQLCode(); //@pda (issue 32120) get rc from SQLCA
String sqlState = firstSqlca.getSQLState (converter); //@issue 34500
}
//else //@PDD check for errors even on cases above (issue 32120)
if(errorClass != 0 ) //@pdc (issue 32120)
{
positionOfSyntaxError_ = firstSqlca.getErrd(5); //@F10A
if(returnCode < 0)
{
//
// Check if error came from a combined opened fetch...
// If so, delay error until fetch occurs. @F3A
//
int errd6 = firstSqlca.getErrd(6);
String errp = firstSqlca.getErrp(converter); /*@N7A*/
if ( errd6 == 1 ||
( "QSQFETCH".equals(errp) &&
(functionId == DBSQLRequestDS.FUNCTIONID_OPEN_DESCRIBE_FETCH))) {
// Delay error
// Only delay error from fetch if coming from open_describe_fetch @O8A
try {
JDError.throwSQLException(this, connection_, id_, errorClass, returnCode);
} catch (SQLException e) {
savedException = e;
}
} else {
JDError.throwSQLException(this, connection_, id_, errorClass, returnCode);
}
}
else
{
Enumeration enumeration = SQLCAs.elements();
while (enumeration.hasMoreElements()) {
DBReplySQLCA thisSqlca = (DBReplySQLCA) enumeration.nextElement();
String sqlState = thisSqlca.getSQLState (converter); //@igwrn
if(sqlState.startsWith("00") || sqlState.startsWith("02")) { //@pda (issue 32120) //@issue 34500 //@35199
// Do not post this warning.
} else {
postWarning(JDError.getSQLWarning(connection_, id_, errorClass, returnCode));
}
}
}
}
//Make an auto-generated key result set if it was requested //@G4A
if(autoGeneratedKeys_ == RETURN_GENERATED_KEYS && //@G4A
(connection_.getVRM() >= JDUtilities.vrm520) &&
((connection_.getVRM() < JDUtilities.vrm610) || !sqlStatement.isSelectFromInsert())) //@F5A @F6C @GKC
//@F6D&& generatedKeys_ == null) //@F5A
makeGeneratedKeyResultSet(returnCode, firstSqlca); //@G4A
else if(generatedKeys_ != null) //@PDA genkeys - handle previous genkeys
{
generatedKeys_.close();
generatedKeys_ = null;
}
//@F5D This belongs on the prepare, not the execute
//@F5D @F3A If user asked us to parse out extended metadata, then make an object
//@K3A Added back.. This belongs here for stored procedure result sets
// extendedMetaData is set to true only for all statements.
if (extendedMetaData) //@F3A
{ //@F3A
extendedColumnDescriptors_ = commonExecuteReply.getExtendedColumnDescriptors(); //@F3A
} //@F3A
// Compute the update count and result set .
if(openNeeded)
{
// @B5A Check for null pointer.
int rowLength = 0;
if (resultRow != null) {
rowLength = resultRow.getRowLength();
}
JDServerRowCache rowCache;
if((fetchFirstBlock) && (resultData != null))
rowCache = new JDServerRowCache (resultRow,
connection_, id_,
getBlockingFactor (cursorSensitivity, sqlStatement, rowLength), resultData,
lastBlock, resultSetType_, cursor_); //@pdc perf2 - fetch/close
else
rowCache = new JDServerRowCache (resultRow,
connection_, id_,
getBlockingFactor (cursorSensitivity, sqlStatement, rowLength), lastBlock, resultSetType_, cursor_); //@PDC perf //@pdc perf2 - fetch/close
// If the result set concurrency is updatable, check to @E1C
// see if the system overrode the cursor type to read only. @E1C
// Don't worry about the other direction (system overrides @E1C
// from read-only to updatable). @E1C
int actualConcurrency = (resultSetConcurrency_ == ResultSet.CONCUR_UPDATABLE) // @E1C
? cursor_.getConcurrency() : resultSetConcurrency_; // @E1C @EAC
if((autoGeneratedKeys_ == RETURN_GENERATED_KEYS) &&
(connection_.getVRM() >= JDUtilities.vrm610) &&
sqlStatement.isSelectFromInsert()) //@GKA
{
// this will be the generated keys result set //@GKA
updateCount_ = firstSqlca.getErrd(3); //@GKA
rowCountEstimate_ = -1; //@GKA
generatedKeys_ = new AS400JDBCResultSet (this, sqlStatement, rowCache, connection_.getCatalog(),//@GKA
cursor_.getName(), maxRows_, //@GKA
ResultSet.TYPE_SCROLL_INSENSITIVE, //@GKA
ResultSet.CONCUR_READ_ONLY, fetchDirection_, fetchSize_,
extendedColumnDescriptors_); //@GKA@P6A
} //@GKA
else //@GKA
{ //@GKA
updateCount_ = -1; // @ECM
rowCountEstimate_ = firstSqlca.getErrd (3); //@F1C // @ECA
resultSet_ = new AS400JDBCResultSet (this,
sqlStatement, rowCache, connection_.getCatalog(),
cursor_.getName(), maxRows_, resultSetType_,
actualConcurrency, fetchDirection_, fetchSize_,
extendedColumnDescriptors_); // @E1C@P6A
if(resultSet_.getConcurrency () != resultSetConcurrency_ && resultSetConcurrency_ == ResultSet.CONCUR_UPDATABLE) //@nowarn only warn if concurrency level is lessened
postWarning (JDError.getSQLWarning (JDError.WARN_OPTION_VALUE_CHANGED));
if (savedException != null) { /*@F3A*/
resultSet_.addSavedException(savedException);
}
} //@GKA
}
else
{
updateCount_ = firstSqlca.getErrd (3); //@F1C
rowCountEstimate_ = -1; // @ECC
}
// Compute the number of results.
//@541D boolean isCall = (sqlStatement.getNativeType () == JDSQLStatement.TYPE_CALL);
if(isCall)
numberOfResults_ = firstSqlca.getErrd (2); //@F1C
else
numberOfResults_ = 0;
if(extendedMetaData) //@541A
{
extendedColumnDescriptors_ = commonExecuteReply.getExtendedColumnDescriptors (); //@F5A
cursor_.setExtendedMetaData(extendedMetaData); //@K3A
}
// If this is a CALL and result sets came back, but
// no format was returned, then open the cursor. The
// result set must be forward only and read only.
// This is a system restriction. @EBA
// As of V5R3 the restriction to be forward only no longer applies @KBA
if(sqlStatement != null)
{
if((isCall) && (numberOfResults_ > 0) && (resultSet_ == null))
{
boolean preV5R3 = connection_.getVRM() < JDUtilities.vrm530;
// Change the result set type based on the current attributes
// unless forward only cursors were requested. This must
// be kept in sync with similar code ins AS400JDBCResultSet
// @C4A
int callResultSetType ;
if (resultSetType_ == ResultSet.TYPE_FORWARD_ONLY) {
// The user requested FORWARD_ONLY, so the result set will
// only be usable as forward only.
callResultSetType = ResultSet.TYPE_FORWARD_ONLY;
} else if(cursor_.getCursorAttributeScrollable() == 0)
callResultSetType = ResultSet.TYPE_FORWARD_ONLY;
else if(cursor_.getCursorAttributeSensitive() == 0)
callResultSetType = ResultSet.TYPE_SCROLL_INSENSITIVE;
else if(cursor_.getCursorAttributeSensitive() == 1)
callResultSetType = ResultSet.TYPE_SCROLL_SENSITIVE;
else
callResultSetType = resultSetType_;
JDServerRow row = new JDServerRow (
connection_, id_, cursor_.openDescribe (openAttributes,
callResultSetType), settings_); //@KBA
JDServerRowCache rowCache = new JDServerRowCache (row,
connection_, id_,
getBlockingFactor (cursorSensitivity, sqlStatement,
row.getRowLength()), false, (preV5R3 ? ResultSet.TYPE_FORWARD_ONLY : resultSetType_), cursor_); //@PDC perf //@pda perf2 - fetch/close
/*@K3A@P6M*/
if (extendedMetaData) {
DBExtendedColumnDescriptors newExtendedColumnDescriptors = cursor_.getExtendedColumnDescriptors();
if (newExtendedColumnDescriptors != null) {
extendedColumnDescriptors_ = newExtendedColumnDescriptors;
}
}
//if pre-v5r3 create a FORWARD_ONLY RESULT SET
if(preV5R3) //@KBA
{
resultSet_ = new AS400JDBCResultSet (this,
sqlStatement, rowCache, connection_.getCatalog(),
cursor_.getName(), maxRows_, ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, fetchDirection_,
fetchSize_, extendedColumnDescriptors_); //@P6C
}
else //@KBA
{ //@KBA
resultSet_ = new AS400JDBCResultSet (this, //@KBA
sqlStatement, rowCache, connection_.getCatalog(), //@KBA
cursor_.getName(), maxRows_, callResultSetType, //@KBA
ResultSet.CONCUR_READ_ONLY, fetchDirection_, //@KBA
fetchSize_, extendedColumnDescriptors_); //@P6C //@KBA
}
if(resultSet_.getConcurrency () != resultSetConcurrency_)
postWarning (JDError.getSQLWarning (JDError.WARN_OPTION_VALUE_CHANGED));
}
}
commonExecuteAfter (sqlStatement, commonExecuteReply);
} catch (SQLException sqlex) {
// Handle interrupted exception
String messageText = sqlex.getMessage();
messageText = messageText.toLowerCase();
if (messageText.indexOf("internal driver error") >= 0) {
if (messageText.indexOf("interrupted") > 0) {
threadInterrupted = true;
}
}
throw sqlex;
}
finally
{ //@P0A
if(request != null) {
request.returnToPool(); request = null;
}
// This can be returned. See comment at declaration. @B5A
if (commonExecuteReply != null) { commonExecuteReply.returnToPool(); commonExecuteReply = null; }
}
}
catch(DBDataStreamException e)
{
JDError.throwSQLException (JDError.EXC_INTERNAL, e);
}
// Inform the transaction manager that a statement
// was executed.
transactionManager_.statementExecuted ();
// Check to see if the statement was cancelled.
if(cancelled_)
JDError.throwSQLException (JDError.EXC_OPERATION_CANCELLED);
if (sqlStatement.isSetSpecialRegister()) {
if (connection_ instanceof AS400JDBCConnectionRedirect) {
((AS400JDBCConnectionRedirect) connection_)
.addSetCommand(sqlStatement.toString());
}
}
// Output a summary as a trace message. The * signifies that the
// statement name comes from the RPB.
if(JDTrace.isTraceOn())
{
JDTrace.logInformation (this,
"Executed " + (usedNameOverride ? (nameOverride_) : (name_ + "*"))
+ ", SQL Statement --> [" + sqlStatement + "]");
JDTrace.logInformation (this,
"Update count = " + updateCount_);
JDTrace.logInformation (this,
"Result set = " + (resultSet_ != null));
JDTrace.logInformation (this,
"Number of result sets = " + numberOfResults_);
JDTrace.logInformation (this, // @ECA
"Row count estimate = " + rowCountEstimate_); // @ECA
}
}
} finally {
/*@D4A*/
if (connection_.isQueryTimeoutMechanismCancel()) {
endCancelThread();
}
}
}
/**
Performs common operations needed after an execute.
@param sqlStatement The SQL statement.
@param reply The execute reply.
@exception SQLException If an error occurs.
**/
//
// This method is intended to be overriden, if needed.
//
void commonExecuteAfter (JDSQLStatement sqlStatement,
DBReplyRequestedDS reply) // private protected
throws SQLException
{
currentJDSQLStatement_ = null;
// Nothing.
}
/**
Performs common operations needed before an execute.
@param sqlStatement The SQL statement.
@param request The execute request.
@exception SQLException If an error occurs.
**/
//
// This method is intended to be overriden, if needed.
//
void commonExecuteBefore (JDSQLStatement sqlStatement,
DBSQLRequestDS request) // private protected
throws SQLException
{
// Clear warnings.
currentJDSQLStatement_ = sqlStatement;
clearWarnings ();
}
/**
Prepares (pre-compiles) the SQL statement on the IBM i system.
@param sqlStatement The SQL statement.
@return The result row or null if none.
@exception SQLException If an error occurs.
**/
//
// Do not override this method. Instead, override
// commonPrepareBefore(), commonPrepareAfter() and
// commonPrepareBypass() as needed.
//
JDServerRow commonPrepare (JDSQLStatement sqlStatement) // private protected
throws SQLException
{
JDServerRow resultRow = null;
currentJDSQLStatement_ = sqlStatement;
try {
/*@D4A*/
if (connection_.isQueryTimeoutMechanismCancel()) {
startCancelThread();
}
cancelled_ = false;
connection_.checkAccess (sqlStatement);
nameOverride_ = "";
// Check for DRDA connect or disconnect. @B1A
if(sqlStatement.isDRDAConnect ())
{
connection_.setDRDA (true);
// It is possible at this point, that current statement
// id does not follow the DRDA rules (defined in
// AS400JDBCConnection.getUnusedId()), but we will not
// work around that at this point. This simple workaround
// is to create a new Statement immediately after connecting.
}
else if(sqlStatement.isDRDADisconnect ())
connection_.setDRDA (false);
// Create the SQL package if necessary.
if(! packageManager_.isCreated())
packageManager_.create ();
// There are three distinct cases. Exactly one of these
// branches will be taken.
// CASE 1: The statement appears in the cached package.
//
// If the SQL package is cached, check to see if this SQL
// statement is in there. If so, then gather data accordingly
// and skip the prepare.
//
if(packageManager_.isCached())
{
if(sqlStatement.isPackaged())
{
int i = packageManager_.getCachedStatementIndex (sqlStatement);
if(i != -1)
{
// Gather results from package cache.
DBDataFormat dataFormat = packageManager_.getCachedDataFormat (i);
if(dataFormat == null)
resultRow = null;
else
resultRow = new JDServerRow (connection_, id_,
dataFormat, settings_);
//@re-prep check if one of the columns is a lob or locator on resultset columns
if( resultRow != null && resultRow.containsLob_) //@re-prep
{
resultRow = null; //@re-prep output lobs
} //@re-prep
commonPrepareBypass (sqlStatement, i);
//@re-prep input lobs on prepared statement
if(parameterRow_ != null && parameterRow_.containsLob_) //@re-prep
{ //@re-prep
nameOverride_ = ""; //@re-prep
// Output a summary as a trace message.
if(JDTrace.isTraceOn()) //@re-prep
JDTrace.logInformation (this,
"Statement [" + sqlStatement + "] was found "
+ "in the cached package "
+ " but must be re-prepared since it contains a lob or locator"); //@re-prep
} //@re-prep
else //@re-prep
{ //@re-prep
nameOverride_ = packageManager_.getCachedStatementName (i);
// Output a summary as a trace message.
if(JDTrace.isTraceOn())
JDTrace.logInformation (this,
"Statement [" + sqlStatement + "] was found "
+ "in the cached package as " + nameOverride_);
} //@re-prep
}
}
}
// If the SQL package is not cached, then we must prepare
// the statement on the system.
if(nameOverride_.length() == 0)
{
// @E7A - start
//
// CASE 2a: Statement is a DRDA CONNECT.
//
if(sqlStatement.getNativeType() == JDSQLStatement.TYPE_CONNECT )
{
/* Only execute now if allowImmediate_, otherwise delay until */
/* execute time. @W4A*/
if (allowImmediate_) {
executeConnectStatement(sqlStatement);
/* Note, the code to execute the connect statement */
/* was moved to its own function. */
} else {
// Do not do anything in this case. The executeConnectStatement
// will be called at execute time.
}
}
// @E7A - end
// CASE 2: Statement can be executed immediately.
//
// This is essentially the prepare and execute combined
// in one datastream. We will then be able to skip the
// execute step later.
//
else if((allowImmediate_) && (sqlStatement.isImmediatelyExecutable ()))
{ // @E7C
// Sync up the RPB.
syncRPB ();
DBSQLRequestDS request = null; //@P0A
try
{
int requestedORS = DBSQLRequestDS.ORS_BITMAP_RETURN_DATA+DBSQLRequestDS.ORS_BITMAP_SQLCA; //@F5A
boolean isCall = (sqlStatement.getNativeType () == JDSQLStatement.TYPE_CALL); //@cur
if(connection_.getVRM() >= JDUtilities.vrm610 ) //@cur //@isol
requestedORS += DBSQLRequestDS.ORS_BITMAP_CURSOR_ATTRIBUTES; //@cur
//@F5A If we are on a system that supports extended column descriptors and if the //@F5A
//@F5A user asked for them, send the extended column descriptors code point. //@F5A
boolean extendedMetaData = false; //@F5A
if(connection_.getVRM() >= JDUtilities.vrm520) //@F5A
{
//@F5A
extendedMetaData = connection_.getProperties().getBoolean(JDProperties.EXTENDED_METADATA); //@F5A
if(extendedMetaData) //@F5A
{
//@F5A
requestedORS = requestedORS + DBSQLRequestDS.ORS_BITMAP_EXTENDED_COLUMN_DESCRIPTORS; //@F5A
} //@F5A
}
request = DBDSPool.getDBSQLRequestDS (DBSQLRequestDS.FUNCTIONID_EXECUTE_IMMEDIATE, id_, requestedORS, 0); //@P0C @F5C
boolean extended = false; //@540
if(connection_.getVRM() >= JDUtilities.vrm540) extended = true; //@540
//Bidi-HCG request.setStatementText(sqlStatement.toString(), connection_.unicodeConverter_, extended); //@E3C @P0C @540C
request.setStatementText(sqlStatement.toString(), connection_.getPackageCCSID_Converter(), extended);//Bidi-HCG
request.setStatementType (sqlStatement.getNativeType ());
int openAttributes = cursor_.getOpenAttributes (sqlStatement, blockCriteria_);
request.setOpenAttributes (openAttributes);
ConvTable converter = connection_.getConverter();
if(packageManager_.isEnabled())
{
if(sqlStatement.isPackaged())
{
request.setPrepareOption (1);
request.setPackageName (packageManager_.getName (), converter); //@P0C
}
else
{
request.setPrepareOption (0);
request.setPackageName(null, converter); //send empty code point
}
}
else
request.setPrepareOption (0);
//@F5A Don't have to check if a v5r2 system, because extendedMetaData
//@F5A can only be true if we are running to v5r2
if(extendedMetaData) //@F5A
{
//@F5A
request.setExtendedColumnDescriptorOption((byte)0xF1); //@F5A
} //@F5A
commonPrepareBefore (sqlStatement, request);
commonExecuteBefore (sqlStatement, request);
if (connectReply != null) {
connectReply.returnToPool();connectReply = null;
}
if (normalPrepareReply != null) {
normalPrepareReply.returnToPool();normalPrepareReply = null;
}
if (execImmediateReply != null) { execImmediateReply.returnToPool(); execImmediateReply=null;}
execImmediateReply = connection_.sendAndReceive (request, id_); //@P0C
int errorClass = execImmediateReply.getErrorClass();
int returnCode = execImmediateReply.getReturnCode();
Vector sqlcas = execImmediateReply.getSQLCAs ();
DBReplySQLCA firstSqlca = (DBReplySQLCA) sqlcas.firstElement();
Enumeration elements = sqlcas.elements();
while (elements.hasMoreElements()) {
DBReplySQLCA sqlca = (DBReplySQLCA) elements.nextElement(); // @F10M
if (errorClass != 0) {
positionOfSyntaxError_ = sqlca.getErrd(5); // @F10A
if (returnCode < 0)
JDError.throwSQLException(this, connection_, id_, errorClass,
returnCode);
else
postWarning(JDError.getSQLWarning(connection_, id_,
errorClass, returnCode));
}
}
transactionManager_.processCommitOnReturn(execImmediateReply); // @E2A
cursor_.processCursorAttributes(execImmediateReply); //@cur
// Compute the update count.
//@F10M DBReplySQLCA sqlca = reply.getSQLCA ();
updateCount_ = firstSqlca.getErrd (3); //@F1C
rowCountEstimate_ = -1; // @ECA
//@F5A Don't have to check if a v5r2 system, because extendedMetaData
//@F5A can only be true if we are running to v5r2
if(extendedMetaData) //@F5A
{
//@F5A
extendedColumnDescriptors_ = execImmediateReply.getExtendedColumnDescriptors (); //@F5A
} //@F5A
//Make an auto-generated key result set if it was requested //@F5A
// Note: This should not happen if running to a release after V5R4 as the insert will always be wrapped with a SELECT //@GKA
if(autoGeneratedKeys_ == RETURN_GENERATED_KEYS && //@F5A
(connection_.getVRM() >= JDUtilities.vrm520)) //@F5A
makeGeneratedKeyResultSet(returnCode, firstSqlca); //@F5A
else if(generatedKeys_ != null) //@PDA genkeys - handle previous genkeys
{
generatedKeys_.close();
generatedKeys_ = null;
}
// Compute the number of results.
//boolean isCall = (sqlStatement.getNativeType () == JDSQLStatement.TYPE_CALL); //@cur moved above
if( /*(numberOfResults_ == 0) && */(isCall))
numberOfResults_ = firstSqlca.getErrd (2); //@F1C
else
numberOfResults_ = 0;
// If this is a CALL and result sets came back, but
// no format was returned, then open the cursor. The result
// set must be forward only and read only.
// This is a system restriction. @EBA
// As of V5R3, the restriction to be forward only no longer applies @KBA
if((isCall == true) && (numberOfResults_ > 0))
{
boolean preV5R3 = connection_.getVRM() < JDUtilities.vrm530;
if (extendedMetaData) { /*@K3A*/
cursor_.setExtendedMetaData(extendedMetaData);
}
JDServerRow row = new JDServerRow (connection_, id_,
cursor_.openDescribe (openAttributes, resultSetType_), //@KBA
settings_);
String cursorSensitivity = connection_.getProperties().getString(JDProperties.CURSOR_SENSITIVITY); //@F8A
JDServerRowCache rowCache = new JDServerRowCache (row, connection_, id_, getBlockingFactor (cursorSensitivity,
sqlStatement, row.getRowLength()), false, (preV5R3 ? ResultSet.TYPE_FORWARD_ONLY : resultSetType_), cursor_); //@PDC perf //@pda perf2 - fetch/close
//if pre-v5r3 create a FORWARD_ONLY RESULT SET
if(preV5R3) //@KBA
{
resultSet_ = new AS400JDBCResultSet (this,
sqlStatement, rowCache, connection_.getCatalog(),
cursor_.getName(), maxRows_, ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, fetchDirection_,
fetchSize_, extendedColumnDescriptors_); //@P6C
}
else //@KBA
{ //@KBA
resultSet_ = new AS400JDBCResultSet (this, //@KBA
sqlStatement, rowCache, connection_.getCatalog(), //@KBA
cursor_.getName(), maxRows_, resultSetType_, //@KBA
ResultSet.CONCUR_READ_ONLY, fetchDirection_, //@KBA
fetchSize_, extendedColumnDescriptors_); //@KBA@P6C
}
if(resultSet_.getConcurrency () != resultSetConcurrency_)
postWarning (JDError.getSQLWarning (JDError.WARN_OPTION_VALUE_CHANGED));
}
commonPrepareAfter (sqlStatement, execImmediateReply);
commonExecuteAfter (sqlStatement, execImmediateReply);
}
catch(DBDataStreamException e)
{
JDError.throwSQLException (JDError.EXC_INTERNAL, e);
}
finally
{ //@P0A
if(request != null) {
request.returnToPool(); request = null;
}
if (execImmediateReply != null) { execImmediateReply.returnToPool(); execImmediateReply = null; } /*@B5A*/
}
// Inform the transaction manager that a statement
// was executed.
transactionManager_.statementExecuted ();
if (sqlStatement.isSetSpecialRegister()) {
if (connection_ instanceof AS400JDBCConnectionRedirect) {
((AS400JDBCConnectionRedirect) connection_)
.addSetCommand(sqlStatement.toString());
}
}
// Output a summary as a trace message. The * signifies that the
// statement name comes from the RPB.
if(JDTrace.isTraceOn())
{
JDTrace.logInformation (this,
"Executed immediately " + name_ + "*, SQL Statement -->[" + sqlStatement + "]");
JDTrace.logInformation (this,
"Update count = " + updateCount_);
JDTrace.logInformation (this,
"Result set = " + (resultSet_ != null));
JDTrace.logInformation (this,
"Number of result sets = " + numberOfResults_);
}
}
// CASE 3: Normal prepare.
//
else
{
// Sync up the RPB.
syncRPB ();
DBSQLRequestDS request = null; //@P0A
if (normalPrepareReply != null) {
normalPrepareReply.returnToPool(); normalPrepareReply = null;
} /* B5A */
try
{
int requestedORS = DBSQLRequestDS.ORS_BITMAP_RETURN_DATA+DBSQLRequestDS.ORS_BITMAP_DATA_FORMAT+DBSQLRequestDS.ORS_BITMAP_SQLCA; //@F5A @F10C
//@F5A If we are on a system that supports extended column descriptors and if the //@F5A
//@F5A user asked for them, send the extended column descriptors code point. //@F5A
boolean extendedMetaData = false; //@F5A
if(connection_.getVRM() >= JDUtilities.vrm520) //@F5A
{
//@F5A
extendedMetaData = connection_.getProperties().getBoolean(JDProperties.EXTENDED_METADATA); //@F5A
if(extendedMetaData) //@F5A
{
//@F5A
requestedORS = requestedORS + DBSQLRequestDS.ORS_BITMAP_EXTENDED_COLUMN_DESCRIPTORS; //@F5A
} //@F5A
}
request = DBDSPool.getDBSQLRequestDS(DBSQLRequestDS.FUNCTIONID_PREPARE_DESCRIBE, id_, requestedORS, 0); //@P0C @F5C
boolean extended = false; //@540
if(connection_.getVRM() >= JDUtilities.vrm540) extended = true; //@540
//Bidi-HCG request.setStatementText(sqlStatement.toString(), connection_.unicodeConverter_, extended); //@E3C @P0C @540C
request.setStatementText(sqlStatement.toString(), connection_.getPackageCCSID_Converter(), extended);//Bidi-HCG
request.setStatementType (sqlStatement.getNativeType ());
if(packageManager_.isEnabled())
{
ConvTable converter = connection_.getConverter();
if(sqlStatement.isPackaged())
{
request.setPrepareOption (1);
request.setPackageName (packageManager_.getName (), converter); //@P0C
}
else
{
request.setPrepareOption (0);
request.setPackageName(null, converter); //send empty code point
}
}
else
request.setPrepareOption (0);
//@F5A Don't have to check if a v5r2 system, because extendedMetaData
//@F5A can only be true if we are running to v5r2
if(extendedMetaData) //@F5A
{
//@F5A
request.setExtendedColumnDescriptorOption((byte)0xF1); //@F5A
} //@F5A
commonPrepareBefore (sqlStatement, request);
if (execImmediateReply != null) {
execImmediateReply.returnToPool();execImmediateReply = null;
}
if (connectReply != null) {
connectReply.returnToPool();connectReply = null;
}
if (normalPrepareReply != null) { normalPrepareReply.returnToPool(); normalPrepareReply=null; }
normalPrepareReply = connection_.sendAndReceive (request, id_); //@P0C
int errorClass = normalPrepareReply.getErrorClass();
int returnCode = normalPrepareReply.getReturnCode();
if(errorClass != 0)
{
positionOfSyntaxError_ = normalPrepareReply.getSQLCA().getErrd(5); //@F10A
if(returnCode < 0)
JDError.throwSQLException (this, connection_, id_, errorClass, returnCode);
else
postWarning (JDError.getSQLWarning (connection_, id_, errorClass, returnCode));
}
// Gather results from the reply.
DBDataFormat dataFormat = normalPrepareReply.getDataFormat ();
if(dataFormat == null)
resultRow = null;
else
resultRow = new JDServerRow (connection_, id_,
dataFormat, settings_);
//@F5A Don't have to check if a v5r2 system, because extendedMetaData
//@F5A can only be true if we are running to v5r2
if(extendedMetaData) //@F5A
{
//@F5A
extendedColumnDescriptors_ = normalPrepareReply.getExtendedColumnDescriptors (); //@F5A
} //@F5A
commonPrepareAfter (sqlStatement, normalPrepareReply);
}
catch(DBDataStreamException e)
{
JDError.throwSQLException (JDError.EXC_INTERNAL, e);
}
finally
{ //@P0A
if(request != null) {
request.returnToPool(); request=null;
}
if (normalPrepareReply != null) { normalPrepareReply.returnToPool(); normalPrepareReply = null; } //@B5A
}
// Output a summary as a trace message. The * signifies that the
// statement name comes from the RPB.
if(JDTrace.isTraceOn())
JDTrace.logInformation (this,
"Prepared " + name_ + "*, SQL Statement -->[" + sqlStatement + "]");
}
}
// Check to see if the statement was cancelled.
if(cancelled_)
JDError.throwSQLException (JDError.EXC_OPERATION_CANCELLED);
/*
// Deleted @Z4
// If any of the fields is a locator, then we need to turn off @B2A
// record blocking. @B2A
lastPrepareContainsLocator_ = false; // @B2A
if(resultRow != null)
{ // @B2A
int fieldCount = resultRow.getFieldCount (); // @B2A
for(int i = 1; i <= fieldCount; ++i)
{ // @B2A
SQLData sqlData = resultRow.getSQLData(i);
int sqlType = sqlData.getSQLType(); //@xml3
if(sqlType == SQLData.CLOB_LOCATOR ||
sqlType == SQLData.BLOB_LOCATOR ||
sqlType == SQLData.DBCLOB_LOCATOR ||
sqlType == SQLData.NCLOB_LOCATOR ||
sqlType == SQLData.XML_LOCATOR) //@xml3
lastPrepareContainsLocator_ = true; // @B2A
} // @B2A
} // @B2A
*/
} finally {
/*@D4A*/
if (connection_.isQueryTimeoutMechanismCancel()) {
endCancelThread();
}
}
return resultRow;
}
// executeConnectStatement executes a connect statement
// Was put in its own routines for @W4
private void executeConnectStatement(JDSQLStatement sqlStatement) throws SQLException {
syncRPB();
DBSQLRequestDS request = null; //@P0A
try
{
request = DBDSPool.getDBSQLRequestDS(DBSQLRequestDS.FUNCTIONID_CONNECT, id_, DBSQLRequestDS.ORS_BITMAP_RETURN_DATA+DBSQLRequestDS.ORS_BITMAP_SQLCA, 0); //@P0C
boolean extended = false; //@540
if(connection_.getVRM() >= JDUtilities.vrm540) extended = true; //@540
//Bidi-HCG request.setStatementText(sqlStatement.toString(), connection_.unicodeConverter_, extended); //@E3C @P0C @540C
request.setStatementText(sqlStatement.toString(), connection_.getPackageCCSID_Converter(), extended);//Bidi-HCG
request.setStatementType (sqlStatement.getNativeType ());
ConvTable converter = connection_.getConverter();
if(packageManager_.isEnabled())
{
if(sqlStatement.isPackaged())
{
request.setPrepareOption (1);
request.setPackageName (packageManager_.getName (), converter); //@P0C
}
else
{
request.setPrepareOption (0);
request.setPackageName(null, converter); //send empty code point per
}
}
else
request.setPrepareOption (0);
commonPrepareBefore (sqlStatement, request);
commonExecuteBefore (sqlStatement, request);
if (execImmediateReply != null) {
execImmediateReply.returnToPool(); execImmediateReply = null;
}
if (normalPrepareReply != null) {
normalPrepareReply.returnToPool();normalPrepareReply = null;
}
if (connectReply != null) { connectReply.returnToPool(); connectReply=null; }
connectReply = connection_.sendAndReceive (request, id_); //@P0C
int errorClass = connectReply.getErrorClass();
int returnCode = connectReply.getReturnCode();
if(errorClass != 0)
{
positionOfSyntaxError_ = connectReply.getSQLCA().getErrd(5); //@F10A
if(returnCode < 0)
JDError.throwSQLException (this, connection_, id_, errorClass, returnCode);
else
postWarning (JDError.getSQLWarning (connection_, id_, errorClass, returnCode));
}
// Compute the update count and number of results.
updateCount_ = 0;
numberOfResults_ = 0;
commonPrepareAfter (sqlStatement, connectReply);
commonExecuteAfter (sqlStatement, connectReply);
}
catch(DBDataStreamException e)
{
JDError.throwSQLException (JDError.EXC_INTERNAL, e);
}
finally
{ //@P0A
if(request != null) {
request.returnToPool(); request=null;
}
if (connectReply != null) { connectReply.returnToPool(); connectReply = null; } /*@B5A*/
}
// Inform the transaction manager that a statement
// was executed.
transactionManager_.statementExecuted ();
// Save the connect statement
if (connection_ instanceof AS400JDBCConnectionRedirect) {
((AS400JDBCConnectionRedirect) connection_)
.addSetCommand(sqlStatement.toString());
}
// Output a summary as a trace message. The * signifies that the
// statement name comes from the RPB.
if(JDTrace.isTraceOn())
{
JDTrace.logInformation (this,
"Executed connect " + name_ + "*, SQL Statement -->[" + sqlStatement + "]");
}
}
/**
Performs common operations needed after a prepare.
@param sqlStatement The SQL statement.
@param reply The prepare reply.
@exception SQLException If an error occurs.
**/
//
// This method is intended to be overriden, if needed.
//
void commonPrepareAfter (JDSQLStatement sqlStatement,
DBReplyRequestedDS reply) // private protected
throws SQLException
{
currentJDSQLStatement_ = sqlStatement;
// Nothing.
}
/**
Performs common operations needed before a prepare.
@param sqlStatement The SQL statement.
@param request The prepare request.
@exception SQLException If an error occurs.
**/
//
// This method is intended to be overriden, if needed.
//
void commonPrepareBefore (JDSQLStatement sqlStatement,
DBSQLRequestDS request) // private protected
throws SQLException
{
// Close the result set before preparing another.
closeResultSet (JDCursor.REUSE_YES);
currentJDSQLStatement_ = sqlStatement;
}
/**
Performs common operations in leiu of a prepare.
@param sqlStatement The SQL statement.
@param statementIndex The cached statement index.
@exception SQLException If an error occurs.
**/
//
// This method is intended to be overriden, if needed.
//
void commonPrepareBypass (JDSQLStatement sqlStatement,
int statementIndex) // private protected
throws SQLException
{
// Nothing.
currentJDSQLStatement_ = sqlStatement;
}
/**
Runs an SQL statement that may return multiple result sets.
This closes the current result set and clears warnings before
executing the new SQL statement.
Under some situations, a single SQL statement may return
multiple result sets, an update count, or both. This might occur
when executing a stored procedure that returns multiple
result sets or when dynamically executing an unknown SQL string.
Use getMoreResults(), getResultSet(), and getUpdateCount()
to navigate through multiple result sets, an update count, or
both.
@param sql The SQL statement.
@return true if a result set was returned, false
if an update count was returned or nothing
was returned.
@exception SQLException If the statement is not open,
the SQL statement contains a syntax
error, the query timeout limit is
exceeded, or an error occurs.
**/
public boolean execute(String sql) throws SQLException {
synchronized (internalLock_) { // @E6A
checkOpen();
JDSQLStatement sqlStatement = new JDSQLStatement(sql,
settings_.getDecimalSeparator(), escapeProcessing_,
packageCriteria_, connection_); // @A1A @G4C
currentJDSQLStatement_ = sqlStatement;
if (JDTrace.isTraceOn()) // @D0A
JDTrace.logInformation(this, "Executing SQL Statement -->["
+ sqlStatement + "]"); // @D0A
// Validate that no parameters are set, since parameters
// imply the need for a PreparedStatement.
//
// Note: This code causes problems with some statements with a syntax
// error.
// For example
// select * from sysibm.sysdummy1 where 'a = '?'
//
// Removing this code to allow database engine errors to be returned.
//
// if(sqlStatement.countParameters () > 0)
// JDError.throwSQLException (JDError.EXC_PARAMETER_COUNT_MISMATCH);
// @AAD
// Prepare and execute.
JDServerRow resultRow = commonPrepare(sqlStatement);
commonExecute(sqlStatement, resultRow);
return (resultSet_ != null);
}
}
//@G4A JDBC 3.0
/**
Runs an SQL statement that may return multiple result sets and
makes any auto-generated keys available for retrieval using
Statement.getGeneratedKeys(). This closes the current result set
and clears warnings before executing the new SQL statement.
Under some situations, a single SQL statement may return
multiple result sets, an update count, or both. This might occur
when executing a stored procedure that returns multiple
result sets or when dynamically executing an unknown SQL string.
Use getMoreResults(), getResultSet(), and getUpdateCount()
to navigate through multiple result sets, an update count, or
both.
This method requires OS/400 V5R2
or IBM i. If connecting to OS/400 V5R1 or earlier, an exception
will be thrown.
@param sql The SQL statement.
@param autoGeneratedKeys Indicates whether auto-generated keys should be made available for
retrieval. Valid values are Statement.RETURN_GENERATED_KEYS and
Statement.NO_GENERATED_KEYS.
@return true if a result set was returned, false
if an update count was returned or nothing
was returned.
@exception SQLException If the statement is not open,
the SQL statement contains a syntax
error, the query timeout limit is
exceeded, the value for autoGeneratedKeys is
not a valid value, if connecting to OS/400 V5R1
or earlier, an error occurs.
@since Modification 5
**/
public boolean execute (String sql, int autoGeneratedKeys)
throws SQLException
{
if(connection_.getVRM() < JDUtilities.vrm520) //@F5A
JDError.throwSQLException(JDError.EXC_FUNCTION_NOT_SUPPORTED); //@F5A
verifyGeneratedKeysParameter(autoGeneratedKeys);
autoGeneratedKeys_ = autoGeneratedKeys;
if((connection_.getVRM() >= JDUtilities.vrm610) && //@GKA
(autoGeneratedKeys_ == RETURN_GENERATED_KEYS)) //@GKA
{
synchronized(internalLock_)
{
checkOpen ();
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
settings_.getDecimalSeparator (), escapeProcessing_,
packageCriteria_, connection_);
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn())
JDTrace.logInformation (this, "Executing SQL Statement -->[" + sqlStatement + "]");
// Validate that no parameters are set, since parameters
// imply the need for a PreparedStatement.
// Note: This code causes problems with some statements with a syntax error.
// For example
// select * from sysibm.sysdummy1 where 'a = '?'
//
// Removing this code to allow database engine errors to be returned.
//
//if(sqlStatement.countParameters () > 0)
// JDError.throwSQLException (JDError.EXC_PARAMETER_COUNT_MISMATCH);
// @AAD
if(sqlStatement.isInsert_)
{
String selectStatement = connection_.makeGeneratedKeySelectStatement(sql);
//Construct the new JDSQLStatement object
sqlStatement = new JDSQLStatement(selectStatement, settings_.getDecimalSeparator(), escapeProcessing_, packageCriteria_, connection_);
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "Generated keys, SQL Statement -->[" + sqlStatement + "]");
sqlStatement.setSelectFromInsert(true);
currentJDSQLStatement_ = sqlStatement;
}
// Prepare and execute.
JDServerRow resultRow = commonPrepare (sqlStatement);
commonExecute (sqlStatement, resultRow);
return(resultSet_ != null);
}
}
else //@GKA do what we always have
return execute (sql);
}
//@G4A JDBC 3.0
/**
Runs an SQL statement that may return multiple result sets and
makes any auto-generated keys for the columns indicated in the given array
available for retrieval using Statement.getGeneratedKeys().
This closes the current result set and clears warnings before
executing the new SQL statement.
Under some situations, a single SQL statement may return
multiple result sets, an update count, or both. This might occur
when executing a stored procedure that returns multiple
result sets or when dynamically executing an unknown SQL string.
Use getMoreResults(), getResultSet(), and getUpdateCount()
to navigate through multiple result sets, an update count, or
both.
This method is not supported when connecting to IBM i V5R4 or earlier systems.
@param sql The SQL statement.
@param columnIndexes Indicates that auto-generated keys for the indicated
columns should be made available for retrieval.
@return true if a result set was returned, false
if an update count was returned or nothing
was returned.
@exception java.sql.SQLException - If connecting to IBM i V5R4 or earlier systems,
if the statement is not open,
the SQL statement contains a syntax
error, the query timeout limit is
exceeded, the value for columnIndexes is
not a valid value, or an error occurs.
@since Modification 5
**/
public boolean execute (String sql, int[] columnIndexes)
throws SQLException
{
if(connection_.getVRM() >= JDUtilities.vrm610) //@GKA
{
synchronized(internalLock_)
{
checkOpen ();
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
settings_.getDecimalSeparator (), escapeProcessing_,
packageCriteria_, connection_);
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn())
JDTrace.logInformation (this, "Executing SQL Statement -->[" + sqlStatement + "]");
// Validate that no parameters are set, since parameters
// imply the need for a PreparedStatement.
// Note: This code causes problems with some statements with a syntax error.
// For example
// select * from sysibm.sysdummy1 where 'a = '?'
//
// Removing this code to allow database engine errors to be returned.
//
// if(sqlStatement.countParameters () > 0)
// JDError.throwSQLException (JDError.EXC_PARAMETER_COUNT_MISMATCH);
// @AAD
//check if the statement is an insert statement
if(sqlStatement.isInsert_)
{
String selectStatement = connection_.makeGeneratedKeySelectStatement(sql, columnIndexes, null);
sqlStatement = new JDSQLStatement(selectStatement, settings_.getDecimalSeparator (), escapeProcessing_, packageCriteria_, connection_);
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "Generated keys, SQL Statement -->[" + sqlStatement + "]");
autoGeneratedKeys_ = RETURN_GENERATED_KEYS; // specify we want generated keys
sqlStatement.setSelectFromInsert(true);
}
// Prepare and execute.
JDServerRow resultRow = commonPrepare (sqlStatement);
commonExecute (sqlStatement, resultRow);
return(resultSet_ != null);
}
}
else //@GKA
{
JDError.throwSQLException (JDError.EXC_FUNCTION_NOT_SUPPORTED);
return false;
}
}
//@G4A JDBC 3.0
/**
Runs an SQL statement that may return multiple result sets and
makes any auto-generated keys for the columns indicated in the given array
available for retrieval using Statement.getGeneratedKeys().
This closes the current result set and clears warnings before
executing the new SQL statement.
Under some situations, a single SQL statement may return
multiple result sets, an update count, or both. This might occur
when executing a stored procedure that returns multiple
result sets or when dynamically executing an unknown SQL string.
Use getMoreResults(), getResultSet(), and getUpdateCount()
to navigate through multiple result sets, an update count, or
both.
This method is not supported when connecting to IBM i V5R4 or earlier systems.
@param sql The SQL statement.
@param columnNames Indicates that auto-generated keys for the indicated
columns should be made available for retrieval.
@return true if a result set was returned, false
if an update count was returned or nothing
was returned.
@exception java.sql.SQLException - If connecting to IBM i V5R4 or earlier systems,
if the statement is not open,
the SQL statement contains a syntax
error, the query timeout limit is
exceeded, the value for columnNames is
not a valid value, or an error occurs.
@since Modification 5
**/
public boolean execute (String sql, String[] columnNames)
throws SQLException
{
if(connection_.getVRM() >= JDUtilities.vrm610) //@GKA
{
synchronized(internalLock_)
{
checkOpen ();
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
settings_.getDecimalSeparator (), escapeProcessing_,
packageCriteria_, connection_);
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn())
JDTrace.logInformation (this, "Executing SQL Statement -->[" + sqlStatement + "]");
// Validate that no parameters are set, since parameters
// imply the need for a PreparedStatement.
// Note: This code causes problems with some statements with a syntax error.
// For example
// select * from sysibm.sysdummy1 where 'a = '?'
//
// Removing this code to allow database engine errors to be returned.
//
// if(sqlStatement.countParameters () > 0)
// JDError.throwSQLException (JDError.EXC_PARAMETER_COUNT_MISMATCH);
// @AAD
//check if the statement is an insert statement
if(sqlStatement.isInsert_)
{
String selectStatement = connection_.makeGeneratedKeySelectStatement(sql, null, columnNames);
sqlStatement = new JDSQLStatement(selectStatement, settings_.getDecimalSeparator (), escapeProcessing_, packageCriteria_, connection_);
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "Generated keys, SQL Statement -->[" + sqlStatement + "]");
sqlStatement.setSelectFromInsert(true);
autoGeneratedKeys_ = RETURN_GENERATED_KEYS; // specify we want generated keys
}
// Prepare and execute.
JDServerRow resultRow = commonPrepare (sqlStatement);
commonExecute (sqlStatement, resultRow);
return(resultSet_ != null);
}
}
else // Do what we always have
{
JDError.throwSQLException (JDError.EXC_FUNCTION_NOT_SUPPORTED);
return false;
}
}
// JDBC 2.0
/**
Runs the batch of SQL statements. Batch updates can be used
to submit a set of SQL statements together as a single unit.
The SQL statements are run in the order in which they were
added to the batch. The batch is cleared after the SQL statements
are run. In addition, this closes the current result set and
clears warnings before executing the new SQL statement.
When batch updates are run, autocommit should usually be turned off.
This allows the caller to decide whether or not to commit the
transaction in the event that an error occurs and some of the
SQL statements in a batch fail to run.
@return An array of row counts for the SQL statements that are run.
The array contains one element for each statement in the
batch of SQL statements. The array is ordered according to
the order in which the SQL statements were added to the batch.
@exception SQLException If the statement is not open,
an SQL statement contains a syntax
error, the query timeout limit is
exceeded, an SQL statement returns
a result set, or an error occurs.
**/
//
// Implementation notes:
//
// 1. We are using a Vector as the main data structure.
// Vector is supposedly synchronized already, so we
// should not have to worry about synchronization.
//
public int[] executeBatch ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
if(batch_ == null) batch_ = new Vector(); //@P0A
int batchSize = batch_.size ();
int[] updateCounts = new int[batchSize];
int i = 0;
try
{
Enumeration list = batch_.elements ();
while(list.hasMoreElements ())
{
// Prepare and execute. Check for a result set in
// both places. It is best to catch it after the
// prepare (so we don't open a cursor), but with
// some stored procedures, we can't catch it until
// the execute.
JDSQLStatement sqlStatement = (JDSQLStatement) list.nextElement ();
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn()) // @D0A
JDTrace.logInformation (this, "Executing from batch SQL Statement -->[" + sqlStatement + "]"); // @D0A
JDServerRow resultRow = commonPrepare (sqlStatement);
if(resultRow != null)
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
commonExecute (sqlStatement, resultRow);
if(resultSet_ != null)
{
closeResultSet (JDCursor.REUSE_YES);
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
}
updateCounts[i++] = updateCount_;
}
}
catch(SQLException e)
{
// The specification says that if we get an error,
// then the size of the update counts array should
// reflect the number of statements that were
// executed without error.
int[] updateCounts2 = new int[i];
System.arraycopy (updateCounts, 0, updateCounts2, 0, i);
batch_.removeAllElements ();
BatchUpdateException throwException = new BatchUpdateException (e.getMessage (),
e.getSQLState (), e.getErrorCode (), updateCounts2);
try {
throwException.initCause(e);
} catch (Throwable t) {}
throw throwException;
}
batch_.removeAllElements ();
return updateCounts;
}
}
/**
Runs an SQL statement that returns a single result set.
This closes the current result set and clears warnings
before executing the new SQL statement.
@param sql The SQL statement.
@return The result set that contains the data produced
by the query.
@exception SQLException If the statement is not open,
the SQL statement contains a syntax
error, no result set is returned by the
database, the query timeout limit is
exceeded, or an error occurs.
**/
public ResultSet executeQuery (String sql)
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
settings_.getDecimalSeparator (), escapeProcessing_,
packageCriteria_, connection_); // @A1A @G4C
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn()) // @D0A
JDTrace.logInformation (this, "Executing query, SQL Statement -->[" + sqlStatement + "]"); // @D0A
// Validate that no parameters are set, since parameters
// imply the need for a PreparedStatement.
// Note: This code causes problems with some statements with a syntax error.
// For example
// select * from sysibm.sysdummy1 where 'a = '?'
//
// Removing this code to allow database engine errors to be returned.
//
// if(sqlStatement.countParameters () > 0)
// JDError.throwSQLException (JDError.EXC_PARAMETER_COUNT_MISMATCH);
// @AAD
// Prepare and execute.
JDServerRow resultRow = commonPrepare (sqlStatement);
commonExecute (sqlStatement, resultRow);
if((behaviorOverride_ & 1) == 0) // @F9a
{
// @F9a
if(resultSet_ == null)
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
}
// @F9a
return resultSet_;
}
}
/**
Runs an SQL INSERT, UPDATE, or DELETE statement, or any
SQL statement that does not return a result set.
This closes the current result set and clears warnings
before executing the new SQL statement.
@param sql The SQL statement.
@return Either the row count for INSERT, UPDATE, or
DELETE, or 0 for SQL statements that
return nothing.
@exception SQLException If the statement is not open,
the SQL statement contains a syntax
error, the query timeout limit is
exceeded, the statement returns
a result set, or an error occurs.
**/
public int executeUpdate (String sql)
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
settings_.getDecimalSeparator (), escapeProcessing_,
packageCriteria_, connection_); // @A1A @G4A
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn()) // @D0A
JDTrace.logInformation (this, "Executing update, SQL Statement -->[" + sqlStatement + "]"); // @D0A
// Validate that no parameters are set, since parameters
// imply the need for a PreparedStatement.
// Note: This code causes problems with some statements with a syntax error.
// For example
// select * from sysibm.sysdummy1 where 'a = '?'
//
// Removing this code to allow database engine errors to be returned.
//
// if(sqlStatement.countParameters () > 0)
// JDError.throwSQLException (JDError.EXC_PARAMETER_COUNT_MISMATCH);
// @AAD
// Prepare and execute. Check for a result set in both
// places. It is best to catch it after the prepare (so
// we don't open a cursor), but with some stored procedures,
// we can't catch it until the execute.
JDServerRow resultRow = commonPrepare (sqlStatement);
if(resultRow != null)
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
commonExecute (sqlStatement, resultRow);
if(resultSet_ != null)
{
closeResultSet (JDCursor.REUSE_YES);
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
}
return updateCount_;
}
}
//@G4A JDBC 3.0
/**
Runs an SQL INSERT, UPDATE, or DELETE statement, or any
SQL statement that does not return a result set and
makes any auto-generated keys available for retrieval using
Statement.getGeneratedKeys().
This closes the current result set and clears warnings
before executing the new SQL statement.
This method requires OS/400 V5R2 or
or IBM i. If connecting to OS/400 V5R1 or earlier, an exception
will be thrown.
@param sql The SQL statement.
@return Either the row count for INSERT, UPDATE, or
DELETE, or 0 for SQL statements that
return nothing.
@exception SQLException If the statement is not open,
the SQL statement contains a syntax
error, the query timeout limit is
exceeded, the statement returns
a result set, the value for autoGeneratedKeys is
not a valid value, if connecting to OS/400 V5R1
or earlier, an error occurs.
@since Modification 5
**/
public int executeUpdate (String sql, int autoGeneratedKeys)
throws SQLException
{
if(connection_.getVRM() < JDUtilities.vrm520) //@F5A
JDError.throwSQLException(JDError.EXC_FUNCTION_NOT_SUPPORTED); //@F5A
verifyGeneratedKeysParameter(autoGeneratedKeys);
autoGeneratedKeys_ = autoGeneratedKeys;
if((connection_.getVRM() >= JDUtilities.vrm610) && //@GKA
(autoGeneratedKeys_ == RETURN_GENERATED_KEYS)) //@GKA
{
synchronized(internalLock_)
{
checkOpen ();
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
settings_.getDecimalSeparator (), escapeProcessing_,
packageCriteria_, connection_);
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn())
JDTrace.logInformation (this, "Executing SQL Statement -->[" + sqlStatement + "]");
// Validate that no parameters are set, since parameters
// imply the need for a PreparedStatement.
// Note: This code causes problems with some statements with a syntax error.
// For example
// select * from sysibm.sysdummy1 where 'a = '?'
//
// Removed this code let engine return error
//
//if(sqlStatement.countParameters () > 0)
// JDError.throwSQLException (JDError.EXC_PARAMETER_COUNT_MISMATCH);
// @AAD
if(sqlStatement.isInsert_)
{
String selectStatement = connection_.makeGeneratedKeySelectStatement(sql);
//Create a new JDSQLStatement
sqlStatement = new JDSQLStatement(selectStatement, settings_.getDecimalSeparator(), escapeProcessing_, packageCriteria_, connection_);
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "Generated keys, SQL Statement -->[" + sqlStatement + "]");
currentJDSQLStatement_ = sqlStatement;
sqlStatement.setSelectFromInsert(true);
// Prepare and execute.
JDServerRow resultRow = commonPrepare (sqlStatement);
commonExecute (sqlStatement, resultRow);
}
else
{
// Prepare and execute.
JDServerRow resultRow = commonPrepare (sqlStatement);
if(resultRow != null)
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
commonExecute (sqlStatement, resultRow);
if(resultSet_ != null)
{
closeResultSet (JDCursor.REUSE_YES);
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
}
}
return updateCount_;
}
}
else //@GKA do what we always have
return executeUpdate (sql);
}
//@G4A JDBC 3.0
/**
Runs an SQL INSERT, UPDATE, or DELETE statement, or any
SQL statement that does not return a result set and
makes any auto-generated keys for the columns indicated in the given array
available for retrieval using Statement.getGeneratedKeys().
This closes the current result set and clears warnings
before executing the new SQL statement.
This method is not supported when connecting to IBM i V5R4 or earlier systems.
@param sql The SQL statement.
@param columnIndexes The indexes of columns for which auto-generated keys should be made
available for retrieval.
@return Either the row count for INSERT, UPDATE, or
DELETE, or 0 for SQL statements that
return nothing.
@exception SQLException If connection to IBM i V5R4 or earlier systems,
the statement is not open,
the SQL statement contains a syntax
error, the query timeout limit is
exceeded, the statement returns
a result set, the value for autoGeneratedKeys is
not a valid value or an error occurs.
@since Modification 5
**/
public int executeUpdate (String sql, int[] columnIndexes)
throws SQLException
{
if(connection_.getVRM() >= JDUtilities.vrm610) //@GKA
{
synchronized(internalLock_)
{
//make sure the statement is open
checkOpen ();
//create the sql statement object.
JDSQLStatement sqlStatement = new JDSQLStatement (sql, settings_.getDecimalSeparator (), escapeProcessing_, packageCriteria_, connection_);
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn())
JDTrace.logInformation (this, "Executing update, SQL Statement -->[" + sqlStatement + "]");
// Validate that no parameters are set, since parameters
// imply the need for a PreparedStatement.
// Note: This code causes problems with some statements with a syntax error.
// For example
// select * from sysibm.sysdummy1 where 'a = '?'
//
// Removing this code to allow database engine errors to be returned.
//
//if(sqlStatement.countParameters () > 0)
// JDError.throwSQLException (JDError.EXC_PARAMETER_COUNT_MISMATCH);
// @AAD
//check if the statement is an insert statement
if(sqlStatement.isInsert_)
{
String selectStatement = connection_.makeGeneratedKeySelectStatement(sql, columnIndexes, null);
sqlStatement = new JDSQLStatement(selectStatement, settings_.getDecimalSeparator (), escapeProcessing_, packageCriteria_, connection_);
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "Generated keys, SQL Statement -->[" + sqlStatement + "]");
sqlStatement.setSelectFromInsert(true);
autoGeneratedKeys_ = RETURN_GENERATED_KEYS; // specify we want generated keys
// prepare and execute
JDServerRow resultRow = commonPrepare(sqlStatement);
commonExecute(sqlStatement, resultRow);
}
else // treat just like executeUpdate(String sql) was called
{
// Prepare and execute. Check for a result set in both
// places. It is best to catch it after the prepare (so
// we don't open a cursor), but with some stored procedures,
// we can't catch it until the execute.
JDServerRow resultRow = commonPrepare (sqlStatement);
if(resultRow != null)
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
commonExecute (sqlStatement, resultRow);
if(resultSet_ != null)
{
closeResultSet (JDCursor.REUSE_YES);
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
}
}
return updateCount_;
}
}
else
{
JDError.throwSQLException (JDError.EXC_FUNCTION_NOT_SUPPORTED);
return 0;
}
}
//@G4A JDBC 3.0
/**
Runs an SQL INSERT, UPDATE, or DELETE statement, or any
SQL statement that does not return a result set and
makes any auto-generated keys for the columns indicated in the given array
available for retrieval using Statement.getGeneratedKeys().
This closes the current result set and clears warnings
before executing the new SQL statement.
This method is not supported when connecting to IBM i V5R4 or earlier systems.
@param sql The SQL statement.
@param columnNames The column names for which auto-generated keys should be made
available for retrieval.
@return Either the row count for INSERT, UPDATE, or
DELETE, or 0 for SQL statements that
return nothing.
@exception SQLException If connection to IBM i V5R4 or earlier systems,
the statement is not open,
the SQL statement contains a syntax
error, the query timeout limit is
exceeded, the statement returns
a result set, the value for autoGeneratedKeys is
not a valid value or an error occurs.
@since Modification 5
**/
public int executeUpdate (String sql, String[] columnNames)
throws SQLException
{
if(connection_.getVRM() >= JDUtilities.vrm610) //@GKA
{
synchronized(internalLock_)
{
//make sure the statement is open
checkOpen ();
//create the sql statement object.
JDSQLStatement sqlStatement = new JDSQLStatement (sql, settings_.getDecimalSeparator (), escapeProcessing_, packageCriteria_, connection_);
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn())
JDTrace.logInformation (this, "Executing update, SQL Statement -->[" + sqlStatement + "]");
// Validate that no parameters are set, since parameters
// imply the need for a PreparedStatement.
// Note: This code causes problems with some statements with a syntax error.
// For example
// select * from sysibm.sysdummy1 where 'a = '?'
//
// Removing this code to allow database engine errors to be returned.
//
//if(sqlStatement.countParameters () > 0)
// JDError.throwSQLException (JDError.EXC_PARAMETER_COUNT_MISMATCH);
// @AAD
//check if the statement is an insert statement
if(sqlStatement.isInsert_)
{
String selectStatement = connection_.makeGeneratedKeySelectStatement(sql, null, columnNames);
sqlStatement = new JDSQLStatement(selectStatement, settings_.getDecimalSeparator (), escapeProcessing_, packageCriteria_, connection_);
currentJDSQLStatement_ = sqlStatement;
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "Generated keys, SQL Statement -->[" + sqlStatement + "]");
sqlStatement.setSelectFromInsert(true);
autoGeneratedKeys_ = RETURN_GENERATED_KEYS; // specify we want generated keys
//prepare and execute
JDServerRow resultRow = commonPrepare(sqlStatement);
commonExecute(sqlStatement, resultRow);
}
else // treat just like executeUpdate(String sql) was called
{
// Prepare and execute. Check for a result set in both
// places. It is best to catch it after the prepare (so
// we don't open a cursor), but with some stored procedures,
// we can't catch it until the execute.
JDServerRow resultRow = commonPrepare (sqlStatement);
if(resultRow != null)
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
commonExecute (sqlStatement, resultRow);
if(resultSet_ != null)
{
closeResultSet (JDCursor.REUSE_YES);
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
}
}
return updateCount_;
}
}
else
{
JDError.throwSQLException (JDError.EXC_FUNCTION_NOT_SUPPORTED);
return 0;
}
}
/**
Closes the statement if not explicitly closed by the caller.
@exception Throwable If an error occurs.
**/
protected void finalize ()
throws Throwable
{
if(! isClosed ()) {
connection_.setInFinalizer(true);
try{
JDTrace.logInformation (this, "WARNING: Finalizer thread closing statement object.");
close ();
}
catch(Exception e){
//catch any exceptions and don't throw them
}
connection_.setInFinalizer(false);
}
super.finalize ();
}
/**
Returns the appropriate blocking factor for the SQL statement.
@param sqlStatement The SQL statement.
@param rowLength The row length.
@return The blocking factor (in rows).
**/
int getBlockingFactor (String cursorSensitivityProperty,
JDSQLStatement sqlStatement,
int rowLength) // private protected
{
boolean block = false;
boolean useFetchSize = false;
currentJDSQLStatement_ = sqlStatement;
// Allow blocking for asensitive cursors @H1A
int requestDSCursorType = AS400JDBCResultSet.getDBSQLRequestDSCursorType(cursorSensitivityProperty, resultSetType_, resultSetConcurrency_);
// Only block if the cursor is not updatable
// and no locators are in the result set. @B2A
if((cursor_.getConcurrency() != ResultSet.CONCUR_UPDATABLE) // @B2C @EAC
/* && (lastPrepareContainsLocator_ == false) @Z5D */
&& (requestDSCursorType != DBSQLRequestDS.CURSOR_SCROLLABLE_SENSITIVE) &&
(requestDSCursorType != DBSQLRequestDS.CURSOR_NOT_SCROLLABLE_SENSITIVE)) //@KKB we do not want to block if a sensitive cursor is being used
{ // @B2A
// Determine if we should block based on the block
// criteria and SQL statement characteristics.
if(blockCriteria_.equalsIgnoreCase (JDProperties.BLOCK_CRITERIA_NONE))
{
block = true;
useFetchSize = true;
if(JDTrace.isTraceOn()) {
JDTrace.logInformation (this, "getBlockingFactor(): Blocking -- blockCriteria_="+blockCriteria_);
}
//
// The documentation for Statement.setFetchSize() says
// that fetchSize is used when the blockSize is 0
//
} else if (fetchSize_ > 1 && blockSize_ == 0) {
block = true;
useFetchSize = true;
if(JDTrace.isTraceOn()) {
JDTrace.logInformation (this, "getBlockingFactor(): Blocking -- fetchSize="+fetchSize_);
}
} else if(sqlStatement != null) {
if((blockCriteria_.equalsIgnoreCase (JDProperties.BLOCK_CRITERIA_IF_FETCH))
&& (sqlStatement.isForFetchOnly())) {
block = true;
if(JDTrace.isTraceOn()) {
JDTrace.logInformation (this, "getBlockingFactor(): Blocking -- blockCriteria_="+blockCriteria_+" and isForFetchOnly");
}
} else if((blockCriteria_.equalsIgnoreCase (JDProperties.BLOCK_CRITERIA_UNLESS_UPDATE))
&& (! sqlStatement.isForUpdate())) {
block = true;
if(JDTrace.isTraceOn()) {
JDTrace.logInformation (this, "getBlockingFactor(): Blocking -- blockCriteria_="+blockCriteria_+" and isForFetchOnly");
}
} else {
if(JDTrace.isTraceOn()) {
JDTrace.logInformation (this, "getBlockingFactor(): Blocking ="+block+" blockCriteria="+ blockCriteria_);
}
}
} else {
if(blockCriteria_.equalsIgnoreCase (JDProperties.BLOCK_CRITERIA_UNLESS_UPDATE)) {
block = true;
} else {
if(JDTrace.isTraceOn()) {
JDTrace.logInformation (this, "getBlockingFactor(): Blocking ="+block+" blockCriteria="+ blockCriteria_+" sqlStatement is null");
}
}
}
} else {
if(JDTrace.isTraceOn()) {
JDTrace.logInformation (this,
"getBlockingFactor(): Not blocking -- concurrency="+cursor_.getConcurrency()+
/* " lastPrepareContainsLocator_="+lastPrepareContainsLocator_+ @Z5D */
" requestCursorType="+requestDSCursorType);
}
}
// Compute the blocking factor.
int blockingFactor;
if(block)
{
if(useFetchSize) {
blockingFactor = fetchSize_;
if(JDTrace.isTraceOn()) {
JDTrace.logInformation (this,
"getBlockingFactor: blockFactor taken from fetchSize_");
}
}
else
{
if (rowLength <= 0) {
blockingFactor = 1; // Avoid divide by zero -- bug 3119833
} else {
blockingFactor = (blockSize_ * 1024) / rowLength;
if(blockingFactor > 32767) {
blockingFactor = 32767;
} else if(blockingFactor <= 1) {
blockingFactor = 1;
if(JDTrace.isTraceOn()) {
JDTrace.logInformation (this,
"getBlockingFactor: blockFactor is 1: blockSize_="+blockSize_+" rowLength="+rowLength);
}
}
}
}
} else {
blockingFactor = 1;
if(JDTrace.isTraceOn()) {
JDTrace.logInformation (this,
"getBlockingFactor: block=false so blockFactor is 1");
}
}
if(JDTrace.isTraceOn()) {
JDTrace.logInformation (this, "getBlockingFactor: blockFactor is "+blockingFactor);
}
return blockingFactor;
}
// JDBC 2.0
/**
Returns the connection for this statement.
@return The connection for this statement.
@exception SQLException If an error occurs.
**/
public Connection getConnection ()
throws SQLException
{
return connection_;
}
/**
Returns the name of the SQL cursor that is used by
subsequent statement execute methods.
@return The cursor name.
**/
String getCursorName ()
{
synchronized(internalLock_)
{ // @E6A
return cursor_.getName ();
}
}
//@F3A
/**
Returns extended column descriptors for this statement.
This will be null if the user has the "extended meta data"
property set to false (the default).
@return The extended column descriptors for this statement.
**/
/* @P6D
DBExtendedColumnDescriptors getExtendedColumnDescriptors ()
{
synchronized(internalLock_)
{
return extendedColumnDescriptors_;
}
}
*/
// JDBC 2.0
/**
Returns the fetch direction.
@return The fetch direction.
@exception SQLException If the statement is not open.
**/
public int getFetchDirection ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
return fetchDirection_;
}
}
// JDBC 2.0
/**
Returns the fetch size.
@return The fetch size.
@exception SQLException If the statement is not open.
**/
public int getFetchSize ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
return fetchSize_;
}
}
//@G4A JDBC 3.0
/**
Retrieves any auto-generated keys created as a result of executing this Statement object.
In order for this method to return auto-generated keys, the statement must be executed on
a table with an identity column. For more information about identity columns, Go to the
IBM i Information Center, and search on the phrase "identity column".
This method will return null if the user did not request auto-generated keys
during the execute of a Statement or during the prepare of a PreparedStatement.
This method will also return null if the application has not executed the
statement before calling this method.
This method will return an empty result set if the database did not generate
any auto-generated keys when executing the statement.
@return The ResultSet object containing the auto-generated key(s)
generated by the execution of this Statement object, an empty
result set if the database did not generate any auto-generated keys,
or null if the application did not request auto-generated keys or
did not execute the statement before calling this method.
@exception SQLException If the statement is not open,
if connecting to OS/400 V5R1 or earlier,
an error occurs.
@since Modification 5
**/
public ResultSet getGeneratedKeys ()
throws SQLException
{
synchronized(internalLock_)
{
if(connection_.getVRM() < JDUtilities.vrm520) //@F5A
{
//@F5A
JDError.throwSQLException (JDError.EXC_FUNCTION_NOT_SUPPORTED); //@F5A
return null; //@F5A
} //@F5A
//Check if open because generated key result set only makes sense if the
//Statement is currently open.
checkOpen ();
//@F6 If the user didn't execute the statement yet, throw a function sequence exception.
//@F6 If it's just an issue of the database not returning any keys,
//@F6 return an empty result set.
//@F6 Since we will also have null generated keys if the database did not
//@F6 return us any values, return null instead of throwing a function sequence error.
//@F6 This matches the behavior of Statement.getResultSet() if no result set was
//@F6 created, or getResultSet() is called before executing a statement.
//@F6D If we have not made any generated keys yet, a statement must
//@F6D not have been executed, so throw a function sequence error.
//@F6D if (generatedKeys_ == null)
//@F6D JDError.throwSQLException (JDError.EXC_FUNCTION_SEQUENCE);
return generatedKeys_;
}
}
/**
Returns the maximum field size limit for the statement.
The maximum field size limit is the maximum amount of data
returned for any column value. It applies only to BINARY,
VARBINARY, CHAR, and VARCHAR fields. If the limit is exceeded,
then the excess data is discarded.
@return The maximum field size limit (in bytes), or
0 for no limit.
@exception SQLException If the statement is not open.
**/
public int getMaxFieldSize ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
return maxFieldSize_;
}
}
/**
Returns the maximum rows limit for the statement.
The maximum rows limit is the maximum number of rows that a
result set can contain. If the limit is exceeded, then the
excess rows are dropped.
@return The maximum rows limit, or 0 for no limit.
@exception SQLException If the statement is not open.
**/
public int getMaxRows ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
return maxRows_;
}
}
/**
Returns the next result set. This closes the
current result set.
@return true if another result set is available, false
if there are no more result sets.
@exception SQLException If an error occurs.
**/
public boolean getMoreResults ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "getMoreResults() numberOfResults="+numberOfResults_);
// Initialize.
cancelled_ = false;
checkOpen ();
closeResultSet (JDCursor.REUSE_RESULT_SET);
// Determine if there more result sets.
if(--numberOfResults_ > 0)
{
// Send the data stream.
DBSQLRequestDS request = null; //@P0A
boolean extendedMetaData = false; //@P6A
try
{
if((connection_.getVRM() >= JDUtilities.vrm610)) {
/*@K3A*/
int requestedORS = DBSQLRequestDS.ORS_BITMAP_RETURN_DATA+DBSQLRequestDS.ORS_BITMAP_SQLCA+DBSQLRequestDS.ORS_BITMAP_DATA_FORMAT+DBSQLRequestDS.ORS_BITMAP_CURSOR_ATTRIBUTES;
extendedMetaData = connection_.getProperties().getBoolean(JDProperties.EXTENDED_METADATA);
if (extendedMetaData)
{
requestedORS = requestedORS + DBSQLRequestDS.ORS_BITMAP_EXTENDED_COLUMN_DESCRIPTORS;
}
request = DBDSPool.getDBSQLRequestDS(DBSQLRequestDS.FUNCTIONID_OPEN_DESCRIBE, id_, requestedORS, 0); //@cur
} else {
request = DBDSPool.getDBSQLRequestDS(DBSQLRequestDS.FUNCTIONID_OPEN_DESCRIBE, id_, DBSQLRequestDS.ORS_BITMAP_RETURN_DATA+DBSQLRequestDS.ORS_BITMAP_SQLCA+DBSQLRequestDS.ORS_BITMAP_DATA_FORMAT, 0); //@P0C
}
int openAttributes = cursor_.getOpenAttributes(null, blockCriteria_); // @E1A
request.setOpenAttributes(openAttributes); // @E1C
//Set the cursor scrollability option if V5R3 or higher, prior to V5R3 we can only be forward only.
if(connection_.getVRM() >= JDUtilities.vrm530)
{
String cursorSensitivity = connection_.getProperties().getString(JDProperties.CURSOR_SENSITIVITY); //@F8A
/* @H1A Use common routine to determine scrollability */
request.setScrollableCursorFlag(AS400JDBCResultSet.getDBSQLRequestDSCursorType(cursorSensitivity, resultSetType_, resultSetConcurrency_));
}
if (getMoreResultsReply != null) { getMoreResultsReply.returnToPool(); getMoreResultsReply=null; }
getMoreResultsReply = connection_.sendAndReceive (request, id_); //@P0C
// Gather information from the reply.
// DBReplySQLCA sqlca = getMoreResultsReply.getSQLCA ();
DBDataFormat dataFormat = getMoreResultsReply.getDataFormat ();
if (extendedMetaData) { //@P6A
DBExtendedColumnDescriptors newDescriptors = getMoreResultsReply
.getExtendedColumnDescriptors(); //@P6A
if (newDescriptors != null) { //@P6A
extendedColumnDescriptors_ = newDescriptors; //@P6A
} else {
// There were no extended descriptors. Do not use a
// stale one.
extendedColumnDescriptors_ = null; //@P6A
} //@P6A
} else { //@P6A
extendedColumnDescriptors_ = null; //@P6A
} //@P6A
// Check for system errors.
int errorClass = getMoreResultsReply.getErrorClass();
int returnCode = getMoreResultsReply.getReturnCode();
if(errorClass != 0)
{
if(returnCode < 0) {
//
// Trace where this statement was created and the other statements
// on the connection where created.
//
if (JDTrace.isTraceOn()) {
JDTrace.logException(this, "Creation location", creationLocation_);
connection_.dumpStatementCreationLocation();
}
JDError.throwSQLException (this, connection_, id_, errorClass, returnCode);
} else {
postWarning (JDError.getSQLWarning (connection_, id_, errorClass, returnCode));
}
}
// Do not use the dataFormat until we know there is not an error
if(this instanceof AS400JDBCCallableStatement) { // @550A
// Also make sure the format is not null (prevent NPE)
if (dataFormat == null) {
JDError.throwSQLException (JDError.EXC_INTERNAL,"null dataFormat");
return false; // @P6A
}
dataFormat.setCSRSData(true); // @550A
}
cursor_.setExtendedColumnDescriptorsFromReply(getMoreResultsReply); //@P6A
// Process a potential cursor conecurrency override. @E1A @EAC
cursor_.processConcurrencyOverride(openAttributes, getMoreResultsReply); // @E1A @EAC
cursor_.processCursorAttributes(getMoreResultsReply); //@cur
// Note that the cursor was opened.
cursor_.setState (false);
// Compute the result set.
JDServerRow row = new JDServerRow (connection_, id_, dataFormat,
settings_);
String cursorSensitivity = connection_.getProperties().getString(JDProperties.CURSOR_SENSITIVITY); //@F8A
JDServerRowCache rowCache = new JDServerRowCache (
row,
connection_, id_,
getBlockingFactor (cursorSensitivity,
null,
row.getRowLength()),
false,
resultSetType_,
cursor_); //@PDC perf //@pda perf2 - fetch/close
// If the result set concurrency is updatable, check to @E1C
// see if the system overrode the cursor type to read only. @E1C
// Don't worry about the other direction (system overrides @E1C
// from read-only to updatable). @E1C
int actualConcurrency = (resultSetConcurrency_ == ResultSet.CONCUR_UPDATABLE) // @E1C
? cursor_.getConcurrency() : resultSetConcurrency_; // @E1C @EAC
resultSet_ = new AS400JDBCResultSet (this, null,
rowCache, connection_.getCatalog(),
cursor_.getName(), maxRows_, resultSetType_,
actualConcurrency, fetchDirection_,
fetchSize_, extendedColumnDescriptors_); // @ECC@P6A
if(resultSet_.getConcurrency () != resultSetConcurrency_)
postWarning (JDError.getSQLWarning (JDError.WARN_OPTION_VALUE_CHANGED));
}
catch(DBDataStreamException e)
{
JDError.throwSQLException (JDError.EXC_INTERNAL, e);
}
finally
{ //@P0A
if(request != null) {
request.returnToPool(); request = null;
}
if (getMoreResultsReply != null) { getMoreResultsReply.returnToPool(); getMoreResultsReply = null; }
}
}
// Check to see if the statement was cancelled.
if(cancelled_)
JDError.throwSQLException (JDError.EXC_OPERATION_CANCELLED);
// @A0A
// Added code to set updateCount_ = -1.
updateCount_ = -1; // @A0A
return(resultSet_ != null);
}
}
//@G4A JDBC 3.0
/**
Returns the next result set. This closes the current result set. This method
handles any current ResultSet object(s) according to the instructions specified
by the actionOnCurrentResultSet parameter, and returns true if the next result is a
ResultSet object.
@param current What should happen to current ResultSet objects
obtained using the method getResultSet. Valid values are
CLOSE_CURRENT_RESULT, KEEP_CURRENT_RESULT, and CLOSE_ALL_RESULTS.
@return Always false because this method is not supported.
@exception SQLException if DatabaseMetaData.supportsMultipleOpenResults returns false
and either Statement.KEEP_CURRENT_RESULT or Statement.CLOSE_ALL_RESULTS are
supplied as the argument.
@since Modification 5
**/
public boolean getMoreResults (int current)
throws SQLException
{
if(current == Statement.CLOSE_CURRENT_RESULT) //@forum1
return getMoreResults(); //@forum1
JDError.throwSQLException (JDError.EXC_FUNCTION_NOT_SUPPORTED);
return false;
}
//@F10A
/**
Will return the value of the last syntax error that came back from the IBM i system.
@return The value of the character of the last syntax error from the system,
or 0 if no errors occurred or the value is not known.
@exception SQLException If the statement is not open.
**/
public int getPositionOfSyntaxError ()
throws SQLException
{
synchronized(internalLock_)
{
checkOpen ();
return positionOfSyntaxError_;
}
}
/**
Returns the query timeout limit for this statement.
The query timeout limit is the number of seconds that the
driver will wait for an SQL statement to execute.
@return The query timeout limit (in seconds), or
0 for no limit.
@exception SQLException If the statement is not open.
**/
public int getQueryTimeout ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
return queryTimeout_;
}
}
/**
Returns the current result set.
@return The current result set, or null if an update
count was returned or there are no more
result sets.
@exception SQLException If the statement is not open.
**/
public ResultSet getResultSet ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
return resultSet_;
}
}
// JDBC 2.0
/**
Returns the result set concurrency to be used for this statement.
@return The result set concurrency.
@exception SQLException If the statement is not open.
**/
public int getResultSetConcurrency ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
return resultSetConcurrency_;
}
}
//@G4A JDBC 3.0
/**
Returns the result set cursor holdability to be used for this statement.
@return The cursor holdability. Valid values are ResultSet.HOLD_CURSORS_OVER_COMMIT and
ResultSet.CLOSE_CURSORS_AT_COMMIT. The holdability is derived in this order
of precedence:
- 1. The holdability, if any, that was specified on statement creation using
the methods createStatement(), prepareCall(), or prepareStatement() on the
Connection object.
- 2. The holdability specified using the method setHoldability(int)
if this method was called on the Connection object.
- 3. If neither of above methods were called, the value of the
cursor hold
driver property.
Full functionality of #1 and #2 requires OS/400 v5r2
or IBM i. If connecting to OS/400 V5R1 or earlier,
the value specified on these two methods will be ignored and the default holdability
will be the value of #3.
@exception SQLException If the statement is not open.
@since Modification 5
**/
public int getResultSetHoldability ()
throws SQLException
{
synchronized(internalLock_)
{
checkOpen ();
//if we can get info from resultSet (post 540), that will be more accurate, since it can be from stored-proc cursor
if((resultSet_ != null) && (!resultSet_.isClosed())) //@cur //@cur2
return resultSet_.getHoldability(); //@cur
//@F4 If resultSetHoldability_ was set by the user, then return it. Otherwise,
//@F4 return the connection's holdability.
if((resultSetHoldability_ == AS400JDBCResultSet.HOLD_CURSORS_OVER_COMMIT) || //@F4A
(resultSetHoldability_ == AS400JDBCResultSet.CLOSE_CURSORS_AT_COMMIT)) //@F4A
{
//@F4A
return resultSetHoldability_; //@F4A
} //@F4A
return connection_.getHoldability();
}
}
// JDBC 2.0
/**
Returns the result set type to be used for this statement.
@return The result set type.
@exception SQLException If the statement is not open.
**/
public int getResultSetType ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
return resultSetType_;
}
}
/**
Returns the current update count.
@return The update count, or -1 if a result set was
returned or there are no more result sets.
@exception SQLException If the statement is not open.
**/
public int getUpdateCount ()
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
return(resultSet_ != null) ? -1 : updateCount_;
}
}
/**
Returns the first warning reported for the statement.
Subsequent warnings may be chained to this warning.
@return The first warning, or null if no warnings
have been reported.
@exception SQLException If an error occurs.
**/
public SQLWarning getWarnings ()
throws SQLException
{
return sqlWarning_;
}
//@KBL
/*
Sets whether or not the statement has been partially closed and if the remaining resources
should be freed when a transaction boundary is reached.
A statement may become partially closed if the user specified to keep statements associated with
locators open until a transaction boundary by setting the "hold statements" connection property to true.
*/
void setHoldStatement(boolean hold){
holdStatement_ = hold;
}
//@KBL
/*
Returns whether or not the statement has been partially closed.
A statement may become partially closed if the user specified to keep statements associated with
locators open until a transaction boundary by setting the "hold statements" connection property to true.
*/
boolean isHoldStatement()
{
return holdStatement_;
}
//@KBL
/*
Sets whether or not this statement object has been used to access a locator.
*/
void setAssociatedWithLocators(boolean hasLocator){
associatedWithLocators_ = hasLocator;
}
//@KBL
/*
Returns whether or not this statement object has been used to access a locator.
*/
boolean isAssociatedWithLocators(){
return associatedWithLocators_;
}
/**
Indicates if the statement is closed.
@return true if the statement is closed;
false otherwise.
* @throws SQLException If a database error occurs.
**/
public boolean isClosed () throws SQLException //@PDC jdbc40
{
return closed_;
}
//@G4A
/**
Creates a result set to be returned from getGeneratedKeys().
Make an empty result set if return code is < 0 because the information
will not be waiting for us in the SQLCA.
**/
private void makeGeneratedKeyResultSet(int returnCode, DBReplySQLCA sqlca)
throws SQLException
{
//@F6A Make sure we close the generated key result set. We don't have to
//@F6A check to see if the user closed it already because close() does
//@F6A that for us already.
if(generatedKeys_ != null) //@F6A
{
//@F6A
generatedKeys_.close(); //@F6A
} //@F6A
//Code checks we are running to a v5r2 or later system before calling this method
BigDecimal generatedKey = null; //@F6C
if(JDTrace.isTraceOn())
JDTrace.logInformation (this, "returnCode is: " + returnCode);
if(returnCode < 0)
{
// If SQLCode (returnCode) from system is not 0, then don't go look
// for auto-generated key because it will not be there. Instead,
// make empty result set.
//@F6D generatedKey = "";
if(JDTrace.isTraceOn())
JDTrace.logInformation (this, "return code was not 0, generated key is null");
}
else
{
// As of right now, we will only be returned the last auto-generated key.
// Even though it is wasteful to return a ResultSet with only one element,
// that's what the spec. says we have to do.
// Consider going to system in the future to fill in the field name.
// Right now, it doesn't seem like a cost-effective trip.
// If there is no error, the errmc is instead filled with the auto-generated
// key for us.
generatedKey = sqlca.getGeneratedKey(); //@P0C @F6C Deleted converter
if(JDTrace.isTraceOn())
JDTrace.logInformation (this, "generated key from system is: " + generatedKey);
// generatedKey will be null if the database did not return to us a
// proper generatedKey
}
String[] fieldNames = {""};
SQLData[] sqlData = { new SQLDecimal (30, 0, settings_, connection_.getVRM(), connection_.getProperties())}; //@F6C // @M0C - changed SQLDecimal ctor signature
int[] fieldNullables = {AS400JDBCDatabaseMetaData.columnNoNulls};
JDSimpleRow formatRow = new JDSimpleRow (fieldNames, sqlData, fieldNullables);
boolean[][] nulls = {{false}};
boolean[][] dataMappingErrors = {{false}};
JDRowCache rowCache = null;
if(generatedKey == null)
{
rowCache = new JDSimpleRowCache(formatRow);
}
else
{
Object[][] data = {{generatedKey}};
rowCache = new JDSimpleRowCache (formatRow, data, nulls, dataMappingErrors);
}
// Construct with row cache, no catalog, and no cursor name
generatedKeys_ = new AS400JDBCResultSet (rowCache, "", "", connection_, null); //@in2
}
// @B3A
/**
Marks the cursor as closed.
@param isRollback True if we called this from rollback(), false if we called this from commit().
**/
void markCursorClosed(boolean isRollback) //@F4C
throws SQLException //@F2A
{
// @K94 - See if the user requested to hold cursors after a rollback
boolean rollbackCursorHold = connection_.getProperties().getBoolean(JDProperties.ROLLBACK_CURSOR_HOLD); //@K94
if(rollbackCursorHold) //@K94
isRollback = false; //@K94
// @F4 Added a check of statement level holdability because the user can specify the
// @F4 holdability of a specific statement (as a different value than the connection
// @F4 holdability) with JDBC 3.0 support. If this was called from Connection.rollback(),
// @F4 close all statements.
if((getResultSetHoldability() == AS400JDBCResultSet.CLOSE_CURSORS_AT_COMMIT //@F4A
|| isRollback) //@F4A
&& ((connection_.getVRM() <= JDUtilities.vrm610)
|| ((connection_.getVRM() >= JDUtilities.vrm710) && cursor_.getCursorIsolationLevel() != 0))) //@isol only close if cursor's isolationlvl is not *none
{
//@F5D cursor_.setState(true);
//@F4 Instead of calling closeResultSet which does more work than we need to,
//@F4 just move the code here that we need to clean up our internal variables.
//@F4 Otherwise, we'd make an unnecessary flow to the system to tell it to
//@F4 close the cursor which it already has.
// synchronized to prevent race with closeResultSet
synchronized(internalLock_) {
if(resultSet_ != null) //@F4A
{
//@F4A
if(! resultSet_.isClosed ()) //@F4A
resultSet_.close (); //@F4A
resultSet_ = null; //@F4A
} //@F4A
}
updateCount_ = -1; //@F4A
}
}
/**
Notifies the statement that its result set has been closed.
@exception SQLException If an error occurs.
**/
void notifyClose ()
throws SQLException
{
// The result set is close, so we can close the cursor.
if(! cursor_.isClosed ())
{
if(numberOfResults_ > 1) {
cursor_.close (JDCursor.REUSE_RESULT_SET);
} else {
// Only one result set.
cursor_.close (JDCursor.REUSE_YES);
}
}
// Close statement if closeOnCompletion_ and all results have been processed.
if (closeOnCompletion_ && numberOfResults_ <= 1) { // @D7A
this.close();
}
}
/**
Posts a warning for the statement.
@param sqlWarning The warning.
**/
void postWarning (SQLWarning sqlWarning)
{
/* check to see if warning should be ignored */
if( connection_ != null && connection_.ignoreWarning(sqlWarning)) {
if (JDTrace.isTraceOn ()) {
JDTrace.logInformation(this, "postWarning("+sqlWarning+") -- ignored");
}
} else {
if (JDTrace.isTraceOn ()) {
JDTrace.logInformation(this, "postWarning("+sqlWarning+")");
}
if(sqlWarning_ == null)
sqlWarning_ = sqlWarning;
else
sqlWarning_.setNextWarning (sqlWarning);
}
}
// @E9C
/**
Sets the SQL cursor name that will be used by the statement.
Cursor names must be unique within the connection.
The cursor name can only be set when no result set is open.
The cursor name can be used in SQL positioned UPDATE or DELETE
statements to identify the current row in the result set generated
by this statement. By definition, SQL positioned UPDATEs or
DELETEs must be executed by a different statement than the one
that generated the result set being used for positioning.
Cursor names are case sensitive. However, when using a cursor
name within other SQL positioned UPDATE or DELETE statements,
the cursor name will be uppercased. If you use a cursor name
with lowercase characters, you need to enclose it in double
quotes when referring to it in other SQL statements.
@param cursorName The cursor name. If null, a unique
default name will be used.
@exception SQLException If the statement is not open,
a result set is open, the cursor
name is not unique within the
connection, or an error occurs.
**/
//
// Implementation note:
//
// If you set the cursor name to a mixed case string, and then
// later refer to it in an SQL statement, SQL will choke because it
// will have uppercased the string.
//
// At first I thought we should always uppercase, the cursor name
// but that limits callers. The better solution is to have the callers
// surround mixed case cursor names in SQL statements with double
// quotes.
//
public void setCursorName (String cursorName)
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
// Check that no cursor is open for this statement.
// We can not just check the cursor, because if the
// caller closes the result set, we do not close the
// cursor right away.
if(resultSet_ != null)
{
if(! resultSet_.isClosed ())
JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID);
else
closeResultSet (JDCursor.REUSE_YES);
}
// If name is null, then use the default name.
if(cursorName == null)
cursorName = cursorDefaultName_;
// Validate the length of the cursor name.
int cursorNameLength = cursorName.length(); // @EEA
int maxLength = (connection_.getVRM() >= JDUtilities.vrm610) ? MAX_CURSOR_NAME_LENGTH : MAX_CURSOR_NAME_LENGTH_PRE_V6R1; //@550 128 byte cursor name support
if((cursorNameLength > maxLength) || (cursorNameLength == 0)) // @EEC @550 changed MAX_CURSOR_NAME_LENGTH to maxLength
JDError.throwSQLException (JDError.EXC_CURSOR_NAME_INVALID);
// If the name is the same as the current cursor name,
// then nothing needs to be done. (If we go through
// with the change and the cursor name is the same, it
// will get flagged as ambiguous).
if(! cursorName.equals (cursor_.getName ()))
{
// Check that the cursor name is unique within the
// connection.
if(connection_.isCursorNameUsed (cursorName))
JDError.throwSQLException (JDError.EXC_CURSOR_NAME_AMBIGUOUS);
cursor_.setName (cursorName);
// Since we store the cursor name in the RPB, we need
// to sync it after a change.
rpbSyncNeeded_ = true;
connectionReset_ = false;
}
}
}
/**
Sets the escape processing mode. When processing escape
clauses, the JDBC driver substitutes escape clauses
in SQL statements with DB2 for IBM i SQL grammar elements.
If escape processing is not needed, then setting the escape
processing mode to false improves performance.
@param escapeProcessing true to process escape clauses;
false otherwise. The default
is true.
@exception SQLException If the statement is not open.
**/
public void setEscapeProcessing (boolean escapeProcessing)
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
escapeProcessing_ = escapeProcessing;
if(JDTrace.isTraceOn())
JDTrace.logProperty (this, "set..", "Escape processing", escapeProcessing_);
}
}
// JDBC 2.0
/**
Sets the direction in which the rows in a result set will be
processed.
This setting is not used.
@param fetchDirection The fetch direction for processing rows.
Valid values are:
- ResultSet.FETCH_FORWARD
- ResultSet.FETCH_REVERSE
- ResultSet.FETCH_UNKNOWN
The default is ResultSet.FETCH_FORWARD.
@exception SQLException If the statement is not open,
the result set type is
ResultSet.TYPE_FORWARD_ONLY,
and the input value is not
ResultSet.FETCH_FORWARD,
or the input value is not valid.
**/
public void setFetchDirection (int fetchDirection)
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
if(((fetchDirection != ResultSet.FETCH_FORWARD)
&& (fetchDirection != ResultSet.FETCH_REVERSE)
&& (fetchDirection != ResultSet.FETCH_UNKNOWN))
|| ((resultSetType_ == ResultSet.TYPE_FORWARD_ONLY)
&& (fetchDirection != ResultSet.FETCH_FORWARD)))
JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);
checkOpen ();
fetchDirection_ = fetchDirection;
if(JDTrace.isTraceOn())
JDTrace.logProperty (this, "set..", "Fetch direction", fetchDirection_);
}
}
// JDBC 2.0
/**
Sets the number of rows to be fetched from the database when more
rows are needed. The number of rows specified only affects result
sets created using this statement. If the value specified is zero,
then the driver will choose an appropriate fetch size.
This setting only affects statements that meet the criteria
specified in the "block criteria" property. The fetch size
is only used if the "block size" property is set to "0".
This setting only takes effect for result sets that are opened
after this method has been called. Ideally, this method should be
called before the statement is executed.
@param fetchSize The number of rows. This must be greater than
or equal to 0 and less than or equal to the
maximum rows limit. The default is zero.
@exception SQLException If the statement is not open
or the input value is not valid.
**/
public void setFetchSize (int fetchSize)
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
if((fetchSize < 0)
|| ((fetchSize > maxRows_) && (maxRows_ > 0)))
JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);
checkOpen ();
fetchSize_ = fetchSize;
if(JDTrace.isTraceOn())
JDTrace.logProperty (this, "set..", "Fetch size", fetchSize_);
}
}
/**
Sets the maximum field size limit. The maximum field size
limit is the maximum amount of data returned for any column
value. It applies only to BINARY, VARBINARY, CHAR, and VARCHAR
fields. If the limit is exceeded, then the excess data is
discarded.
@param maxFieldSize The maximum field size limit (in bytes) or
0 for no limit. The default is 0.
@exception SQLException If the statement is not open
or the input value is not valid.
**/
public void setMaxFieldSize (int maxFieldSize)
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
// Validate the argument.
if(maxFieldSize < 0)
JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);
maxFieldSize_ = maxFieldSize;
settings_ = SQLConversionSettings.getConversionSettingsWithMaxFieldSize(settings_,maxFieldSize);
if (parameterRow_ != null) {
parameterRow_.updateSettings(settings_);
}
if(JDTrace.isTraceOn())
JDTrace.logProperty (this, "set..", "Max field size", maxFieldSize_);
}
}
/**
Sets the maximum rows limit. The maximum rows limit is the
maximum number of rows that a result set can contain.
If the limit is exceeded, the excess rows are dropped.
@param maxRows The maximum rows limit or 0 for no limit.
The default is 0.
@exception SQLException If the statement is not open
or the input value is not valid.
**/
//
// Implementation note:
//
// We had a debate about what this means with respect to scrollable
// result sets. Does it limit the number of rows in the result set,
// or the number of rows fetched. I.e., if you set the max rows to
// 50, can you successfully do absolute(51)? It is only fetching
// 1 row. The answer came back from the JavaSoft people that it
// does indeed limit the number of rows in the result set, not
// necessarily the number of fetches.
//
public void setMaxRows (int maxRows)
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
// Validate the argument.
if(maxRows < 0)
JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);
maxRows_ = maxRows;
longMaxRows_ = maxRows;
if(JDTrace.isTraceOn())
JDTrace.logProperty (this, "set..", "Max rows", maxRows_);
}
}
/**
Sets the query timeout limit. The query timeout limit
is the number of seconds that the driver will wait for a
SQL statement to execute.
This is implemented using the database query time limit, also
known as QQRYTIMLMT. This value specifies the query processing time limit that is
compared to the estimated number of elapsed seconds that a query must run. The
time limit determines if the database query can start.
Beginning with Version 6 Release 1 of IBM i, you must have *JOBCTL special authority.
@param queryTimeout The query timeout limit (in seconds)
or 0 for no limit. The default is the job's query timeout limit
value unless this method is explicitly called.
@exception SQLException If the statement is not open
or the input value is not valid.
**/
public void setQueryTimeout (int queryTimeout)
throws SQLException
{
synchronized(internalLock_)
{ // @E6A
checkOpen ();
// Validate the argument.
if(queryTimeout < 0)
JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);
if((queryTimeout_ != queryTimeout) || !queryTimeoutSet_) /*@B2C*/
{
queryTimeoutSet_ = true; /*@B2A*/
queryTimeout_ = queryTimeout;
// Since we store the query timeout in the RPB, we need
// to sync it after a change.
rpbSyncNeeded_ = true;
rpbQueryTimeoutChanged_ = true; //@EFA
}
if(JDTrace.isTraceOn())
JDTrace.logProperty (this, "set..", "Query timeout", queryTimeout_);
}
}
/**
Creates or changes the RPB (Request Parameter Block) for the
statement.
@exception SQLException If an error occurs.
**/
private void syncRPB ()
throws SQLException
{
if(rpbSyncNeeded_)
{
int functionId = rpbCreated_ ? DBSQLRPBDS.FUNCTIONID_CHANGE_RPB
: DBSQLRPBDS.FUNCTIONID_CREATE_RPB;
DBSQLRPBDS request = null; //@P0A
try
{
ConvTable converter = connection_.getConverter();
request = DBDSPool.getDBSQLRPBDS(functionId, id_, 0, 0); //@P0C
request.setPrepareStatementName (name_, converter); //@P0C
request.setCursorName (cursor_.getName (), converter); //@P0C
if(packageManager_.isEnabled())
request.setLibraryName (packageManager_.getLibraryName (), converter); //@P0C
if(rpbQueryTimeoutChanged_) //@EFA
{
// Don't set the query timeout in the request if using the cancel query timeout mechanism @D4C
if(queryTimeout_ > 0 && !connection_.isQueryTimeoutMechanismCancel())
request.setQueryTimeout (queryTimeout_);
else
request.setQueryTimeout (-1);
}
if(! connection_.getMustSpecifyForUpdate()) // @J3a @J31c
{
// @J3a
if(resultSetConcurrency_ == ResultSet.CONCUR_UPDATABLE) // @J3a
request.setOpenAttributes(0x10 + 0x20 + 0x40 + 0x80); // @J3a
} // @J3a
//@F5D Do not need to specify this on the RPB
//@F5D Check system level before sending new code point
//@F5D if (connection_.getVRM() >= JDUtilities.vrm520) // @F4A
//@F5D {
//@F5D if (resultSetHoldability_ == AS400JDBCResultSet.CLOSE_CURSORS_AT_COMMIT) // @F4A
//@F5D request.setResultSetHoldabilityOption((byte)0xD5); // @F4A
//@F5D else if (resultSetHoldability_ == AS400JDBCResultSet.HOLD_CURSORS_OVER_COMMIT) // @F4A
//@F5D request.setResultSetHoldabilityOption((byte)0xE8); // @F4A
//@F5D}
// @F6A - Send the RPB describe option
String rpbDescOpt = connection_.getProperties().getString(JDProperties.DESCRIBE_OPTION);
if(null != rpbDescOpt && rpbDescOpt.length() > 0){
if(rpbDescOpt.equals(JDProperties.DESCRIBE_OPTION_SYSTEM_NAMES)){
request.setDescribeOption(0xE2);
} else if(rpbDescOpt.equals(JDProperties.DESCRIBE_OPTION_LONG_NAMES)){
request.setDescribeOption(0xD5);
}else if(rpbDescOpt.equals(JDProperties.DESCRIBE_OPTION_LABELS)){
request.setDescribeOption(0xD3);
}
}
connection_.send (request, id_);
}
catch(DBDataStreamException e)
{
JDError.throwSQLException (JDError.EXC_INTERNAL, e);
}
finally
{ //@P0A
if(request != null) {
request.returnToPool(); request = null;
}
}
rpbCreated_ = true;
rpbSyncNeeded_ = false;
connectionReset_ = false;
}
}
/**
Returns the statement name.
@return The statement name.
**/
public String toString ()
{
return name_;
}
/**
Verifies values for the autoGeneratedKey parameter.
@param autoGeneratedKeys Valid values are Statement.RETURN_GENERATED_KEYS and
Statement.NO_GENERATED_KEYS.
@exception SQLException If an error occurs.
**/
static final void verifyGeneratedKeysParameter (int autoGeneratedKeys)
throws SQLException
{
if((autoGeneratedKeys != NO_GENERATED_KEYS)
&& (autoGeneratedKeys != RETURN_GENERATED_KEYS))
JDError.throwSQLException (JDError.EXC_ATTRIBUTE_VALUE_INVALID);
}
//@PDA jdbc40
/**
* Requests that a Statement
be pooled or not pooled. The value
* specified is a hint to the statement pool implementation indicating
* whether the applicaiton wants the statement to be pooled. It is up to
* the statement pool manager as to whether the hint is used.
*
* The poolable value of a statement is applicable to both internal
* statement caches implemented by the driver and external statement caches
* implemented by application servers and other applications.
*
* By default, a Statement
is poolable when it is created.
*
* @param poolable requests that the statement be pooled if true and
* that the statement not be pooled if false
*
* @throws SQLException if the Statement
has been closed
*/
public void setPoolable(boolean poolable) throws SQLException
{
checkOpen();//@pda do same as native
isPoolable_ = poolable;
}
//@PDA jdbc40
/**
* Returns the value of the statements poolable hint, indicating whether
* pooling of the statement is requested.
*
* @return The value of the statements poolable hint.
*
* @throws SQLException if the Statement
has been closed
*
* see java.sql.Statement#setPoolable(boolean) setPoolable(boolean)
*/
public boolean isPoolable() throws SQLException
{
checkOpen();//@pda do same as native
return isPoolable_;
}
//@pda jdbc40
protected String[] getValidWrappedList()
{
return new String[] { "com.ibm.as400.access.AS400JDBCStatement", "java.sql.Statement" };
}
// @D7A
/**
* Specifies that this Statement will be closed when all its dependent result sets are closed.
* If execution of the Statement does not produce any result sets, this method has no effect.
*
Note: Multiple calls to closeOnCompletion do not toggle the effect on this Statement.
* However, a call to closeOnCompletion does effect both the subsequent execution of statements,
* and statements that currently have open, dependent, result sets.
* @throws SQLException - if this method is called on a closed Statement
*/
public void closeOnCompletion() throws SQLException {
checkOpen();
closeOnCompletion_ = true;
}
/**
* Returns a value indicating whether this Statement will be closed when all its dependent result sets are closed.
* @return true if the Statement will be closed when all of its dependent result sets are closed; false otherwise
* @throws SQLException - if this method is called on a closed Statement
*/
// @D7A
public boolean isCloseOnCompletion() throws SQLException {
checkOpen();
return closeOnCompletion_;
}
/*@D4A*/
/**
Handles the work involved in supporting a setQueryTimeout option with the cancel property set. .
**/
protected void startCancelThread()
{
// Start a cancel thread if there is a query running and a timeout value has been
// specified.
if (queryTimeoutSet_ && queryTimeout_ != 0) {
// We only are going to allow the query timeout to effect queries.
// Set a flag that a query is running.
queryRunning_ = true;
// Create a thread to do the cancel if needed. Start the thread.
cancelThread_ = new AS400JDBCQueryCancelThread(this);
// Uncommented this @A7A ..
// this is needed to prevent job from hanging if the extra threads
// we started don't end.
//
cancelThread_.setDaemon(true);
cancelThread_.start();
}
}
/*@D4A*/
/**
* endTheCancelThread
**/
protected void endCancelThread()
{
// Deal with the cancel thread at this point.
if (queryTimeout_ != 0) {
// Set the flag saying the query is no longer running.
queryRunning_ = false;
// Detach the thread from the statement.
cancelThread_.statement_ = null;
// Interrupt the thread so that it wakes up and dies.
cancelThread_.interrupt();
}
}
/**
*
Retrieves the current result as an update count; if the result is a ResultSet object
* or there are no more results, -1 is returned. This method should be called only
* once per result.
*
This method should be used when the returned row count may exceed Integer.MAX_VALUE.
*
* @return the current result as an update count; -1 if the current result is a ResultSet
* object or there are no more results
* @throws SQLException - if a database access error occurs or this method is
* called on a closed Statement
*/
public long getLargeUpdateCount() throws SQLException {
return (long) getUpdateCount();
}
/**
*
Sets the limit for the maximum number of rows that any ResultSet object
*generated by this Statement object can contain to the given number.
*If the limit is exceeded, the excess rows are silently dropped.
*
This method should be used when the row limit may exceed Integer.MAX_VALUE.
* @param max the new max rows limit; zero means there is no limit
* @throws SQLException - if a database access error occurs, this
* method is called on a closed Statement or the
* condition max >= 0 is not satisfied
*/
public void setLargeMaxRows(long max) throws SQLException {
int intMax = (int) max;
// If we overflow, just set it to no limit
if (max > 0x7FFFFFFF) {
intMax = 0;
}
setMaxRows(intMax);
longMaxRows_ = max;
}
/**
*Retrieves the maximum number of rows that a ResultSet object produced by this
*Statement object can contain. If this limit is exceeded, the excess rows
*are silently dropped.
*
This method should be used when the returned row limit may exceed Integer.MAX_VALUE.
* @return the current maximum number of rows for a ResultSet object produced by this
* means there is no limit
* @throws SQLException -if a database access error occurs or this method is
* called on a closed Statement
*/
public long getLargeMaxRows() throws SQLException {
checkOpen ();
return longMaxRows_;
}
/**
*
Submits a batch of commands to the database for execution and if all commands
* execute successfully, returns an array of update counts. The long elements of
* the array that is returned are ordered to correspond to the commands in the batch,
* which are ordered according to the order in which they were added to the batch.
* The elements in the array returned by the method executeLargeBatch may be one of
* the following:
*
*
A number greater than or equal to zero -- indicates that the command was
* processed successfully and is an update count giving the number of rows in
* the database that were affected by the command's execution
*
A value of SUCCESS_NO_INFO -- indicates that the command was processed
* successfully but that the number of rows affected is unknown.
*
*
If one of the commands in a batch update fails to execute properly,
* this method throws a BatchUpdateException, and a JDBC driver may or may
* not continue to process the remaining commands in the batch. However,
* the driver's behavior must be consistent with a particular DBMS,
* either always continuing to process commands or never continuing to
* process commands. If the driver continues processing after a failure,
* the array returned by the method BatchUpdateException.getLargeUpdateCounts
* will contain as many elements as there are commands in the batch, and
* at least one of the elements will be the following:
*
*
A value of EXECUTE_FAILED -- indicates that the command failed to execute
* successfully and occurs only if a driver continues to process commands
* after a command fails
*
*
This method should be used when the returned row count may exceed
* Integer.MAX_VALUE.
* @return an array of update counts containing one element for each command in the
* batch. The elements of the array are ordered according to the order in which
* commands were added to the batch.
* @throws SQLException - if a database access error occurs, this method is called
* on a closed Statement or the driver does not support batch statements.
* Throws BatchUpdateException (a subclass of SQLException) if one of the commands
* sent to the database fails to execute properly or attempts to return a result set.
* @throws SQLException - when the driver has determined that the timeout value
* that was specified by the setQueryTimeout method has been exceeded and has at least
* attempted to cancel the currently running Statement
*/
public long[] executeLargeBatch() throws SQLException {
int[] results = executeBatch();
long[] longResults = new long[results.length];
for (int i = 0; i < results.length; i++) {
longResults[i] = results[i];
}
return longResults;
}
/**
* Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE
* statement or an SQL statement that returns nothing, such as an SQL DDL
* statement.
*
This method should be used when the returned row count may exceed
* Integer.MAX_VALUE.
*
Note:This method cannot be called on a PreparedStatement or CallableStatement.
* @param sql an SQL Data Manipulation Language (DML) statement, such as INSERT,
* UPDATE or DELETE; or an SQL statement that returns nothing, such as a DDL
* statement.
* @return either (1) the row count for SQL Data Manipulation Language (DML)
* statements or (2) 0 for SQL statements that return nothing
* @throws SQLException - if a database access error occurs, this method is
* called on a closed Statement, the given SQL statement produces a ResultSet
* object, the method is called on a PreparedStatement or CallableStatement.
*/
public long executeLargeUpdate(String sql) throws SQLException {
return (long) executeUpdate(sql);
}
/**
* Executes the given SQL statement and signals the driver with the given flag
* about whether the auto-generated keys produced by this Statement object should
* be made available for retrieval. The driver will ignore the flag if the SQL
* statement is not an INSERT statement, or an SQL statement able to return
* auto-generated keys (the list of such statements is vendor-specific).
*
This method should be used when the returned row count may exceed
* Integer.MAX_VALUE.
* @param sql - an SQL Data Manipulation Language (DML) statement, such as
* INSERT, UPDATE or DELETE; or an SQL statement that returns nothing, such
* as a DDL statement.
* @param autoGeneratedKeys - a flag indicating whether auto-generated keys
* should be made available for retrieval; one of the following constants:
* Statement.RETURN_GENERATED_KEYS Statement.NO_GENERATED_KEYS
* @return either (1) the row count for SQL Data Manipulation Language (DML)
* statements or (2) 0 for SQL statements that return nothing
* @throws SQLException - if a database access error occurs, this method is
* called on a closed Statement, the given SQL statement returns a ResultSet
* object, the given constant is not one of those allowed, the method is
* called on a PreparedStatement or CallableStatement
*/
public long executeLargeUpdate(String sql,
int autoGeneratedKeys)
throws SQLException {
return (long) executeUpdate(sql, autoGeneratedKeys);
}
/**
* Executes the given SQL statement and signals the driver that the auto-generated
* keys indicated in the given array should be made available for retrieval. This
* array contains the indexes of the columns in the target table that contain the
* auto-generated keys that should be made available. The driver will ignore the
* array if the SQL statement is not an INSERT statement, or an SQL statement able
* to return auto-generated keys (the list of such statements is vendor-specific).
*
This method should be used when the returned row count may exceed
* Integer.MAX_VALUE.
*
Note:This method cannot be called on a PreparedStatement or CallableStatement.
* @param sql - an SQL Data Manipulation Language (DML) statement, such as INSERT,
* UPDATE or DELETE; or an SQL statement that returns nothing, such as a DDL
* statement.
* @param columnIndexes - an array of column indexes indicating the columns that
* should be returned from the inserted row
* @return either (1) the row count for SQL Data Manipulation Language (DML)
* statements or (2) 0 for SQL statements that return nothing
* @throws SQLException - if a database access error occurs, this method is called
* on a closed Statement, the SQL statement returns a ResultSet object,the second
* argument supplied to this method is not an int array whose elements are valid
* column indexes, the method is called on a PreparedStatement or CallableStatement
*
*/
public long executeLargeUpdate(String sql,
int[] columnIndexes)
throws SQLException {
return (long) executeUpdate(sql, columnIndexes);
}
/**
* Executes the given SQL statement and signals the driver that the
* auto-generated keys indicated in the given array should be made
* available for retrieval. This array contains the names of the columns
* in the target table that contain the auto-generated keys that should
* be made available. The driver will ignore the array if the SQL
* statement is not an INSERT statement, or an SQL statement able
* to return auto-generated keys (the list of such statements is
* vendor-specific).
*
This method should be used when the returned row count may exceed
* Integer.MAX_VALUE.
*
Note:This method cannot be called on a PreparedStatement or
* CallableStatement.
* @param sql - an SQL Data Manipulation Language (DML) statement, such as
* INSERT, UPDATE or DELETE; or an SQL statement that returns nothing,
* such as a DDL statement.
* @param columnNames - an array of the names of the columns that
* should be returned from the inserted row
* @return either the row count for INSERT, UPDATE, or DELETE statements,
* or 0 for SQL statements that return nothing
* @throws SQLException if a database access error occurs, this method
* is called on a closed Statement, the SQL statement returns a ResultSet
* object, the second argument supplied to this method is not a String
* array whose elements are valid column names, the method is called on a
* PreparedStatement or CallableStatement
*/
public long executeLargeUpdate(String sql,
String[] columnNames) throws SQLException {
return (long) executeUpdate(sql, columnNames);
}
JDSQLStatement getJDSQLStatement() {
return currentJDSQLStatement_ ;
}
void setConnectionReset(boolean reset) {
rpbSyncNeeded_ = true;
rpbCreated_ = false;
connectionReset_ = reset;
}
JDCursor getCursor() {
return cursor_;
}
AS400JDBCStatementLock getInternalLock() {
return internalLock_;
}
int getInternalResultSetHoldability() {
return resultSetHoldability_;
}
boolean isQueryRunning() {
return queryRunning_;
}
int getInternalQueryTimeout ()
{
return queryTimeout_;
}
}