All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.ibm.as400.access.AS400JDBCStatement Maven / Gradle / Ivy

There is a newer version: 11.1
Show newest version
///////////////////////////////////////////////////////////////////////////////
//
// 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_; private boolean doNotClearWarningsInExecute_ = false; /** 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; if (!doNotClearWarningsInExecute_) { 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. clearWarnings(); JDServerRow resultRow = commonPrepare(sqlStatement); doNotClearWarningsInExecute_ = true; commonExecute(sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; 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. clearWarnings(); JDServerRow resultRow = commonPrepare (sqlStatement); doNotClearWarningsInExecute_ = true; commonExecute (sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; 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. clearWarnings(); JDServerRow resultRow = commonPrepare (sqlStatement); doNotClearWarningsInExecute_ = true; commonExecute(sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; 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. clearWarnings(); JDServerRow resultRow = commonPrepare (sqlStatement); doNotClearWarningsInExecute_ = true; commonExecute (sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; 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 clearWarnings(); JDServerRow resultRow = commonPrepare (sqlStatement); if(resultRow != null) JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID); doNotClearWarningsInExecute_ = true; commonExecute (sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; 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. clearWarnings(); JDServerRow resultRow = commonPrepare (sqlStatement); doNotClearWarningsInExecute_ = true; commonExecute (sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; 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. clearWarnings(); JDServerRow resultRow = commonPrepare (sqlStatement); if(resultRow != null) JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID); doNotClearWarningsInExecute_ = true; commonExecute (sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; 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. clearWarnings(); JDServerRow resultRow = commonPrepare (sqlStatement); doNotClearWarningsInExecute_ = true; commonExecute (sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; } else { // Prepare and execute. clearWarnings(); JDServerRow resultRow = commonPrepare (sqlStatement); if(resultRow != null) JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID); doNotClearWarningsInExecute_ = true; commonExecute (sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; 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 clearWarnings(); JDServerRow resultRow = commonPrepare(sqlStatement); doNotClearWarningsInExecute_ = true; commonExecute(sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; } 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. clearWarnings(); JDServerRow resultRow = commonPrepare (sqlStatement); if(resultRow != null) JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID); doNotClearWarningsInExecute_ = true; commonExecute (sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; 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 clearWarnings(); JDServerRow resultRow = commonPrepare(sqlStatement); doNotClearWarningsInExecute_ = true; commonExecute(sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; } 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. clearWarnings(); JDServerRow resultRow = commonPrepare (sqlStatement); if(resultRow != null) JDError.throwSQLException (JDError.EXC_CURSOR_STATE_INVALID); doNotClearWarningsInExecute_ = true; commonExecute (sqlStatement, resultRow); doNotClearWarningsInExecute_ = false; 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_; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy