src.com.ibm.as400.access.AS400JDBCConnectionImpl Maven / Gradle / Ivy
Show all versions of jt400-jdk8 Show documentation
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: AS400JDBCConnection.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-2006 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
/* ifdef JDBC40
import java.sql.ClientInfoStatus;
import java.sql.SQLClientInfoException;
import java.sql.SQLPermission;
endif */
import java.sql.Clob;
import java.sql.DatabaseMetaData;
import java.sql.DataTruncation;
/* ifdef JDBC40
import java.sql.NClob;
endif */
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
/* ifdef JDBC40
import java.sql.SQLXML;
endif */
import java.sql.Statement;
import java.sql.Savepoint; // @E10a
import java.sql.Struct;
import java.util.Enumeration; // @DAA
/* ifdef JDBC40
import java.util.HashMap;
endif */
import java.util.Map;
import java.util.Properties;
import java.util.Vector;
/* ifdef JDBC40
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.Executor;
endif */
/**
The AS400JDBCConnection class provides a JDBC connection
to a specific DB2 for IBM i database. Use
DriverManager.getConnection() to create new AS400JDBCConnection
objects.
There are many optional properties that can be specified
when the connection is created. Properties can be specified either
as part of the URL or in a java.util.Properties object. See
JDBC properties for a complete
list of properties supported by the AS400JDBCDriver.
Note that a connection may contain at most 9999 open
statements.
**/
//
// Implementation notes:
//
// 1. Each connection and statement has an "id" associated with
// it. All ids are unique within a connection, and this
// uniqueness is maintained by the id table for each
// connection.
//
// The id is used as a convention for assigning each
// connection and statement its own ORS (Operation Result
// Set) on the IBM i as well as assigning each statement
// its own RPB (Request Parameter Block).
//
// Every communication to the database requires a connection
// and an id within that connection.
//
// 2. It is a requirement that no finalize() methods need to
// receive a reply from the IBM i system. Because of the way the
// AS400Server class is implemented, certain scenarios where
// this is the case will result in deadlock. The AS400Server
// class provides sendAndDiscardReply() specifically to avoid
// this problem.
//
// Within the JDBC driver, finalize() usually calls one or more
// close() methods. Therefore, this requirement is also
// imposed on close() methods.
//
// 3. All requests for the connection and the related objects in
// its context should be sent via a variation of one of the
// sendXXX() methods. This makes debugging cleaner.
//
public class AS400JDBCConnectionImpl
extends AS400JDBCConnection
{
private class CancelLock extends Object {} //@C7A
private class HeldRequestsLock extends Object {} //@C7A
// Turn this flag on to prevent this Connection object from establishing an actual connection to the IBM i system. This is useful when doing multi-threaded stress testing on the Toolbox's built-in JDBC connection pool manager, where we create/delete massive numbers of connections.
// For production, this flag _must_ be set to 'false'.
private static final boolean TESTING_THREAD_SAFETY = false; //@CPMa
// This is a compile time flag for doing simple
// communications traces.
//
// The choices are:
// 0 = No communication trace (for production code).
// 1 = Only request and reply ids.
// 2 = Request and reply ids and contents.
//
// Note that the LL (length) and parameter count for
// requests will not be accurate, since they have not yet
// been set at the time when the request is dumped.
//
private static int DEBUG_COMM_TRACE_ = 0;
// This is a compile time flag for temporarily disabling
// request chaining. This can be useful when a request
// is failing, but all we see is an error class == 7,
// return code == -1000. This means a chain request
// failed.
//
// The choices are:
// true = Enable request chaining (for production code).
// false = Disable request chaining.
//
// @E5D private static final boolean DEBUG_REQUEST_CHAINING_ = true;
// This is a compile time flag for forcing the use of
// extended datastream formats. This can be useful when
// testing extended formats, but the IBM i system is not reporting
// the correct VRM.
//
// The choices are:
// true = Force extended datastream formats.
// false = Decide based on system VRM (for production code).
//
// @E9D private static final boolean FORCE_EXTENDED_FORMATS_ = false;
// @F8 -- the key change is to put a 1 in the 7th position. That 1 is the "ODBC" flag.
// The IBM i passes it along to database to enable correct package caching of
// "where current of" statements. This flag affects only package caching.
// The 2nd and 4th digits are used to turn on variable field compression
// @L3C
static final String CLIENT_FUNCTIONAL_LEVEL_= "V7R2M01 "; // @EDA F8c H2c pdc 610
private static final int DRDA_SCROLLABLE_CUTOFF_ = 129; // @B1A
private static final int DRDA_SCROLLABLE_MAX_ = 255; // @DAA
private static final int INITIAL_STATEMENT_TABLE_SIZE_ = 256; // @DAA
static final int UNICODE_CCSID_ = 13488; // @E3C
// The max number of open statements per connection. If this @DAA
// changes, then change the relevant sentence in the javadoc, too. @DAA
static final int MAX_STATEMENTS_ = 9999; // @DAC
private final boolean[] assigned_ = new boolean[MAX_STATEMENTS_]; //@P0C
// Private data.
private AS400ImplRemote as400_;
private AS400 as400PublicClassObj_; // Prevents garbage collection.
//@P0D private BitSet assigned_; // @DAC
private boolean cancelling_; // @E8A
private CancelLock cancelLock_ = new CancelLock(); // @E8A@C7C
private String catalog_;
boolean checkStatementHoldability_ = false; // @F3A //@XAC
private boolean closing_; // @D4A
private boolean aborted_ = false; // @D7A
// The aborting thread should be able to close resources when the aborted_ flag is set
private Thread abortingThread_ = null;
ConvTable converter_; //@P0C
private int dataCompression_ = -1; // @ECA
private boolean disableCompression_ = false; //@L9A
private JDDataSourceURL dataSourceUrl_;
private boolean drda_; // @B1A
private String defaultSchema_;
private boolean extendedFormats_;
// @E2D private ConverterImplRemote graphicConverter_;
// @E2D private boolean graphicConverterLoaded_;
private Vector heldRequests_; // @E5A
private HeldRequestsLock heldRequestsLock_ = new HeldRequestsLock(); // @E5A@C7C
private int holdability_ = AS400JDBCResultSet.HOLDABILITY_NOT_SPECIFIED; // @G4A
private int id_;
private AS400JDBCDatabaseMetaData metaData_;
private JDPackageManager packageManager_;
private JDProperties properties_;
// Make this visible to classes that pool @L16C
boolean readOnly_;
//@P0D private BitSet requestPending_; // @DAC
//@P1Dprivate final boolean[] requestPending_ = new boolean[MAX_STATEMENTS_]; //@P0A
private AS400Server server_;
private int serverFunctionalLevel_; // @E7A
private String serverJobIdentifier_ = null; // @E8A
private SQLWarning sqlWarning_;
private Vector
statements_ = new Vector(INITIAL_STATEMENT_TABLE_SIZE_); // @DAC
JDTransactionManager transactionManager_; // @E10c
static final ConvTable unicodeConverter_ = new ConvTable13488(); // @E3A @P0C
ConvTable packageCCSID_Converter = null; //Bidi-HCG
int vrm_; // @D0A @E10c
private int correlationID_ = 0; //@D2A - only used for multiple receives
// declare the user-supplied value for server trace. The constants for
// the definition of each bit in the bit map are defined in Trace.java
private int traceServer_ = 0; // @j1a
// set to true if database host server tracing is started via the setDBHostServerTrace method
private boolean databaseHostServerTrace_ = false; // @2KR
private boolean mustSpecifyForUpdate_ = true; // @j31
//counter to keep track of number of open statements
private int statementCount_ = 0; //@K1A
private boolean thousandStatements_ = false; //@K1A
private String qaqqiniLibrary_ = null; //@K2A
//@KBA Specifies level of autocommit support to use.
// If V5R2 or earlier use old support of running SET TRANSACTION STATEMENTS (0)
// If "true autocommit" connection property is false - run autocommit under *NONE isolation (1)
// If "true autocommit" connection property is true - run with specified isolation (2)
int newAutoCommitSupport_ = 1; //@KBA
private boolean wrappedInsert_ = false; // @GKA
//@pda 550 client info
//Names for clientInfo identifiers. DatabaseMetadata also will use these names
static final String applicationNamePropertyName_ = "ApplicationName";
static final String clientUserPropertyName_ = "ClientUser";
static final String clientHostnamePropertyName_ = "ClientHostname";
static final String clientAccountingPropertyName_ = "ClientAccounting";
static final String clientProgramIDPropertyName_ = "ClientProgramID"; //@pda
//@pda 550 client info values
private String applicationName_ = ""; //@pdc so can be added to Properties object in getClientInfo()
private String clientUser_ = ""; //@pdc
private String clientHostname_ = ""; //@pdc
private String clientAccounting_ = ""; //@pdc
private String clientProgramID_ = ""; //@pdc
private String ignoreWarnings_ = ""; /*@Q1A*/
private int concurrentAccessResolution_ = AS400JDBCDataSource.CONCURRENTACCESS_NOT_SET; //@cc1
private boolean useBlockUpdate_ = false; //@A2A
private int maximumBlockedInputRows_ = 32000; //@A6A
protected final static int QUERY_TIMEOUT_QQRYTIMLMT = 0;
protected final static int QUERY_TIMEOUT_CANCEL = 1;
private int queryTimeoutMechanism_ = QUERY_TIMEOUT_QQRYTIMLMT;
// @K3 determine variable field compression settings
boolean variableFieldCompressionPropertyEvaluated_ = false;
boolean useVariableFieldCompression_ = false;
boolean useVariableFieldInsertCompression_ = false;
// what should truncated query parameters be replaced with
// null means that truncated query parameter should not be replaced
String queryReplaceTruncatedParameter_ = null ;
private static final int CHARACTER_TRUNCATION_DEFAULT = 0;
private static final int CHARACTER_TRUNCATION_WARNING = 1;
private static final int CHARACTER_TRUNCATION_NONE = 2;
private int characterTruncation_ = CHARACTER_TRUNCATION_DEFAULT;
private static final int NUMERIC_RANGE_ERROR_DEFAULT = 0;
private static final int NUMERIC_RANGE_ERROR_WARNING = 1;
private static final int NUMERIC_RANGE_ERROR_NONE = 2;
private int numericRangeError_ = NUMERIC_RANGE_ERROR_DEFAULT;
String lastServerSQLState_; // Remember the state associated with the connection @Q4A
private String alternateServer_ = null ; // Alternate server returned from the host
String portNumberString = "*N";
int portNumber = 0;
private String systemName_;
/**
Static initializer. Initializes the reply data streams
that we expect to receive.
**/
static
{
// The database server will only return 1 type of reply.
//@P0D AS400Server.addReplyStream (new DBReplyRequestedDS (),
AS400Server.addReplyStream(DBDSPool.getDBReplyRequestedDS(), //@P0A
AS400.DATABASE);
}
// The default constructor reserved for use within the package.
AS400JDBCConnectionImpl () //@A3A
{
}
// @A3D Deleted constructor:
// AS400JDBCConnection (JDDataSourceURL dataSourceUrl, JDProperties properties)
// throws SQLException
// @E8A
/**
Cancels a statement within this connection.
@param id The ID of the statement.
@exception SQLException If the statement cannot be executed.
**/
public void cancel(int id)
throws SQLException
{
// Lock out all other operations for this connection.
synchronized(cancelLock_)
{
if (TESTING_THREAD_SAFETY) return; // in certain testing modes, don't contact the system
cancelling_ = true;
AS400JDBCConnectionImpl cancelConnection = null;
try
{
// If the server job identifier was returned, and the system is at a
// functional level 5 or greater, then use the job identifier to issue
// the cancel from another connection. Otherwise, do nothing.
if ((serverJobIdentifier_ != null) && (serverFunctionalLevel_ >= 5))
{
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Cancelling statement " + id);
// Create another connection to issue the cancel.
cancelConnection = new AS400JDBCConnectionImpl();
//AS400 system = new AS400(as400PublicClassObj_);
//cancelConnection.setSystem(system);
cancelConnection.setProperties(dataSourceUrl_, properties_, as400_,
true, /* new server */
false /* skip signon request */ );
// Send the cancel request.
DBSQLRequestDS request = null;
DBReplyRequestedDS cancelReply = null;
try
{
request = DBDSPool.getDBSQLRequestDS(DBSQLRequestDS.FUNCTIONID_CANCEL, id_,
DBBaseRequestDS.ORS_BITMAP_RETURN_DATA, 0);
request.setJobIdentifier(serverJobIdentifier_, converter_);
cancelReply = cancelConnection.sendAndReceive (request);
int errorClass = cancelReply.getErrorClass();
int returnCode = cancelReply.getReturnCode();
if (errorClass != 0)
JDError.throwSQLException(this, this, id_, errorClass, returnCode);
}
catch (DBDataStreamException e)
{
JDError.throwSQLException (this, JDError.EXC_INTERNAL, e);
}
finally
{
if (request != null) {
request.returnToPool(); request = null;
}
if (cancelReply != null) {
cancelReply.returnToPool(); cancelReply = null;
}
}
}
else
{
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Cancel of statement " + id + " requested, but is not supported by system");
}
}
finally
{
// always need to close the connection
if (cancelConnection != null) {
try { cancelConnection.close(); }
catch (Throwable e) {} // ignore any exceptions
}
// Let others back in.
cancelling_ = false;
cancelLock_.notifyAll();
}
}
}
/**
Checks that the specified SQL statement can be executed.
This decision is based on the access specified by the caller
and the read only mode.
@param sqlStatement The SQL statement.
@exception SQLException If the statement cannot be executed.
**/
public void checkAccess (JDSQLStatement sqlStatement)
throws SQLException
{
String access = properties_.getString (JDProperties.ACCESS);
// If we only have read only access, then anything other
// than a SELECT can not be executed.
if ((access.equalsIgnoreCase (JDProperties.ACCESS_READ_ONLY))
&& (! sqlStatement.isSelect ())) {
// Do not throw exception if we have a metadata call @K5A
if (! sqlStatement.getIsMetaDataCall()) {
JDError.throwSQLException (this, JDError.EXC_ACCESS_MISMATCH);
}
}
// If we have read call access, then anything other than
// a SELECT or CALL can not be executed.
if (((readOnly_)
|| ((access.equalsIgnoreCase (JDProperties.ACCESS_READ_CALL))))
&& (! sqlStatement.isSelect())
&& (! sqlStatement.isProcedureCall()))
JDError.throwSQLException (this, JDError.EXC_ACCESS_MISMATCH);
}
// @E8A
/**
Checks to see if we are cancelling a statement. If so, wait until the
cancel is done. If not, go ahead.
**/
public void checkCancel()
{
synchronized(cancelLock_)
{
while (cancelling_)
{
try
{
cancelLock_.wait();
}
catch (InterruptedException e)
{
// Ignore.
}
}
}
}
//@F3A
/**
Checks if what the user passed in for holdability is valid.
**/
public boolean checkHoldabilityConstants (int holdability)
{
if ((holdability == AS400JDBCResultSet.HOLD_CURSORS_OVER_COMMIT) ||
(holdability == AS400JDBCResultSet.CLOSE_CURSORS_AT_COMMIT) ||
(holdability == AS400JDBCResultSet.HOLDABILITY_NOT_SPECIFIED))
{
return true;
}
return false;
}
/**
Checks that the connection is open. Public methods
that require an open connection should call this first.
@exception SQLException If the connection is not open.
**/
public void checkOpen ()
throws SQLException
{
if (TESTING_THREAD_SAFETY) return; // in certain testing modes, don't contact IBM i system
if ((server_ == null))
JDError.throwSQLException (this, JDError.EXC_CONNECTION_NONE);
if (aborted_) {
if (Thread.currentThread() != abortingThread_) {
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Returning closed since aborted_");
JDError.throwSQLException (this, JDError.EXC_CONNECTION_NONE);
}
}
}
/**
Clears all warnings that have been reported for the connection.
After this call, getWarnings() returns null until a new warning
is reported for the connection.
@exception SQLException If an error occurs.
**/
public void clearWarnings ()
throws SQLException
{
sqlWarning_ = null;
}
/**
Releases the connection's resources immediately instead of waiting
for them to be automatically released. This rolls back any active
transactions, closes all statements that are running in the context
of the connection, and disconnects from the IBM i system.
@exception SQLException If an error occurs.
**/
//
// Implementation notes:
//
// 1. We do not have to worry about thread synchronization here,
// since the AS400Server object handles it.
//
// 2. 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
{
// @D4A
// Avoid recursion. When we close associated statements, they try
// to close this connection.
if (closing_) return;
closing_ = true;
// 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;
// partial close (moved rollback and closing of all the statements). @E1
pseudoClose();
// Disconnect from the system.
if (server_ != null)
{
// @B3 It turns out that we were closing the connection,
// @B3 then the AS400Server object was in its disconnectServer()
// @B3 method. Since the AS400Server object needs to do other
// @B3 cleanup, we still need to call it.
// @B3D try {
// @B3D DBSQLEndCommDS request = new DBSQLEndCommDS (
// @B3D DBSQLEndCommDS.FUNCTIONID_END_COMMUNICATION,
// @B3D id_, 0, 0);
// @B3D send (request);
// @B3D }
// @B3D catch (Exception e) {
// @B3D JDError.throwSQLException (this, JDError.EXC_INTERNAL, e);
// @B3D }
as400_.disconnectServer (server_);
server_ = null;
}
if (JDTrace.isTraceOn())
JDTrace.logClose (this);
}
/*
* handle the processing of the abort. @D7A
*/
public void handleAbort() {
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "handleAbort() called");
abortingThread_ = Thread.currentThread();
// Mark all statements as cancelled
Vector statements = (Vector)statements_.clone();
Enumeration list = statements.elements();
while (list.hasMoreElements())
{
AS400JDBCStatement statement = (AS400JDBCStatement)list.nextElement();
statement.cancelled_ = true;
}
// Send a cancel to the server.
try {
cancel(0);
} catch (SQLException e ) {
// Ingore any errors
}
closing_ = true;
// partial close (moved rollback and closing of all the statements).
try {
pseudoClose();
} catch (SQLException e) {
// Just ignore and continue
}
// Disconnect from the system.
if (server_ != null)
{
as400_.disconnectServer (server_);
server_ = null;
}
}
// @E4C
/**
Commits all changes made since the previous commit or
rollback and releases any database locks currently held by
the connection. This has no effect when the connection
is in auto-commit mode.
This method can not be called when the connection is part
of a distributed transaction. See
AS400JDBCXAResource for more information.
@exception SQLException If the connection is not open
or an error occurs.
**/
public void commit ()
throws SQLException
{
checkOpen ();
if (!transactionManager_.isLocalTransaction()) // @E4A
JDError.throwSQLException (this, JDError.EXC_TXN_STATE_INVALID); // @E4A
// Note: CPS 72CSHT support
if (transactionManager_.getAutoCommit () && properties_.getBoolean(JDProperties.AUTOCOMMIT_EXCEPTION)) //@CE1
JDError.throwSQLException (this, JDError.EXC_FUNCTION_SEQUENCE); //@CE1
// Note: Intuitively, it seems like if we are in
// auto-commit mode, that we should not need to
// do anything for an explicit commit. However,
// somewhere along the line, the system gets
// confused, so we go ahead an send the commit
// anyway.
transactionManager_.commit ();
// @F3 If cursor hold property is false, then mark the cursors closed. Don't worry here
// @F3 about whether their statement level holdability is different; we will check that
// @F3 within AS400JDBCStatement.markCursorsClosed().
// @F3 If the user has changed any statement's holdability, then we need to go through
// @F3 the enumeration to see if there are ones where we may need to close our cursors
// @F3 or internal result sets.
// @F3 Passing true to markCursorsClosed means we called this method from rollback().
if (transactionManager_.getHoldIndicator() == JDTransactionManager.CURSOR_HOLD_FALSE // @B4A
|| (checkStatementHoldability_ && getVRM() >= JDUtilities.vrm520)) // @F3A
markCursorsClosed(false); // @B4A
if(!getAutoCommit() && properties_.getBoolean(JDProperties.HOLD_STATEMENTS )) //@KBL if auto commit is off, check to see if any statements have been partially closed //@PDA additional HOLD_STATEMENTS check
markStatementsClosed(); //@KBL
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Transaction commit");
}
//@F3A
/**
Sets a flag for whether the user has changed the holdability for any of the statements that
came from this connection. As of JDBC 3.0, the user can specify a statement-level holdability
that is different from the statement-level holdability. Rather than always going through all
of the statements to see if any of their holidabilities is different, we will mark this flag if
the user changes any of the statement holdabilities.
**/
public void setCheckStatementHoldability(boolean check)
{
checkStatementHoldability_ = check;
}
/**
Corrects the result set type based on the result set concurrency
and posts a warning.
@param resultSetType The result set type.
@param resultSetConcurrency The result set concurrency.
@return The correct result set type.
**/
public int correctResultSetType (int resultSetType,
int resultSetConcurrency)
throws SQLException // @EGA
{
int newResultSetType = (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE)
? ResultSet.TYPE_SCROLL_SENSITIVE : ResultSet.TYPE_SCROLL_INSENSITIVE;
postWarning (JDError.getSQLWarning (JDError.WARN_OPTION_VALUE_CHANGED));
return newResultSetType;
}
/**
Creates a Statement object for executing SQL statements without
parameters. If the same SQL statement is executed many times, it
is more efficient to use prepareStatement().
Result sets created using the statement will be type
ResultSet.TYPE_FORWARD_ONLY and concurrency
ResultSet.CONCUR_READ_ONLY.
@return The statement object.
@exception SQLException If the connection is not open,
the maximum number of statements
for this connection has been reached, or an
error occurs.
**/
public Statement createStatement ()
throws SQLException
{
return createStatement (this, ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, getInternalHoldability()); //@G4C
}
public Statement createStatement (AS400JDBCConnection con)
throws SQLException
{
return createStatement (con,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, getInternalHoldability()); //@G4C
}
// JDBC 2.0
/**
Creates a Statement object for executing SQL statements without
parameters. If the same SQL statement is executed many times, it
is more efficient to use prepareStatement().
@param resultSetType The result set type. Valid values are:
- ResultSet.TYPE_FORWARD_ONLY
- ResultSet.TYPE_SCROLL_INSENSITIVE
- ResultSet.TYPE_SCROLL_SENSITIVE
@param resultSetConcurrency The result set concurrency. Valid values are:
- ResultSet.CONCUR_READ_ONLY
- ResultSet.CONCUR_UPDATABLE
@return The statement object.
@exception SQLException If the connection is not open,
the maximum number of statements
for this connection has been reached, the
result type or currency is not supported,
or an error occurs.
**/
public Statement createStatement (int resultSetType,
int resultSetConcurrency)
throws SQLException
{
return createStatement (this, resultSetType, //@G4A
resultSetConcurrency, getInternalHoldability()); //@G4A
//@G4M Moved code to createStatement (int, int, int)
}
public Statement createStatement (AS400JDBCConnection con, int resultSetType,
int resultSetConcurrency)
throws SQLException
{
return createStatement (con, resultSetType, //@G4A
resultSetConcurrency, getInternalHoldability()); //@G4A
//@G4M Moved code to createStatement (int, int, int)
}
//@G4A JDBC 3.0
/**
Creates a Statement object for executing SQL statements without
parameters. If the same SQL statement is executed many times, it
is more efficient to use prepareStatement().
Full functionality of this method requires support in OS/400 V5R2
or IBM i. If connecting to OS/400 V5R1 or earlier, the value for
resultSetHoldability will be ignored.
@param resultSetType The result set type. Valid values are:
- ResultSet.TYPE_FORWARD_ONLY
- ResultSet.TYPE_SCROLL_INSENSITIVE
- ResultSet.TYPE_SCROLL_SENSITIVE
@param resultSetConcurrency The result set concurrency. Valid values are:
- ResultSet.CONCUR_READ_ONLY
- ResultSet.CONCUR_UPDATABLE
@param resultSetHoldability The result set holdability. Valid values are:
- ResultSet.HOLD_CURSORS_OVER_COMMIT
- ResultSet.CLOSE_CURSORS_AT_COMMIT
@return The statement object.
@exception SQLException If the connection is not open,
the maximum number of statements
for this connection has been reached, the
result type, currency, or holdability is not supported,
or an error occurs.
@since Modification 5
**/
public Statement createStatement (int resultSetType,
int resultSetConcurrency,
int resultSetHoldability)
throws SQLException
{
return createStatement(this, resultSetType, resultSetConcurrency, resultSetHoldability);
}
public Statement createStatement (AS400JDBCConnection con,
int resultSetType,
int resultSetConcurrency,
int resultSetHoldability)
throws SQLException
{
// Validation.
checkOpen ();
if (! metaData_.supportsResultSetConcurrency (resultSetType, resultSetConcurrency))
resultSetType = correctResultSetType (resultSetType, resultSetConcurrency);
if (!checkHoldabilityConstants (resultSetHoldability)) //@F3A
JDError.throwSQLException (this, JDError.EXC_ATTRIBUTE_VALUE_INVALID); //@F3A
// Create the statement.
int statementId = getUnusedId (resultSetType); // @B1C
AS400JDBCStatement statement = new AS400JDBCStatement (con,
statementId, transactionManager_, packageManager_,
properties_.getString (JDProperties.BLOCK_CRITERIA),
properties_.getInt (JDProperties.BLOCK_SIZE),
properties_.getBoolean (JDProperties.PREFETCH),
properties_.getString (JDProperties.PACKAGE_CRITERIA), // @A2A
resultSetType, resultSetConcurrency, resultSetHoldability, //@G4A
AS400JDBCStatement.GENERATED_KEYS_NOT_SPECIFIED); //@G4A
statements_.addElement(statement); // @DAC
statementCount_++; //@K1A
if(thousandStatements_ == false && statementCount_ == 1000) //@K1A
{ //@K1A
thousandStatements_ = true; //@K1A
//post warning //@K1A
postWarning(JDError.getSQLWarning(JDError.WARN_1000_OPEN_STATEMENTS)); //@K1A
} //@K1A
if (JDTrace.isTraceOn()) //@F4A
{ //@F4A
int size = statements_.size(); //@F4A
if (size % 256 == 0) //@F4A
{ //@F4A
JDTrace.logInformation (this, "Warning: Open handle count now: " + size); //@F4A
} //@F4A
} //@F4A
return statement;
}
/**
Outputs debug information for a request. This should only be used
for debugging the JDBC driver and is not intended for production code.
@param request The request.
**/
public void debug (DBBaseRequestDS request)
{
if (DEBUG_COMM_TRACE_ >= 1)
System.out.println ("Server request: "
+ Integer.toString (request.getServerID(), 16).toUpperCase()
+ ":" + Integer.toString (request.getReqRepID(), 16).toUpperCase()
+ ".");
if (DEBUG_COMM_TRACE_ >= 2)
request.dump (System.out);
}
/**
Outputs debug information for a reply. This should only be used
for debugging the JDBC driver and is not intended for production code.
@param reply The reply.
**/
public void debug (DBReplyRequestedDS reply)
{
if (DEBUG_COMM_TRACE_ >= 1)
System.out.println ("Server reply: "
+ Integer.toString (reply.getServerID(), 16).toUpperCase()
+ ":" + Integer.toString (reply.getReturnDataFunctionId(), 16).toUpperCase()
+ ".");
if (DEBUG_COMM_TRACE_ >= 2)
reply.dump (System.out);
if (DEBUG_COMM_TRACE_ >= 1)
{
int returnCode = ((DBReplyRequestedDS) reply).getReturnCode();
int errorClass = ((DBReplyRequestedDS) reply).getErrorClass();
if ((errorClass != 0) || (returnCode != 0))
System.out.println ("Server error = " + errorClass + ":"
+ returnCode + ".");
}
}
/**
Closes the connection if not explicitly closed by the caller.
@exception Throwable If an error occurs.
**/
public void finalize ()
throws Throwable
{
if (! isClosed ()) {
JDTrace.logInformation (this, "WARNING: Finalizer thread closing connection object.");
close ();
}
super.finalize ();
}
/**
Returns the AS400 object for this connection.
@return The AS400 object.
**/
public AS400Impl getAS400 ()
throws SQLException // @EGA
{
return as400_;
}
/**
Returns the auto-commit state.
@return true if the connection is in auto-commit mode;
false otherwise.
@exception SQLException If the connection is not open.
**/
public boolean getAutoCommit ()
throws SQLException
{
checkOpen ();
return transactionManager_.getAutoCommit ();
}
/**
Returns the catalog name.
@return The catalog name.
@exception SQLException If the connection is not open.
**/
public String getCatalog ()
throws SQLException
{
checkOpen ();
return catalog_;
}
//@cc1
/**
* This method returns the concurrent access resolution setting.
* This method has no effect on IBM i V6R1 or earlier.
* The possible values for this property are {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_NOT_SET},
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_USE_CURRENTLY_COMMITTED},
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_WAIT_FOR_OUTCOME} and
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_SKIP_LOCKS},
* with the property defaulting to {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_NOT_SET}.
* Setting this property to default exhibits the default behavior on the servers
* i.e., the semantic applied for read
* transactions to avoid locks will be determined by the server.
*
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_USE_CURRENTLY_COMMITTED} specifies that driver will flow USE CURRENTLY COMMITTED
* to server. Whether CURRENTLY COMMITTED will actually be in effect is
* ultimately determined by server.
*
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_WAIT_FOR_OUTCOME} specifies that driver will flow WAIT FOR OUTCOME
* to server. This will disable the CURRENTLY COMMITTED behavior at the server,
* if enabled, and the server will wait for the commit or rollback of data in the process of
* being updated.
*
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_SKIP_LOCKS} specifies that driver will flow SKIP LOCKS
* to server. This directs the database manager to skip records in the case of record lock conflicts.
*
* @return The concurrent access resolution setting. Possible return valuse:
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_NOT_SET},
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_USE_CURRENTLY_COMMITTED},
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_WAIT_FOR_OUTCOME}, or
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_SKIP_LOCKS}
*/
public int getConcurrentAccessResolution ()
{
return concurrentAccessResolution_;
}
/**
Returns the converter for this connection.
@return The converter.
**/
//@P0D ConverterImplRemote ()
//@P0D throws SQLException // @EGA
//@P0D {
//@P0D return converter_;
//@P0D }
/**
Returns the converter for the specified CCSID, unless
it is 0 or 65535 (i.e. probably set for a non-text field), in
which case it returns the converter for this connection.
This is useful for code that handles all types of fields
in a generic manner.
@param ccsid The CCSID.
@return The converter.
@exception SQLException If the CCSID is not valid.
**/
public ConvTable getConverter (int ccsid) //@P0C
throws SQLException
{
try
{
if (ccsid == 0 || ccsid == 1 || ccsid == 65535 || ccsid == -1) return converter_; //@P0C
//@P0D switch (ccsid)
//@P0D { // @E3A
//@P0D case 65535: //@ELC // @E3A
//@P0D case 0: // @E3A
//@P0D case 1: // @E3A
//@P0D return converter_; // @E3A
//@P0D case UNICODE_CCSID_: // @E3A
//@P0D if (unicodeConverter_ == null) // @E3A
//@P0D unicodeConverter_ = ConverterImplRemote.getConverter(13488, as400_); // @E3A
//@P0D return unicodeConverter_; // @E3A
//@P0D default: // @E3A
//@P0D return ConverterImplRemote.getConverter (ccsid, as400_); // @E3C
//@P0D } // @E3A
return ConvTable.getTable(ccsid, null); //@P0A
}
catch (UnsupportedEncodingException e)
{
JDError.throwSQLException (this, JDError.EXC_INTERNAL, e);
return null;
}
}
// @ECA
/**
Returns the style of data compression.
@return The style of data compression. Possible values are DATA_COMPRESSION_NONE_,
DATA_COMPRESSION_OLD_, and DATA_COMPRESSION_RLE_.
**/
public int getDataCompression() // @ECA
{ // @ECA
return dataCompression_; // @ECA
} // @ECA
/**
Returns the default SQL schema.
@return The default SQL schema, or QGPL if none was
specified.
**/
public String getDefaultSchema ()
throws SQLException // @EGA
{
return((defaultSchema_ == null) ? "QGPL" : defaultSchema_);
}
//@DELIMa
/**
Returns the default SQL schema.
@param returnRawValue Indicates what to return if default SQL schema has not been set. If true, return raw value; if false, then return QGPL rather than null.
@return The default SQL schema. If returnRawValue==false and no default SQL schema was specified, then return QGPL rather than null.
**/
public String getDefaultSchema (boolean returnRawValue)
throws SQLException
{
return((returnRawValue || defaultSchema_ != null) ? defaultSchema_ : "QGPL");
}
//@G4A JDBC 3.0
/**
Returns the holdability of ResultSets created from this connection.
@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 specified using the method setHoldability(int)
if this method was called.
- 2. The value of the
cursor hold
driver property.
Full functionality of #1 requires support in OS/400
V5R2 or IBM i. If connecting to OS/400 V5R1 or earlier,
the value specified on this method will be ignored and the default holdability
will be the value of #2.
@exception SQLException If the connection is not open.
@since Modification 5
**/
public int getHoldability ()
throws SQLException
{
checkOpen ();
// If holdability has been set, return its value.
if ((holdability_ == AS400JDBCResultSet.HOLD_CURSORS_OVER_COMMIT) ||
(holdability_ == AS400JDBCResultSet.CLOSE_CURSORS_AT_COMMIT))
{
return holdability_;
}
// Else, holdability either equals AS400JDBCResultSet.HOLDABILITY_NOT_SPECIFIED
// or has an incorrect value (shouldn't be able to happen).
// Return the holdability determined by seeing what the cursor hold driver property
// was set to. Default is HOLD_CURSORS_AT_COMMIT.
else
{
if (transactionManager_.getHoldIndicator() == JDTransactionManager.CURSOR_HOLD_TRUE)
return AS400JDBCResultSet.HOLD_CURSORS_OVER_COMMIT;
else if (transactionManager_.getHoldIndicator() == JDTransactionManager.CURSOR_HOLD_FALSE)
return AS400JDBCResultSet.CLOSE_CURSORS_AT_COMMIT;
// Hold indicator will be set to -1 if the user gave us a bad number in setHoldIndicator().
// We threw an exception there, so throw another exception here, then return default
// value for driver.
else
{
JDError.throwSQLException (this, JDError.EXC_INTERNAL);
return AS400JDBCResultSet.HOLD_CURSORS_OVER_COMMIT;
}
}
}
//@DELIMa
/**
Returns the ID of the connection.
@return The connection ID.
**/
public int getID()
{
return id_;
}
//@G4A JDBC 3.0
/**
Returns the holdability of ResultSets created from this connection.
Use this method internally to return the value specified if the user has called
setHoldability(int), or HOLDABILITY_NOT_SPECIFIED if that
method hasn't been called, meaning to use the old behavior and not the new code
point for cursor holdability.
@return The cursor holdability. Valid values are
AS400JDBCResultSet.HOLD_CURSORS_OVER_COMMIT,
AS400JDBCResultSet.CLOSE_CURSORS_AT_COMMIT,
and AS400JDBCResultSet.HOLDABILITY_NOT_SPECIFIED.
@since Modification 5
**/
public int getInternalHoldability ()
{
return holdability_;
}
// @E2D /**
// @E2D Returns the graphic converter for this connection.
// @E2D
// @E2D @return The graphic converter.
// @E2D
// @E2D @exception SQLException If no graphic converter was loaded.
// @E2D **/
// @E2D //
// @E2D // Implementation note:
// @E2D //
// @E2D // * Graphic data is pure double-byte, so we will need a
// @E2D // different converter for that. If there is no associated
// @E2D // double-byte CCSID, or the converter can not be loaded,
// @E2D // then we should throw an exception. We wait to load this,
// @E2D // since the majority of callers do not need this converter.
// @E2D //
// @E2D ConverterImplRemote getGraphicConverter ()
// @E2D throws SQLException
// @E2D {
// @E2D // If the graphic converter has not yet been loaded,
// @E2D // then do so.
// @E2D if (graphicConverterLoaded_ == false) {
// @E2D int serverGraphicCCSID = ExecutionEnvironment.getAssociatedDbcsCcsid (converter_.getCcsid ());
// @E2D if (serverGraphicCCSID != -1) {
// @E2D try {
// @E2D graphicConverter_ = ConverterImplRemote.getConverter (serverGraphicCCSID, as400_);
// @E2D }
// @E2D catch (UnsupportedEncodingException e) {
// @E2D graphicConverter_ = null;
// @E2D }
// @E2D }
// @E2D
// @E2D if (JDTrace.isTraceOn ()) {
// @E2D if (graphicConverter_ != null)
// @E2D JDTrace.logInformation (this, "Server graphic CCSID = " + serverGraphicCCSID);
// @E2D else
// @E2D JDTrace.logInformation (this, "No graphic CCSID was loaded");
// @E2D }
// @E2D }
// @E2D
// @E2D // Return the graphic converter, or throw an exception.
// @E2D if (graphicConverter_ == null)
// @E2D JDError.throwSQLException (this, JDError.EXC_CCSID_INVALID);
// @E2D return graphicConverter_;
// @E2D }
/**
Returns the DatabaseMetaData object that describes the
connection's tables, supported SQL grammar, stored procedures,
capabilities and more.
@return The metadata object.
@exception SQLException If an error occurs.
**/
public DatabaseMetaData getMetaData ()
throws SQLException
{
// We allow a user to get this object even if the
// connection is closed.
return metaData_;
}
/**
Returns the connection properties.
@return The connection properties.
* @throws SQLException If a database error occurs.
**/
public JDProperties getProperties ()
throws SQLException // @EGA
{
return properties_;
}
// @E8A
/**
Returns the job identifier of the host server job corresponding to this connection.
Every JDBC connection is associated with a host server job on the IBM i system. The
format is:
- 10 character job name
- 10 character user name
- 6 character job number
Note: Since this method is not defined in the JDBC Connection interface,
you typically need to cast a Connection object to AS400JDBCConnection in order
to call this method:
String serverJobIdentifier = ((AS400JDBCConnection)connection).getServerJobIdentifier();
@return The server job identifier, or null if not known.
**/
public String getServerJobIdentifier() // @E8A
{ // @E8A
return serverJobIdentifier_; // @E8A
} // @E8A
public int getServerFunctionalLevel() // @EEA
{ // @EEA
return serverFunctionalLevel_; // @EEA
} // @EEA
// @EHA
/**
Returns the system object which is managing the connection to the system.
Note: Since this method is not defined in the JDBC Connection interface,
you typically need to cast a Connection object to AS400JDBCConnection in order
to call this method:
AS400 system = ((AS400JDBCConnection)connection).getSystem();
@return The system.
**/
// Implementation note: Don't use this object internally because we could be running in a proxy environment
// The purpose of this method is to simply hold the full AS400 object so it can be retrieved from the Connection
public AS400 getSystem() // @EHA
{ // @EHA
return as400PublicClassObj_; // @EHA
} // @EHA
/**
Returns the transaction isolation level.
@return The transaction isolation level. Possible
values are:
- TRANSACTION_NONE
- TRANSACTION_READ_UNCOMMITTED
- TRANSACTION_READ_COMMITTED
- TRANSACTION_REPEATABLE_READ
@exception SQLException If the connection is not open.
**/
public int getTransactionIsolation ()
throws SQLException
{
checkOpen ();
return transactionManager_.getIsolation ();
}
public JDTransactionManager getTransactionManager() // @E4A
{ // @E4A
return transactionManager_; // @E4A
} // @E4A
// JDBC 2.0
/**
Returns the type map.
This driver does not support the type map.
@return The type map.
@exception SQLException This exception is always thrown.
**/
public Map getTypeMap ()
throws SQLException
{
JDError.throwSQLException (this, JDError.EXC_FUNCTION_NOT_SUPPORTED);
return null;
}
// @B1C
/**
Returns the next unused id.
@param resultSetType The result set type. This is
relevant only when the connection
is being used for DRDA.
@return The next unused id.
**/
//
// Implementation note: This method needs to be synchronized
// so that the same id does not get assigned twice.
//
public int getUnusedId (int resultSetType) //@P0C
throws SQLException
{
synchronized(assigned_) //@P1A
{
// Note: We will always assume id 0 is being used,
// since that represents the connection itself.
// If this connection is being used for DRDA, then we
// must use statement ids of 1-128 for non-scrollable
// cursors and 129-255 for scrollable cursors.
if (drda_)
{
if (resultSetType == ResultSet.TYPE_FORWARD_ONLY)
{
for (int i = 1; i < DRDA_SCROLLABLE_CUTOFF_; ++i)
{
//@P0Dif (assigned_.get(i) == false)
//@P0D{ // @DAC
//@P0D assigned_.set(i); // @DAC
//@P0D return i;
//@P0D}
if (!assigned_[i]) //@P0A
{
assigned_[i] = true; //@P0A
return i; //@P0A
}
}
}
else
{
for (int i = DRDA_SCROLLABLE_CUTOFF_; i < DRDA_SCROLLABLE_MAX_; ++i)
{ // @DAC
//@P0Dif (assigned_.get(i) == false)
//@P0D{ // @DAC
//@P0D assigned_.set(i); // @DAC
//@P0D return i;
//@P0D}
if (!assigned_[i]) //@P0A
{
assigned_[i] = true; //@P0A
return i; //@P0A
}
}
}
}
// If this connection is NOT being used for DRDA, then
// we can use any statement id.
else
{
for (int i = 1; i < MAX_STATEMENTS_; ++i)
{
//@P0Dif (assigned_.get(i) == false)
//@P0D{ // @DAC
//@P0D assigned_.set(i); // @DAC
//@P0D return i;
//@P0D}
if (!assigned_[i]) //@P0A
{
assigned_[i] = true; //@P0A
return i; //@P0A
}
}
}
// All ids are being used.
JDError.throwSQLException (this, JDError.EXC_MAX_STATEMENTS_EXCEEDED);
return -1;
}
}
public // @j31a new method -- Must the user have "for update" on their
// SQL statement to guarantee an updatable cursor? The answer is
// no for v5r2 and v5r1 systems with a PTF. For V5R1 systems
// without the PTF, v4r5, and earlier, the answer is yes.
boolean getMustSpecifyForUpdate ()
{
return mustSpecifyForUpdate_;
}
/**
Returns the URL for the connection's database.
@return The URL for the database.
**/
public String getURL ()
throws SQLException // @EGA
{
return dataSourceUrl_.toString ();
}
/**
Returns the user name as currently signed on to the system.
@return The user name.
**/
public String getUserName ()
throws SQLException // @EGA
{
if (TESTING_THREAD_SAFETY) // in certain testing modes, don't contact IBM i system
{
String userName = as400_.getUserId ();
if (userName == null || userName.length() == 0) {
userName = as400PublicClassObj_.getUserId();
}
return userName;
}
return as400_.getUserId ();
}
public int getVRM() // @D0A
throws SQLException // @EGA
{ // @D0A
return vrm_; // @D0A
} // @D0A
/**
Returns the first warning reported for the connection.
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_;
}
/**
Indicates if the specified cursor name is already used
in the connection.
@return true if the cursor name is already used;
false otherwise.
**/
public boolean isCursorNameUsed (String cursorName)
throws SQLException // @EGA
{
// Make a clone of the vector, since it will be modified as each statement @FAA
Vector statements = (Vector)statements_.clone();
Enumeration list = statements.elements(); // @DAA
while (list.hasMoreElements())
{ // @DAC
try {
if (((AS400JDBCStatement)list.nextElement()).getCursorName().equalsIgnoreCase(cursorName)) // @DAC
return true;
} catch (Exception e) { /*@FAA */
// ignore any exceptions
if (JDTrace.isTraceOn()) {
JDTrace.logException(this, "isCursorNameUsed caught exception", e);
}
}
}
return false;
}
/**
Indicates if the connection is closed.
@return true if the connection is closed; false
otherwise.
@exception SQLException If an error occurs.
**/
public boolean isClosed ()
throws SQLException
{
if (aborted_ && (Thread.currentThread() != abortingThread_)) return true; /*@D7A*/
if (TESTING_THREAD_SAFETY) return false; // in certain testing modes, don't contact IBM i system
if (server_ == null) // @EFC
return true; // @EFA
if (!server_.isConnected())
{ // @EFA
server_ = null; // @EFA
return true; // @EFA
} // @EFA
else // @EFA
return false; // @EFA
}
/**
Indicates if the connection is in read-only mode.
@return true if the connection is in read-only mode;
false otherwise.
@exception SQLException If the connection is not open.
**/
public boolean isReadOnly ()
throws SQLException
{
checkOpen ();
return((readOnly_) || isReadOnlyAccordingToProperties()); // @CPMc
}
// Called by AS400JDBCPooledConnection.
public boolean isReadOnlyAccordingToProperties()
throws SQLException
{
checkOpen ();
return((properties_.getString (JDProperties.ACCESS).equalsIgnoreCase (JDProperties.ACCESS_READ_ONLY))
|| (properties_.getString (JDProperties.ACCESS).equalsIgnoreCase (JDProperties.ACCESS_READ_CALL)));
}
// @B4A
/**
Marks all of the cursors as closed.
@param isRollback True if we called this from rollback(), false if we called this from commit().
**/
public void markCursorsClosed(boolean isRollback) //@F3C //@XAC
throws SQLException //@F2A
{
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Testing to see if cursors should be held."); //@F3C
// Make a clone of the vector, since it will be modified as each statement
// closes itself. @FAA
Vector statements = (Vector)statements_.clone();
Enumeration list = statements.elements(); // @DAA
while (list.hasMoreElements()) // @DAC
{ //@KBL
AS400JDBCStatement statement = (AS400JDBCStatement)list.nextElement(); //@KBL
//@KBLD ((AS400JDBCStatement)list.nextElement()).markCursorClosed(isRollback); // @DAC @F3C
// If the statement is held open, all of the result sets have already been closed
// If we happen to get an exception, just ignore it. There exists a
// race condition where another thread could have closed the connected while
// we were looping through the statement elements. @F7A
try {
if(!statement.isHoldStatement()) //@KBL
statement.markCursorClosed(isRollback); //@KBL
} catch (SQLException ex) {
if (JDTrace.isTraceOn()) {
JDTrace.logException(this, "markCursorsClosed caught exception", ex);
}
}
} //@KBL
}
//@KBL
/*
If a statement associated with locators has been partially closed, finish closing the statement object.
A statement may become partially closed if the user closed the statement and set the "hold statements" connection
property to true when making the connection. Additionally, the statement must have been used to access a locator.
*/
public void markStatementsClosed()
{
if(!statements_.isEmpty())
{
// Make a clone of the vector, since it will be modified as each statement
// closes itself.
// @KBL Close any statements the user called close on that were associated with locators.
Vector statements = (Vector)statements_.clone();
Enumeration list = statements.elements();
while (list.hasMoreElements())
{
AS400JDBCStatement statement = (AS400JDBCStatement)list.nextElement();
try
{
if(statement.isHoldStatement())
{
statement.setAssociatedWithLocators(false);
statement.finishClosing();
}
}
catch (SQLException e)
{
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Closing statement after rollback failed: " + e.getMessage());
}
}
}
}
//@GKA
// Note: This method is used when the user supplies either the column indexes or names
// to the execute/executeUpdate/prepareStatement method.
/*
* Prepares and executes the statement needed to retrieve generated keys.
*/
public String makeGeneratedKeySelectStatement(String sql, int[] columnIndexes, String[] columnNames)
throws SQLException
{
if(columnIndexes != null)
{
//verify there is a column index in the specified array
if(columnIndexes.length == 0)
JDError.throwSQLException(JDError.EXC_ATTRIBUTE_VALUE_INVALID);
//Prepare a statement in order to retrieve the column names associated with the indexes specified in the array
//wrapper the statement with a select * from final table
// @B4C. Use NEW TABLE instead of FINAL TABLE. With FINAL TABLE, the query will fail if
// AFTER INSERT TRIGGERS are present. Since it is unlikely that AFTER INSERT triggers will
// change the autogenerated keys, NEW TABLE is used.
StringBuffer selectAll = new StringBuffer("SELECT * FROM NEW TABLE(");
selectAll.append(sql);
selectAll.append(")");
PreparedStatement genPrepStat = prepareStatement(selectAll.toString());
// retrieve the JDServerRow object associated with this statement. It contains the column name info.
JDServerRow results = ((AS400JDBCPreparedStatement)genPrepStat).getResultRow();
columnNames = new String[columnIndexes.length];
try{
for(int j=0; jResult sets created using the statement will be type
ResultSet.TYPE_FORWARD_ONLY and concurrency
ResultSet.CONCUR_READ_ONLY.
@param sql The SQL stored procedure call.
@return The callable statement object.
@exception SQLException If the connection is not open,
the maximum number of statements
for this connection has been reached, or an
error occurs.
**/
public CallableStatement prepareCall (String sql)
throws SQLException
{
return prepareCall (this, sql, ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, getInternalHoldability()); //@G4A
}
public CallableStatement prepareCall (AS400JDBCConnection con, String sql)
throws SQLException
{
return prepareCall (con, sql, ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, getInternalHoldability()); //@G4A
}
// JDBC 2.0
/**
Precompiles an SQL stored procedure call with optional input
and output parameters and stores it in a CallableStatement
object. This object can be used to efficiently call the SQL
stored procedure multiple times.
@param sql The SQL statement.
@param resultSetType The result set type. Valid values are:
- ResultSet.TYPE_FORWARD_ONLY
- ResultSet.TYPE_SCROLL_INSENSITIVE
- ResultSet.TYPE_SCROLL_SENSITIVE
@param resultSetConcurrency The result set concurrency. Valid values are:
- ResultSet.CONCUR_READ_ONLY
- ResultSet.CONCUR_UPDATABLE
@return The prepared statement object.
@exception SQLException If the connection is not open,
the maximum number of statements
for this connection has been reached, the
result type or currency is not valid,
or an error occurs.
**/
public CallableStatement prepareCall (String sql,
int resultSetType,
int resultSetConcurrency)
throws SQLException
{
return prepareCall(this, sql, resultSetType, resultSetConcurrency,
getInternalHoldability()); //@G4A
//@G4M Moved code below
}
public CallableStatement prepareCall(AS400JDBCConnection con, String sql,
int resultSetType, int resultSetConcurrency) throws SQLException {
return prepareCall(con, sql, resultSetType, resultSetConcurrency,
getInternalHoldability()); // @G4A
// @G4M Moved code below
}
//@G4A JDBC 3.0
/**
Precompiles an SQL stored procedure call with optional input
and output parameters and stores it in a CallableStatement
object. This object can be used to efficiently call the SQL
stored procedure multiple times.
Full functionality of this method requires support in OS/400 V5R2
or IBM i. If connecting to OS/400 V5R1 or earlier, the value for
resultSetHoldability will be ignored.
@param sql The SQL statement.
@param resultSetType The result set type. Valid values are:
- ResultSet.TYPE_FORWARD_ONLY
- ResultSet.TYPE_SCROLL_INSENSITIVE
- ResultSet.TYPE_SCROLL_SENSITIVE
@param resultSetConcurrency The result set concurrency. Valid values are:
- ResultSet.CONCUR_READ_ONLY
- ResultSet.CONCUR_UPDATABLE
@return The prepared statement object.
@param resultSetHoldability The result set holdability. Valid values are:
- ResultSet.HOLD_CURSORS_OVER_COMMIT
- ResultSet.CLOSE_CURSORS_AT_COMMIT
@exception SQLException If the connection is not open,
the maximum number of statements
for this connection has been reached, the
result type, currency, or holdability is not valid,
or an error occurs.
@since Modification 5
**/
public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return prepareCall(this, sql, resultSetType, resultSetConcurrency,
resultSetHoldability);
}
public CallableStatement prepareCall(AS400JDBCConnection con, String sql,
int resultSetType, int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
// Validation.
checkOpen ();
if (! metaData_.supportsResultSetConcurrency (resultSetType, resultSetConcurrency))
resultSetType = correctResultSetType (resultSetType, resultSetConcurrency);
if (!checkHoldabilityConstants(resultSetHoldability)) //@F3A
JDError.throwSQLException (this, JDError.EXC_ATTRIBUTE_VALUE_INVALID); //@F3A
// Create the statement.
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
properties_.getString (JDProperties.DECIMAL_SEPARATOR), true,
properties_.getString (JDProperties.PACKAGE_CRITERIA), this); // @A2A @G4A
int statementId = getUnusedId (resultSetType); // @B1C
AS400JDBCCallableStatement statement = new AS400JDBCCallableStatement (con,
statementId, transactionManager_, packageManager_,
properties_.getString (JDProperties.BLOCK_CRITERIA),
properties_.getInt (JDProperties.BLOCK_SIZE),
sqlStatement,
properties_.getString (JDProperties.PACKAGE_CRITERIA),
resultSetType, resultSetConcurrency, resultSetHoldability, //@G4A
AS400JDBCStatement.GENERATED_KEYS_NOT_SPECIFIED); //@G4A
statements_.addElement(statement); // @DAC
statementCount_++; //@K1A
if(thousandStatements_ == false && statementCount_ == 1000) //@K1A
{ //@K1A
thousandStatements_ = true; //@K1A
//post warning //@K1A
postWarning(JDError.getSQLWarning(JDError.WARN_1000_OPEN_STATEMENTS)); //@K1A
} //@K1A
if (JDTrace.isTraceOn()) //@F4A
{ //@F4A
int size = statements_.size(); //@F4A
if (size % 256 == 0) //@F4A
{ //@F4A
JDTrace.logInformation (this, "Warning: Open handle count now: " + size); //@F4A
} //@F4A
} //@F4A
return statement;
}
/**
Precompiles an SQL statement with optional input parameters
and stores it in a PreparedStatement object. This object can
be used to efficiently execute this SQL statement
multiple times.
Result sets created using the statement will be type
ResultSet.TYPE_FORWARD_ONLY and concurrency
ResultSet.CONCUR_READ_ONLY.
@param sql The SQL statement.
@return The prepared statement object.
@exception SQLException If the connection is not open,
the maximum number of statements
for this connection has been reached, or an
error occurs.
**/
public PreparedStatement prepareStatement (String sql)
throws SQLException {
return prepareStatement(this, sql);
}
public PreparedStatement prepareStatement (AS400JDBCConnection con, String sql)
throws SQLException
{
return prepareStatement (con, sql, ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY,
getInternalHoldability()); //@G4A
}
//@G4A
//JDBC 3.0
/**
Precompiles an SQL statement with optional input parameters
and stores it in a PreparedStatement object. This object can
be used to efficiently execute this SQL statement
multiple times.
This method requires OS/400 V5R2 or IBM i. If connecting to OS/400 V5R1 or earlier, an exception will be
thrown.
Result sets created using the statement will be type
ResultSet.TYPE_FORWARD_ONLY and concurrency
ResultSet.CONCUR_READ_ONLY.
@param sql The SQL statement.
@param autoGeneratedKeys Whether to return auto generated keys. Valid values are:
- Statement.RETURN_GENERATED_KEYS
- Statement.NO_GENERATED_KEYS
@return The prepared statement object.
@exception SQLException If the connection is not open,
the maximum number of statements
for this connection has been reached,
if connecting to OS/400 V5R1 or earlier,
an error occurs.
@since Modification 5
**/
public PreparedStatement prepareStatement (String sql, int autoGeneratedKeys)
throws SQLException
{
return prepareStatement(this, sql, autoGeneratedKeys);
}
public PreparedStatement prepareStatement (AS400JDBCConnection con, String sql, int autoGeneratedKeys)
throws SQLException
{
if (getVRM() < JDUtilities.vrm520) //@F5A
JDError.throwSQLException(this, JDError.EXC_FUNCTION_NOT_SUPPORTED); //@F5A
// Validation.
checkOpen ();
// Create the statement.
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
properties_.getString (JDProperties.DECIMAL_SEPARATOR), true,
properties_.getString (JDProperties.PACKAGE_CRITERIA), con); // @A2A @G4A
if(getVRM() >= JDUtilities.vrm610 && autoGeneratedKeys==Statement.RETURN_GENERATED_KEYS) //@GKA added new generated key support
{
// check if it is an insert statement.
// Note: this should be false if the statement was wrappered with a SELECT
// when prepareStatement(String sql, int[] columnIndex) or
// prepareStatement(String sql, String[] columnNames) was called.
if(sqlStatement.isInsert_)
{
//wrapper the statement
String selectStatement = makeGeneratedKeySelectStatement(sql);
sqlStatement = new JDSQLStatement (selectStatement, properties_.getString(JDProperties.DECIMAL_SEPARATOR), true,
properties_.getString(JDProperties.PACKAGE_CRITERIA), con);
wrappedInsert_ = true;
}
}
int statementId = getUnusedId (ResultSet.TYPE_FORWARD_ONLY); // @B1C
if(wrappedInsert_)
{
sqlStatement.setSelectFromInsert(true);
wrappedInsert_ = false;
}
AS400JDBCPreparedStatement statement = new AS400JDBCPreparedStatementImpl (con,
statementId, transactionManager_, packageManager_,
properties_.getString (JDProperties.BLOCK_CRITERIA),
properties_.getInt (JDProperties.BLOCK_SIZE),
properties_.getBoolean (JDProperties.PREFETCH),
sqlStatement, false,
properties_.getString (JDProperties.PACKAGE_CRITERIA),
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
getInternalHoldability(), autoGeneratedKeys); //@G4A
statements_.addElement(statement); // @DAC
statementCount_++; //@K1A
if(thousandStatements_ == false && statementCount_ == 1000) //@K1A
{ //@K1A
thousandStatements_ = true; //@K1A
//post warning //@K1A
postWarning(JDError.getSQLWarning(JDError.WARN_1000_OPEN_STATEMENTS)); //@K1A
} //@K1A
if (JDTrace.isTraceOn()) //@F4A
{ //@F4A
int size = statements_.size(); //@F4A
if (size % 256 == 0) //@F4A
{ //@F4A
JDTrace.logInformation (this, "Warning: Open handle count now: " + size); //@F4A
} //@F4A
} //@F4A
return statement;
}
// JDBC 2.0
/**
Precompiles an SQL statement with optional input parameters
and stores it in a PreparedStatement object. This object can
be used to efficiently execute this SQL statement
multiple times.
Result sets created using the statement will be holdability
ResultSet.CLOSE_CURSORS_AT_COMMIT.
@param sql The SQL statement.
@param resultSetType The result set type. Valid values are:
- ResultSet.TYPE_FORWARD_ONLY
- ResultSet.TYPE_SCROLL_INSENSITIVE
- ResultSet.TYPE_SCROLL_SENSITIVE
@param resultSetConcurrency The result set concurrency. Valid values are:
- ResultSet.CONCUR_READ_ONLY
- ResultSet.CONCUR_UPDATABLE
@return The prepared statement object.
@exception SQLException If the connection is not open,
the maximum number of statements
for this connection has been reached, the
result type or currency is not valid,
or an error occurs.
**/
public PreparedStatement prepareStatement (String sql,
int resultSetType,
int resultSetConcurrency)
throws SQLException
{
return prepareStatement (this, sql, resultSetType, //@G4A
resultSetConcurrency, getInternalHoldability()); //@G4A
//@G4M Moved code to next method.
}
public PreparedStatement prepareStatement(AS400JDBCConnection con,
String sql, int resultSetType, int resultSetConcurrency)
throws SQLException {
return prepareStatement(con, sql, resultSetType, // @G4A
resultSetConcurrency, getInternalHoldability()); // @G4A
}
//@G4A
// JDBC 3.0
/**
Precompiles an SQL statement with optional input parameters
and stores it in a PreparedStatement object. This object can
be used to efficiently execute this SQL statement
multiple times.
@param sql The SQL statement.
@param resultSetType The result set type. Valid values are:
- ResultSet.TYPE_FORWARD_ONLY
- ResultSet.TYPE_SCROLL_INSENSITIVE
- ResultSet.TYPE_SCROLL_SENSITIVE
@param resultSetConcurrency The result set concurrency. Valid values are:
- ResultSet.CONCUR_READ_ONLY
- ResultSet.CONCUR_UPDATABLE
@param resultSetHoldability The result set holdability. Valid values are:
- ResultSet.HOLD_CURSORS_OVER_COMMIT
- ResultSet.CLOSE_CURSORS_AT_COMMIT
@return The prepared statement object.
@exception SQLException If the connection is not open,
the maximum number of statements
for this connection has been reached, the
result type, currency, or holdability is not valid,
or an error occurs.
**/
public PreparedStatement prepareStatement (String sql,
int resultSetType,
int resultSetConcurrency,
int resultSetHoldability)
throws SQLException
{
return prepareStatement(this, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
public PreparedStatement prepareStatement (AS400JDBCConnection con, String sql,
int resultSetType,
int resultSetConcurrency,
int resultSetHoldability)
throws SQLException
{
// Validation.
checkOpen ();
if (! metaData_.supportsResultSetConcurrency (resultSetType, resultSetConcurrency))
resultSetType = correctResultSetType (resultSetType, resultSetConcurrency);
if (!checkHoldabilityConstants(resultSetHoldability)) //@F3A
JDError.throwSQLException (this, JDError.EXC_ATTRIBUTE_VALUE_INVALID); //@F3A
// Create the statement.
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
properties_.getString (JDProperties.DECIMAL_SEPARATOR), true,
properties_.getString (JDProperties.PACKAGE_CRITERIA), con); // @A2A @G4A
int statementId = getUnusedId (resultSetType); // @B1C
AS400JDBCPreparedStatementImpl statement = new AS400JDBCPreparedStatementImpl (con,
statementId, transactionManager_, packageManager_,
properties_.getString (JDProperties.BLOCK_CRITERIA),
properties_.getInt (JDProperties.BLOCK_SIZE),
properties_.getBoolean (JDProperties.PREFETCH),
sqlStatement, false,
properties_.getString (JDProperties.PACKAGE_CRITERIA),
resultSetType, resultSetConcurrency, resultSetHoldability, //@G4A
AS400JDBCStatement.GENERATED_KEYS_NOT_SPECIFIED); //@G4A
statements_.addElement(statement); // @DAC
statementCount_++; //@K1A
if(thousandStatements_ == false && statementCount_ == 1000) //@K1A
{ //@K1A
thousandStatements_ = true; //@K1A
//post warning //@K1A
postWarning(JDError.getSQLWarning(JDError.WARN_1000_OPEN_STATEMENTS)); //@K1A
} //@K1A
if (JDTrace.isTraceOn()) //@F4A
{ //@F4A
int size = statements_.size(); //@F4A
if (size % 256 == 0) //@F4A
{ //@F4A
JDTrace.logInformation (this, "Warning: Open handle count now: " + size); //@F4A
} //@F4A
} //@F4A
return statement;
}
// @G4 new method
/**
* Precompiles an SQL statement with optional input parameters
* and stores it in a PreparedStatement object. This object can
* be used to efficiently execute this SQL statement
* multiple times.
*
* This method is not supported when connecting to IBM i V5R4 or earlier systems.
*
* @param sql The SQL statement.
* @param columnIndexes An array of column indexes indicating the columns that should be returned from the inserted row or rows.
* @return The prepared statement object.
* @exception java.sql.SQLException - If connecting to IBM i V5R4 or earlier systems,
* the connection is not open,
* the maximum number of statements for this connection has been reached,
* or an error occurs.
* @since Modification 5
**/
public PreparedStatement prepareStatement (String sql, int[] columnIndexes)
throws SQLException
{
return prepareStatement(this, sql, columnIndexes);
}
public PreparedStatement prepareStatement (AS400JDBCConnection con, String sql, int[] columnIndexes)
throws SQLException
{
if(getVRM() >= JDUtilities.vrm610) //@GKA added support for generated keys
{
// Validation
checkOpen();
//Create a JDSQLStatement
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
properties_.getString (JDProperties.DECIMAL_SEPARATOR), true,
properties_.getString (JDProperties.PACKAGE_CRITERIA), con);
//Check if the statement is an insert
if(sqlStatement.isInsert_){
wrappedInsert_ = true;
return prepareStatement(con, makeGeneratedKeySelectStatement(sql, columnIndexes, null), Statement.RETURN_GENERATED_KEYS);
}
else // treat like prepareStatement(sql) was called
return prepareStatement(con, sql);
}
else //@GKA Throw an exception. V5R4 and earlier does not support retrieving generated keys by column index.
{
JDError.throwSQLException (this, JDError.EXC_FUNCTION_NOT_SUPPORTED);
return null;
}
}
// @G4 new method
/**
* Precompiles an SQL statement with optional input parameters
* and stores it in a PreparedStatement object. This object can
* be used to efficiently execute this SQL statement
* multiple times.
*
*
This method is not supported when connecting to IBM i V5R4 or earlier systems.
*
* @param sql The SQL statement.
* @param columnNames An array of column names indicating the columns that should be returned from the inserted row or rows.
* @return The prepared statement object.
* @exception java.sql.SQLException - If connecting to IBM i V5R4 or earlier systems,
* the connection is not open,
* the maximum number of statements for this connection has been reached,
* or an error occurs.
* @since Modification 5
**/
public PreparedStatement prepareStatement (String sql, String[] columnNames)
throws SQLException
{
return prepareStatement(this, sql, columnNames);
}
public PreparedStatement prepareStatement (AS400JDBCConnection con, String sql, String[] columnNames)
throws SQLException
{
if(getVRM() >= JDUtilities.vrm610) //@GKA added generated key support
{
//Validation
checkOpen();
//Create a JDSQLStatement
JDSQLStatement sqlStatement = new JDSQLStatement (sql,
properties_.getString (JDProperties.DECIMAL_SEPARATOR), true,
properties_.getString (JDProperties.PACKAGE_CRITERIA), con);
//Check if the statement is an insert
if(sqlStatement.isInsert_){
wrappedInsert_ = true;
return prepareStatement(con, makeGeneratedKeySelectStatement(sql, null, columnNames), Statement.RETURN_GENERATED_KEYS);
}
else // treat like prepareStatement(sql) was called
return prepareStatement(con, sql);
}
else //@GKA Throw an exception. V5R4 and earlier does not support retrieving generated keys by column name.
{
JDError.throwSQLException (this, JDError.EXC_FUNCTION_NOT_SUPPORTED);
return null;
}
}
//@E10a new method
public void processSavepointRequest(String savepointStatement)
throws SQLException
{
// must be OS/400 v5r2 or IBM i
if (vrm_ < JDUtilities.vrm520)
JDError.throwSQLException(this, JDError.EXC_FUNCTION_NOT_SUPPORTED);
// cannot do savepoints on XA transactions
if (!transactionManager_.isLocalTransaction())
JDError.throwSQLException (this, JDError.EXC_TXN_STATE_INVALID);
// cannot do savepoints if autocommit on
if (getAutoCommit())
JDError.throwSQLException(this, JDError.EXC_TXN_STATE_INVALID);
Statement statement = null; //@scan1
try{
statement = createStatement();
statement.executeUpdate(savepointStatement);
}finally //@scan1
{
if(statement != null) //@scan1
statement.close();
}
}
/**
Partial closing of the connection.
@exception SQLException If a database error occurs.
**/
public void pseudoClose() throws SQLException // @E1
{
// Rollback before closing.
if ((transactionManager_.isLocalTransaction()) && (transactionManager_.isLocalActive())) // @E4A
rollback ();
// Close all statements that are running in the context of this connection.
// Make a clone of the vector, since it will be modified as each statement @DAA
// closes itself. // @DAA
// @j4 change -- close may throw a SQLException. Log that error and keep going.
// Since the user called close we won't return until we tried to close all
// statements.
Vector statements = (Vector)statements_.clone(); // @DAA
Enumeration list = statements.elements(); // @DAA
while (list.hasMoreElements()) // @DAC
{
// @DAC
AS400JDBCStatement statement = (AS400JDBCStatement)list.nextElement(); // @DAA
try
{ // @J4a
if(statement.isHoldStatement()) //@KBL user already called close, now completely close it
{ //@KBL
statement.setAssociatedWithLocators(false); //@KBL
statement.finishClosing(); //@KBL
} //@KBL
// @J4a
if (! statement.isClosed()) // @DAC
statement.close(); // @DAC
} // @J4a
catch (SQLException e) // @J4a
{
// @J4a
if (JDTrace.isTraceOn()) // @J4a
JDTrace.logInformation (this, "Closing statement while closing connection failed: " + e.getMessage()); // @j4a
} // @J4a
}
// @j1a clean up any IBM i debug that is going on. This entire block
// is new for @J1
if (traceServer_ > 0 || databaseHostServerTrace_) // @2KRC
{
// Get the job identifier because we need the id (it is part of some
// of our trace files). I know I could have saved it from
// the start-trace code but tracing is not performance critical so
// why make the object bigger by storing trace stuff as member data.
String serverJobIdentifier = getServerJobIdentifier();
// Same for this flag. Don't want to grow the object by saving
// this as member data.
boolean preV5R1 = true;
boolean SQLNaming = properties_.getString(JDProperties.NAMING).equals(JDProperties.NAMING_SQL);
try
{
preV5R1 = getVRM() <= JDUtilities.vrm450;
}
catch (Exception e)
{
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to end server job tracing failed, could not get server VRM");
}
boolean endedTraceJob = false; //@540 Used to determine if ENDTRC has already been done.
// End trace-job
if ((traceServer_ & ServerTrace.JDBC_TRACE_SERVER_JOB) > 0)
{
try
{
if (preV5R1)
JDUtilities.runCommand(this, "QSYS/TRCJOB SET(*OFF) OUTPUT(*PRINT)", SQLNaming);
else
{
JDUtilities.runCommand(this, "QSYS/ENDTRC SSNID(QJT" +
serverJobIdentifier.substring(20) +
") DTAOPT(*LIB) DTALIB(QUSRSYS) RPLDTA(*YES) PRTTRC(*YES)", SQLNaming );
JDUtilities.runCommand(this, "QSYS/DLTTRC DTAMBR(QJT" +
serverJobIdentifier.substring(20) +
") DTALIB(QUSRSYS)", SQLNaming );
}
endedTraceJob = true; //@540
}
catch (Exception e)
{
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to end server job tracing failed");
}
}
//@540 End database host server trace job
// Database Host Server Trace is supported on V5R3+
if(getVRM() >= JDUtilities.vrm530 && !endedTraceJob)
{
// Only issue ENDTRC if not already done.
if(((traceServer_ & ServerTrace.JDBC_TRACE_DATABASE_HOST_SERVER) > 0) || databaseHostServerTrace_) // @2KRC
{
// end database host server trace
try{
JDUtilities.runCommand(this, "QSYS/ENDTRC SSNID(QJT" +
serverJobIdentifier.substring(20) +
") DTAOPT(*LIB) DTALIB(QUSRSYS) RPLDTA(*YES) PRTTRC(*YES)", SQLNaming );
JDUtilities.runCommand(this, "QSYS/DLTTRC DTAMBR(QJT" +
serverJobIdentifier.substring(20) +
") DTALIB(QUSRSYS)", SQLNaming );
}
catch(Exception e){
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to end database host server tracing failed.");
}
}
}
// End debug-job
if ((traceServer_ & ServerTrace.JDBC_DEBUG_SERVER_JOB) > 0)
{
try
{
JDUtilities.runCommand(this, "QSYS/ENDDBG", SQLNaming);
}
catch (Exception e)
{
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to end server job tracing failed, could not end debug on server job ");
}
}
// End the database monitor
if ((traceServer_ & ServerTrace.JDBC_START_DATABASE_MONITOR) > 0)
{
try
{
JDUtilities.runCommand(this, "QSYS/ENDDBMON", SQLNaming);
}
catch (Exception e)
{
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to end server job tracing failed, could not end database monitor");
}
}
// Dump out SQL information
if (((traceServer_ & ServerTrace.JDBC_SAVE_SQL_INFORMATION) > 0) && !preV5R1)
{
try
{
JDUtilities.runCommand(this, "QSYS/PRTSQLINF *JOB", SQLNaming);
}
catch (Exception e)
{
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to end server job tracing failed, could not print SQL information");
}
}
// Dump the joblog
if ((traceServer_ & ServerTrace.JDBC_SAVE_SERVER_JOBLOG) > 0)
{
try
{
JDUtilities.runCommand(this, "QSYS/DSPJOBLOG JOB(*) OUTPUT(*PRINT)", SQLNaming);
}
catch (Exception e)
{
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to end server job tracing failed, could not save job log");
}
}
// If the user set our flag to turn on client tracing then turn it back off.
// This may turn off tracing even though the user wanted it on for some other
// reason but there is no way for this code to know why tracing was turned on.
// It does know this interface is one reason it is on so we will assume it
// is the only reason and will turn it off here.
if ((traceServer_ & ServerTrace.JDBC_TRACE_CLIENT) > 0)
JDTrace.setTraceOn(false);
}
}
// @E10a new method
/**
* Removes the given Savepoint object from the current transaction.
* Any reference to the savepoint after it has been removed will
* cause an SQLException to be thrown.
*
* @param savepoint the savepoint to be removed.
*
* @exception SQLException if a database access error occurs or the given Savepoint
* is not a valid savepoint in the current transaction.
*
* @since Modification 5
**/
public void releaseSavepoint(Savepoint savepoint)
throws SQLException
{
if (savepoint == null)
throw new NullPointerException("savepoint");
AS400JDBCSavepoint sp = (AS400JDBCSavepoint) savepoint;
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Releasing savepoint " + sp.getName());
if (sp.getStatus() != AS400JDBCSavepoint.ACTIVE)
JDError.throwSQLException(this, JDError.EXC_SAVEPOINT_DOES_NOT_EXIST);
String SQLCommand = "RELEASE SAVEPOINT " + sp.getName();
processSavepointRequest(SQLCommand);
sp.setStatus(AS400JDBCSavepoint.CLOSED);
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Savepoint " + sp.getName() + " released.");
}
// @E4C
/**
Drops all changes made since the previous commit or
rollback and releases any database locks currently held by
the connection. This has no effect when the connection
is in auto-commit mode.
This method can not be called when the connection is part
of a distributed transaction. See
AS400JDBCXAResource for more information.
@exception SQLException If the connection is not open
or an error occurs.
**/
public void rollback ()
throws SQLException
{
checkOpen ();
if (!transactionManager_.isLocalTransaction()) // @E4A
JDError.throwSQLException (this, JDError.EXC_TXN_STATE_INVALID); // @E4A
if (transactionManager_.getAutoCommit () && properties_.getBoolean(JDProperties.AUTOCOMMIT_EXCEPTION))
JDError.throwSQLException (this, JDError.EXC_FUNCTION_SEQUENCE);
if (! transactionManager_.getAutoCommit ())
{
transactionManager_.rollback ();
// @F3 Mark all cursors closed on a rollback. Don't worry here
// @F3 about whether their statement level holdability is different; we will check
// @F3 that within Statement.markCursorsClosed().
// @F3D if (transactionManager_.getHoldIndicator() == JDTransactionManager.CURSOR_HOLD_FALSE // @B4A
// @F3 Passing true means we called markCursorClosed from rollback.
markCursorsClosed(true); // @B4A @F3C
if(properties_.getBoolean(JDProperties.HOLD_STATEMENTS )) //@PDA additional HOLD_STATEMENTS check
markStatementsClosed(); //@KBL
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Transaction rollback");
}
}
// @E10 new method
/**
* Undoes all changes made after the specified Savepoint was set.
*
* @param savepoint the savepoint to be rolled back to.
*
* @exception SQLException if a database access error occurs, the Savepoint
* is no longer valid, or this Connection
* is currently in auto-commit mode.
* @since Modification 5
**/
public void rollback(Savepoint savepoint)
throws SQLException
{
if (savepoint == null)
throw new NullPointerException("savepoint");
AS400JDBCSavepoint sp = (AS400JDBCSavepoint) savepoint;
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Rollback with savepoint " + sp.getName());
if (sp.getStatus() != AS400JDBCSavepoint.ACTIVE)
JDError.throwSQLException(this, JDError.EXC_SAVEPOINT_DOES_NOT_EXIST);
String SQLCommand = "ROLLBACK TO SAVEPOINT " + sp.getName();
processSavepointRequest(SQLCommand);
sp.setStatus(AS400JDBCSavepoint.CLOSED);
if(properties_.getBoolean(JDProperties.HOLD_STATEMENTS )) //@PDA additional HOLD_STATEMENTS check
markStatementsClosed(); //@KBL
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Rollback with savepoint " + sp.getName() + " complete.");
}
/**
Sends a request data stream to the system using the
connection's id and does not expect a reply.
@param request The request.
@exception SQLException If an error occurs.
**/
//
// See implementation notes for sendAndReceive().
//
public void send (DBBaseRequestDS request)
throws SQLException
{
send (request, id_, true);
}
/**
Sends a request data stream to the system and does not
expect a reply.
@param request The request.
@param id The id.
@exception SQLException If an error occurs.
**/
public //
// See implementation notes for sendAndReceive().
//
void send (DBBaseRequestDS request, int id)
throws SQLException
{
send (request, id, true);
}
/**
Sends a request data stream to the system and does not
expect a reply.
@param request The request.
@param id The id.
@param leavePending Indicates if the request should
be left pending. This indicates
whether or not to base the next
request on this one.
@exception SQLException If an error occurs.
**/
public //
// See implementation notes for sendAndReceive().
//
void send (DBBaseRequestDS request, int id, boolean leavePending)
throws SQLException
{
checkCancel(); // @E8A
checkOpen(); // @W1a
try
{
// Since we are just calling send() (instead of sendAndReceive()), // @EAA
// make sure we are not asking the system for a reply. Otherwise, // @EAA
// the reply will come back and it will get held in the AS400 // @EAA
// read daemon indefinitely - - a memory leak. // @EAA
if (JDTrace.isTraceOn())
{ // @EAA
if (request.getOperationResultBitmap() != 0) // @EAA
JDTrace.logInformation (this, "Reply requested but not collected:" + request.getReqRepID()); // @EAA
} // @EAA
request.setBasedOnORSHandle (0); // @DAC @EKC
// DBReplyRequestedDS reply = null;
if (dataCompression_ == DATA_COMPRESSION_RLE_ && !disableCompression_) //@L9C
{ // @ECA
request.addOperationResultBitmap(DBBaseRequestDS.ORS_BITMAP_REQUEST_RLE_COMPRESSION); // @ECA
request.addOperationResultBitmap(DBBaseRequestDS.ORS_BITMAP_REPLY_RLE_COMPRESSION); // @ECA
request.compress(); // @ECA
} // @ECA
DataStream actualRequest; // @E5A
synchronized(heldRequestsLock_)
{ // @E5A
if (heldRequests_ != null) // @E5A
actualRequest = new DBConcatenatedRequestDS(heldRequests_, request); // @E5A
else // @E5A
actualRequest = request; // @E5A
heldRequests_ = null; // @E5A
server_.send(actualRequest); // @E5A @F7M
//@P1D requestPending_[id] = leavePending; //@P0A @F7M
} // @E5A
// @E5D if (DEBUG_REQUEST_CHAINING_ == true) {
//@P0D if (leavePending) // @DAA
//@P0D requestPending_.set(id); // @DAC
//@P0D else // @DAA
//@P0D requestPending_.clear(id); // @DAA
// @E5D }
// @E5D else {
// @E5D request.addOperationResultBitmap (DBBaseRequestDS.ORS_BITMAP_RETURN_DATA);
// @E5D reply = (DBReplyRequestedDS) server_.sendAndReceive (request);
// @E5D requestPending_[id] = false;
// @E5D }
if (DEBUG_COMM_TRACE_ > 0)
{
debug (request);
// @E5D if (DEBUG_REQUEST_CHAINING_ == false)
// @E5D debug (reply);
}
}
// @J5D catch (ConnectionDroppedException e) { // @C1A
// @J5D server_ = null; // @D8
// @J5D request.freeCommunicationsBuffer(); // @EMa
// @J5D JDError.throwSQLException (this, JDError.EXC_CONNECTION_NONE, e); // @C1A
// @J5D } // @C1A
catch (IOException e)
{ // @J5A
server_ = null; // @J5A
//@P0D request.freeCommunicationsBuffer(); // @J5A
JDError.throwSQLException (this, JDError.EXC_COMMUNICATION_LINK_FAILURE, e); // @J5A
} // @J5A
catch (Exception e)
{
//@P0D request.freeCommunicationsBuffer(); // @EMa
JDError.throwSQLException (this, JDError.EXC_INTERNAL, e);
}
}
// @EBD /**
// @EBD Sends a request data stream to the system and discards
// @EBD the reply.
// @EBD
// @EBD @param request The request.
// @EBD @param id The id.
// @EBD @param leavePending Indicates if the request should
// @EBD be left pending. This indicates
// @EBD whether or not to base the next
// @EBD request on this one.
// @EBD
// @EBD @exception SQLException If an error occurs.
// @EBD **/
// @EBD //
// @EBD // See implementation notes for sendAndReceive().
// @EBD //
// @EBD void sendAndDiscardReply (DBBaseRequestDS request, int id)
// @EBD throws SQLException
// @EBD {
// @EBD checkCancel(); // @E8A
// @EBD
// @EBD try {
// @EBD request.setBasedOnORSHandle (0); //@EKC
// @EBD
// @EBD DataStream actualRequest; // @E5A
// @EBD synchronized(heldRequestsLock_) { // @E5A
// @EBD if (heldRequests_ != null) // @E5A
// @EBD actualRequest = new DBConcatenatedRequestDS(heldRequests_, request); // @E5A
// @EBD else // @E5A
// @EBD actualRequest = request; // @E5A
// @EBD heldRequests_ = null; // @E5A
// @EBD } // @E5A
// @EBD
// @EBD server_.sendAndDiscardReply(actualRequest); // @E5C
// @EBD requestPending_[id] = false;
// @EBD
// @EBD if (DEBUG_COMM_TRACE_ > 0)
// @EBD debug (request);
// @EBD }
// @EBD catch (ConnectionDroppedException e) { // @C1A
// @EBD server_ = null; // @D8
// @EBD JDError.throwSQLException (this, JDError.EXC_CONNECTION_NONE, e); // @C1A
// @EBD } // @C1A
// @EBD catch (Exception e) {
// @EBD JDError.throwSQLException (this, JDError.EXC_INTERNAL, e);
// @EBD }
// @EBD }
// @E5A
/**
Holds a request until the next explicit request. It will
be concatenated at the beginning of the next request.
@param request The request.
@param id The id.
@exception SQLException If an error occurs.
**/
//
// See implementation notes for sendAndReceive().
//
public void sendAndHold(DBBaseRequestDS request, int id)
throws SQLException
{
checkCancel(); // @E8A
checkOpen(); // @W1a
try
{
// Since we are just calling send() (instead of sendAndReceive()), // @EAA
// make sure we are not asking the system for a reply. Otherwise, // @EAA
// the reply will come back and it will get held in the AS400 // @EAA
// read daemon indefinitely - - a memory leak. // @EAA
if (JDTrace.isTraceOn())
{ // @EAA
if (request.getOperationResultBitmap() != 0) // @EAA
JDTrace.logInformation (this, "Reply requested but not collected:" + request.getReqRepID()); // @EAA
} // @EAA
request.setBasedOnORSHandle(0); // @DAC @EKC
if (dataCompression_ == DATA_COMPRESSION_RLE_ && !disableCompression_) //@L9C
{ // @ECA
request.addOperationResultBitmap(DBBaseRequestDS.ORS_BITMAP_REQUEST_RLE_COMPRESSION); // @ECA
request.addOperationResultBitmap(DBBaseRequestDS.ORS_BITMAP_REPLY_RLE_COMPRESSION); // @ECA
request.compress(); // @ECA
} // @ECA
synchronized(heldRequestsLock_)
{
if (heldRequests_ == null)
heldRequests_ = new Vector();
heldRequests_.addElement(request);
}
//@P0D requestPending_.set(id); // @DAC
//@P1D requestPending_[id] = true; //@P0A
if (DEBUG_COMM_TRACE_ > 0)
{
debug (request);
System.out.println("This request was HELD.");
}
}
// Note: No need to check for an IOException in this method, since we don't contact the system. @J5A
catch (Exception e)
{
JDError.throwSQLException (this, JDError.EXC_INTERNAL, e);
}
}
/**
Sends a request data stream to the system using the
connection's id and returns the corresponding reply from
the system.
@param request The request.
@return The reply.
@exception SQLException If an error occurs.
**/
//
// See implementation notes for sendAndReceive().
//
public DBReplyRequestedDS sendAndReceive (DBBaseRequestDS request)
throws SQLException
{
return sendAndReceive (request, id_);
}
/**
Sends a request data stream to the system and returns the
corresponding reply from the system.
@param request The request.
@param id The id.
@return The reply.
@exception SQLException If an error occurs.
**/
//
// Implementation notes:
//
// 1. We do not have to worry about thread synchronization
// here, since the AS400Server object handles it.
//
// 2. The based on id is used to chain requests for the
// same ORS without needing to get a reply for each one.
// If a request fails, then all subsequent requests will
// too, and the results from the original failure will
// ultimately be returned.
//
// Initially, the based on id is set to 0. After a
// request is sent the based on id is set to the statement's
// id, so that subsequent requests will base on this id.
// Finally, when a reply is retrieved, the based on id
// is reset to 0.
//
// The status of the based on id depends on whether a
// request is pending, which is maintained in the id table.
//
public DBReplyRequestedDS sendAndReceive (DBBaseRequestDS request, int id)
throws SQLException
{
checkCancel(); // @E8A
checkOpen(); // @W1a
DBReplyRequestedDS reply = null;
try
{
request.setBasedOnORSHandle (0); // @DAC @EKC
if (dataCompression_ == DATA_COMPRESSION_RLE_ && !disableCompression_) //@L9C
{ // @ECA
request.addOperationResultBitmap(DBBaseRequestDS.ORS_BITMAP_REQUEST_RLE_COMPRESSION); // @ECA
request.addOperationResultBitmap(DBBaseRequestDS.ORS_BITMAP_REPLY_RLE_COMPRESSION); // @ECA
request.compress(); // @ECA
} // @ECA
DataStream actualRequest; // @E5A
synchronized(heldRequestsLock_)
{ // @E5A
if (heldRequests_ != null) // @E5A
actualRequest = new DBConcatenatedRequestDS(heldRequests_, request); // @E5A
else // @E5A
actualRequest = request; // @E5A
heldRequests_ = null; // @E5A
reply = (DBReplyRequestedDS)server_.sendAndReceive(actualRequest); // @E5C @F7M
//@P0D requestPending_.clear(id);
//@P1D requestPending_[id] = false; //@P0A @F7M
} // @E5A
reply.parse(dataCompression_); // @E5A
// @DAC
if (DEBUG_COMM_TRACE_ > 0)
{
debug (request);
debug (reply);
}
}
// @J5D catch (ConnectionDroppedException e) { // @C1A
// @J5D server_ = null; // @D8
// @J5D request.freeCommunicationsBuffer(); // @EMa
// @J5D JDError.throwSQLException (this, JDError.EXC_CONNECTION_NONE, e); // @C1A
// @J5D } // @C1A
catch (IOException e)
{ // @J5A
server_ = null; // @J5A
if (Trace.isTraceErrorOn()) {
Trace.log(Trace.ERROR, "Communication Link Failure ");
Trace.log(Trace.ERROR, e);
Trace.log(Trace.ERROR, "Server job is "+serverJobIdentifier_);
if (request != null && request.data_ != null ) {
Trace.log(Trace.ERROR,"Request bytes", request.data_);
}
}
//@P0D request.freeCommunicationsBuffer(); // @J5A
JDError.throwSQLException (this, JDError.EXC_COMMUNICATION_LINK_FAILURE, e); // @J5A
} // @J5A
catch (Exception e)
{
//@P0D request.freeCommunicationsBuffer(); // @EMa
if (Trace.isTraceErrorOn()) {
Trace.log(Trace.ERROR, "Unexpected exception ");
Trace.log(Trace.ERROR, e);
Trace.log(Trace.ERROR, "Server job is "+serverJobIdentifier_);
if (request != null && request.data_ != null ) {
Trace.log(Trace.ERROR,"Request bytes", request.data_);
}
} else if (JDTrace.isTraceOn()) {
JDTrace.logException(this, "Unexpected exception", e);
JDTrace.logInformation(this, "Server job is "+serverJobIdentifier_);
}
JDError.throwSQLException (this, JDError.EXC_INTERNAL, e);
}
// if (DBDSPool.monitor) {
// reply.setAllocatedLocation();
// }
return(DBReplyRequestedDS) reply;
}
//@D2A
public DBReplyRequestedDS sendAndMultiReceive (DBBaseRequestDS request)
throws SQLException
{
checkCancel(); // @E8A
checkOpen(); // @W1a
DBReplyRequestedDS reply = null;
try
{
request.setBasedOnORSHandle (0); // @DAC @EKC
if (dataCompression_ == DATA_COMPRESSION_RLE_ && !disableCompression_) //@L9C
{ // @ECA
request.addOperationResultBitmap(DBBaseRequestDS.ORS_BITMAP_REQUEST_RLE_COMPRESSION); // @ECA
request.addOperationResultBitmap(DBBaseRequestDS.ORS_BITMAP_REPLY_RLE_COMPRESSION); // @ECA
request.compress(); // @ECA
} // @ECA
DataStream actualRequest; // @E5A
synchronized(heldRequestsLock_)
{ // @E5A
if (heldRequests_ != null) // @E5A
actualRequest = new DBConcatenatedRequestDS(heldRequests_, request); // @E5A
else // @E5A
actualRequest = request; // @E5A
heldRequests_ = null; // @E5A
//D2A- allowed correlation ID to be stored and used on multiple receive calls
correlationID_ = server_.send(actualRequest);
reply = (DBReplyRequestedDS)server_.receive(correlationID_);
} // @E5A
reply.parse(dataCompression_); // @E5A
// @DAC
if (DEBUG_COMM_TRACE_ > 0)
{
debug (request);
debug (reply);
}
}
// @J5D catch (ConnectionDroppedException e) { // @C1A
// @J5D server_ = null; // @D8
// @J5D request.freeCommunicationsBuffer(); // @EMa
// @J5D JDError.throwSQLException (this, JDError.EXC_CONNECTION_NONE, e); // @C1A
// @J5D } // @C1A
catch (IOException e)
{ // @J5A
server_ = null; // @J5A
//@P0D request.freeCommunicationsBuffer(); // @J5A
JDError.throwSQLException (this, JDError.EXC_COMMUNICATION_LINK_FAILURE, e); // @J5A
} // @J5A
catch (Exception e)
{
//@P0D request.freeCommunicationsBuffer(); // @EMa
JDError.throwSQLException (this, JDError.EXC_INTERNAL, e);
}
return(DBReplyRequestedDS) reply;
}
//@DA2 - sew added new receive method.
public DBReplyRequestedDS receiveMoreData()
throws SQLException{
DBReplyRequestedDS reply = null;
try{
if(correlationID_ > 0){
synchronized(heldRequestsLock_)
{
reply = (DBReplyRequestedDS)server_.receive(correlationID_);
}
reply.parse(dataCompression_);
}
}catch (Exception e)
{
JDError.throwSQLException (this, JDError.EXC_INTERNAL, e);
}
return reply;
}
// @E4C
/**
Sets the auto-commit mode. If the connection is in auto-commit
mode, then all of its SQL statements are executed and committed
as individual transactions. Otherwise, its SQL statements are
grouped into transactions that are terminated by either a commit
or rollback.
By default, the connection is in auto-commit mode. The
commit occurs when the statement execution completes or the
next statement execute occurs, whichever comes first. In the
case of statements returning a result set, the statement
execution completes when the last row of the result set has
been retrieved or the result set has been closed. In advanced
cases, a single statement may return multiple results as well
as output parameter values. Here the commit occurs when all results
and output parameter values have been retrieved.
The auto-commit mode is always false when the connection is part
of a distributed transaction. See
AS400JDBCXAResource for more information.
@param autoCommit true to turn on auto-commit mode, false to
turn it off.
@exception SQLException If the connection is not open
or an error occurs.
**/
public void setAutoCommit (boolean autoCommit)
throws SQLException
{
checkOpen ();
if (TESTING_THREAD_SAFETY) return; // in certain testing modes, don't contact IBM i system
transactionManager_.setAutoCommit (autoCommit);
if (JDTrace.isTraceOn())
JDTrace.logProperty (this, "setAutoCommit", "Auto commit", transactionManager_.getAutoCommit ());
}
/**
This method is not supported.
@exception SQLException If the connection is not open.
**/
public void setCatalog (String catalog)
throws SQLException
{
checkOpen ();
// No-op.
}
//@cc1
/**
* This method sets concurrent access resolution. This method overrides the setting of ConcurrentAccessResolution on the datasource or connection
* URL properties. This changes the setting for this connection only. This method has no effect on
* IBM i V6R1 or earlier.
* The possible values for this property are {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_NOT_SET},
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_USE_CURRENTLY_COMMITTED},
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_WAIT_FOR_OUTCOME} and
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_SKIP_LOCKS},
* with the property defaulting to {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_NOT_SET}.
* Setting this property to default exhibits the default behavior on the servers
* i.e., the semantic applied for read
* transactions to avoid locks will be determined by the server.
*
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_USE_CURRENTLY_COMMITTED} specifies that driver will flow USE CURRENTLY COMMITTED
* to server. Whether CURRENTLY COMMITTED will actually be in effect is
* ultimately determined by server.
*
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_WAIT_FOR_OUTCOME} specifies that driver will flow WAIT FOR OUTCOME
* to server. This will disable the CURRENTLY COMMITTED behavior at the server,
* if enabled, and the server will wait for the commit or rollback of data in the process of
* being updated.
*
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_SKIP_LOCKS} specifies that driver will flow SKIP LOCKS
* to server. This directs the database manager to skip records in the case of record lock conflicts.
*
* @param concurrentAccessResolution The current access resolution setting. Possible valuse:
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_NOT_SET},
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_USE_CURRENTLY_COMMITTED},
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_WAIT_FOR_OUTCOME}, or
* {@link com.ibm.as400.access.AS400JDBCDataSource#CONCURRENTACCESS_SKIP_LOCKS}
* @throws SQLException If a database error occurs.
*/
public void setConcurrentAccessResolution (int concurrentAccessResolution) throws SQLException
{
DBSQLAttributesDS request = null;
DBReplyRequestedDS reply = null;
try
{
if (getVRM() >= JDUtilities.vrm710)
{
request = DBDSPool.getDBSQLAttributesDS(DBSQLAttributesDS.FUNCTIONID_SET_ATTRIBUTES, id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA + DBBaseRequestDS.ORS_BITMAP_SERVER_ATTRIBUTES, 0);
//get value of concurrent access resolution.
int car = properties_.getInt(JDProperties.CONCURRENT_ACCESS_RESOLUTION);
//here, we also allow resetting back to default 0
//pass value of concurrent access resolution into the hostserver request.
request.setConcurrentAccessResolution( car );
reply = sendAndReceive(request);
int errorClass = reply.getErrorClass();
if (errorClass != 0)
JDError.throwSQLException(this, this, id_, errorClass, reply.getReturnCode());
}
} catch( Exception e)
{
JDError.throwSQLException( this, JDError.EXC_INTERNAL, e);
} finally
{
if (request != null) {
request.returnToPool(); request=null;
}
if (reply != null) {
reply.returnToPool(); reply = null; // Can return -- only errorClass accessed
}
}
concurrentAccessResolution_ = concurrentAccessResolution;
}
/**
Sets the eWLM Correlator. It is assumed a valid correlator value is used.
If the value is null, all ARM/eWLM implementation will be turned off.
eWLM correlators require IBM i V5R3 or later systems. This request is ignored when running to OS/400 V5R2 or earlier systems.
@param bytes The eWLM correlator value
* @throws SQLException If a database error occurs.
**/
public void setDB2eWLMCorrelator(byte[] bytes)
throws SQLException //@eWLM
{
if(vrm_ >= JDUtilities.vrm530)
{
DBSQLAttributesDS request = null;
DBReplyRequestedDS reply = null;
try
{
if(bytes == null)
{
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "Correlator is null");
}
request = DBDSPool.getDBSQLAttributesDS (DBSQLAttributesDS.FUNCTIONID_SET_ATTRIBUTES,
id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA
+ DBBaseRequestDS.ORS_BITMAP_SERVER_ATTRIBUTES, 0);
request.seteWLMCorrelator(bytes);
reply = sendAndReceive(request);
int errorClass = reply.getErrorClass();
if(errorClass != 0)
JDError.throwSQLException(this, this, id_, errorClass, reply.getReturnCode());
}
catch(DBDataStreamException e)
{
JDError.throwSQLException(JDError.EXC_INTERNAL, e);
}
finally
{
if (request != null) { request.returnToPool(); request = null; }
if (reply != null) { reply.returnToPool(); reply = null; } // Return to pool since only errorClass accessed
}
}
}
// @B1A
/**
Sets whether the connection is being used for DRDA.
@param drda true if the connection is being used for DRDA,
false otherwise.
**/
public void setDRDA (boolean drda)
throws SQLException // @EGA
{
drda_ = drda;
if (JDTrace.isTraceOn())
JDTrace.logProperty (this, "setDRDA", "DRDA", drda_);
}
//@G4A JDBC 3.0
/**
Sets the holdability of ResultSets created from this connection.
Full functionality of this method requires OS/400 V5R2
or IBM i. If connecting to OS/400 V5R1 or earlier, all
cursors for the connection will be changed to the value of the variable
holdability.
@param holdability The cursor holdability.
Valid values are ResultSet.HOLD_CURSORS_OVER_COMMIT or
ResultSet.CLOSE_CURSORS_AT_COMMIT.
@exception SQLException If the connection is not open
or the value passed in is not valid.
@since Modification 5
**/
public void setHoldability (int holdability)
throws SQLException
{
checkOpen ();
if (TESTING_THREAD_SAFETY) return; // in certain testing modes, don't contact IBM i system
if (!checkHoldabilityConstants(holdability)) //@F3A
JDError.throwSQLException (this, JDError.EXC_ATTRIBUTE_VALUE_INVALID); //@F3A
holdability_ = holdability;
if (holdability == AS400JDBCResultSet.CLOSE_CURSORS_AT_COMMIT) //@F5A
transactionManager_.setHoldIndicator(JDProperties.CURSORHOLD_FALSE); //@F5A
else if (holdability == AS400JDBCResultSet.HOLD_CURSORS_OVER_COMMIT) //@F5A
transactionManager_.setHoldIndicator(JDProperties.CURSORHOLD_TRUE); //@F5A
if (JDTrace.isTraceOn())
JDTrace.logProperty (this, "setHoldability", "Holdability", holdability_);
}
//@D4A
public void setProperties (JDDataSourceURL dataSourceUrl, JDProperties properties,
AS400 as400, Properties info)
throws SQLException
{
if (TESTING_THREAD_SAFETY) // in certain testing modes, don't contact IBM i system
{
as400PublicClassObj_ = as400;
}
else
{
try
{
portNumber = 0;
// Check to see if the port property is set. If so,
// Then we must set the port in the PortMapper and
// tell the as400 object not to use the signon server.
// The port in the URL has precedence over the property.
/*@V1A*/
if (dataSourceUrl.isPortSpecified()) {
portNumber = dataSourceUrl.getPortNumber();
}
if (portNumber == 0) {
portNumber = properties.getInt(JDProperties.PORTNUMBER);
}
if (portNumber > 0) {
as400.skipSignonServer = true;
as400.connectService (AS400.DATABASE, portNumber);
portNumberString = ""+portNumber;
} else {
as400.connectService (AS400.DATABASE);
}
systemName_ = as400.getSystemName();
}
catch (AS400SecurityException e)
{ //@D5C
JDError.throwSQLException (this, JDError.EXC_CONNECTION_REJECTED, e);
}
catch (IOException e)
{ //@D5C
JDError.throwSQLException (this, JDError.EXC_CONNECTION_UNABLE, e);
}
finally //@dbldrvr
{ //@dbldrvr
//Since driver is registered twice in DriverManager via DriverManager.registerDriver(new AS400JDBCDriver()),
//remove extra driver references now so we don't waste resources by continuing to try, and also so we don't lock out id if pwd is not correct.
Enumeration en = DriverManager.getDrivers(); //@dbldrvr
Driver firstDriver = null; //@dbldrvr
Driver nextDriver = null; //@dbldrvr
while (en.hasMoreElements()) //@dbldrvr
{ //@dbldrvr
nextDriver = (Driver) en.nextElement(); //@dbldrvr
if(nextDriver instanceof AS400JDBCDriver) //@dbldrvr
{ //@dbldrvr
if(firstDriver == null) //@dbldrvr
firstDriver = nextDriver; //@dbldrvr
else //@dbldrvr
DriverManager.deregisterDriver(nextDriver); //@dbldrvr
} //@dbldrvr
} //@dbldrvr
} //@dbldrvr
}
setProperties (dataSourceUrl, properties, as400.getImpl(), false, as400.skipSignonServer);
}
public void setProperties(JDDataSourceURL dataSourceUrl, JDProperties properties, AS400Impl as400)
throws SQLException
{
setProperties(dataSourceUrl, properties, as400, false, false);
}
/* Should the warning be ignored @Q1A*/
public boolean ignoreWarning(String sqlState) {
if (ignoreWarnings_.indexOf(sqlState ) >= 0) {
return true;
} else {
return false;
}
}
public boolean ignoreWarning(SQLWarning warning) {
return ignoreWarning(warning.getSQLState());
}
//@A3A - This logic formerly resided in the ctor.
public void setProperties (JDDataSourceURL dataSourceUrl, JDProperties properties, AS400Impl as400, boolean newServer, boolean skipSignonServer)
throws SQLException
{
// Initialization.
as400_ = (AS400ImplRemote) as400; //@A3A
//@P0D assigned_ = new BitSet(INITIAL_STATEMENT_TABLE_SIZE_); // @DAC
dataSourceUrl_ = dataSourceUrl;
extendedFormats_ = false;
properties_ = properties;
ignoreWarnings_ = properties_.getString(JDProperties.IGNORE_WARNINGS).toUpperCase(); /*@Q1A*/
//Set the real default for METADATA SOURCE property since we now know the hostsrvr version
if(properties_.getString(JDProperties.METADATA_SOURCE).equals(JDProperties.METADATA_SOURCE_HOST_VERSION_DEFAULT)) //@mdsp
{ //@mdsp
if(as400_.getVRM() < JDUtilities.vrm710) //@mdsp //@710 take effect after 710 (ie. not 615)
properties_.setString(JDProperties.METADATA_SOURCE, JDProperties.METADATA_SOURCE_ROI); //@mdsp
else //@mdsp
properties_.setString(JDProperties.METADATA_SOURCE, JDProperties.METADATA_SOURCE_STORED_PROCEDURE); //@mdsp
} //@mdsp
//@P0D requestPending_ = new BitSet(INITIAL_STATEMENT_TABLE_SIZE_); // @DAC
if(!TESTING_THREAD_SAFETY && as400_.getVRM() <= JDUtilities.vrm520) //@KBA //if V5R2 or less use old support of issuing set transaction statements
newAutoCommitSupport_ = 0; //@KBA
else if(!properties_.getBoolean(JDProperties.TRUE_AUTO_COMMIT)) //@KBA //@true //run autocommit with *NONE isolation level
newAutoCommitSupport_ = 1; //@KBA
else //@KBA
newAutoCommitSupport_ = 2; //@KBA //run autocommit with specified isolation level
if (as400_.getVRM() >= JDUtilities.vrm710) {
useBlockUpdate_ = properties_.getBoolean(JDProperties.USE_BLOCK_UPDATE); //@A2A
}
maximumBlockedInputRows_ = properties_.getInt(JDProperties.MAXIMUM_BLOCKED_INPUT_ROWS); // @A6A
if ( maximumBlockedInputRows_ > 32000 ) maximumBlockedInputRows_ = 32000; // @A6A
if ( maximumBlockedInputRows_ < 1 ) maximumBlockedInputRows_ = 1; // @A6A
// Issue any warnings.
if (dataSourceUrl_.isExtraPathSpecified ())
postWarning (JDError.getSQLWarning (JDError.WARN_URL_EXTRA_IGNORED));
if (properties.isExtraPropertySpecified ())
postWarning (JDError.getSQLWarning (JDError.WARN_PROPERTY_EXTRA_IGNORED));
if (dataSourceUrl_.isPortSpecified ()) {
if (dataSourceUrl_.getPortNumber() == 0) {
postWarning (JDError.getSQLWarning (JDError.WARN_URL_EXTRA_IGNORED));
}
}
// Initialize the library list.
String urlSchema = dataSourceUrl_.getSchema ();
if (urlSchema == null)
JDError.throwSQLException (this, JDError.WARN_URL_SCHEMA_INVALID);
JDLibraryList libraryList = new JDLibraryList (
properties_.getString (JDProperties.LIBRARIES), urlSchema,
properties_.getString (JDProperties.NAMING)); // @B2C
defaultSchema_ = libraryList.getDefaultSchema ();
// The connection gets an id automatically, but never
// creates an RPB on the system. There should never be a need
// to create an RPB on the system for a connection, but an
// id is needed for retrieving Operational Result Sets (ORS)
// for errors, etc.
// Initialize a transaction manager for this connection.
transactionManager_ = new JDTransactionManager (this, id_,
properties_.getString (JDProperties.TRANSACTION_ISOLATION),
properties_.getBoolean (JDProperties.AUTO_COMMIT)); //@AC1
transactionManager_.setHoldIndicator(properties_.getString(JDProperties.CURSOR_HOLD)); // @D9
// If the hold properties are specified, make sure they are set locally
if (properties_.getString(JDProperties.CURSOR_HOLD) != null) {
if (transactionManager_.getHoldIndicator() == JDTransactionManager.CURSOR_HOLD_TRUE)
holdability_ = AS400JDBCResultSet.HOLD_CURSORS_OVER_COMMIT;
else if (transactionManager_.getHoldIndicator() == JDTransactionManager.CURSOR_HOLD_FALSE)
holdability_ = AS400JDBCResultSet.CLOSE_CURSORS_AT_COMMIT;
}
// Initialize the read-only mode to true if the access
// property says read only.
readOnly_ = (properties_.equals (JDProperties.ACCESS,
JDProperties.ACCESS_READ_ONLY));
// Determine the amount of system tracing that should be started. Trace
// can be started by either a JDBC property or the ServerTrace class. Our value
// will be the combination of the two (instead of one overriding the other).
traceServer_ = properties_.getInt(JDProperties.TRACE_SERVER) |
ServerTrace.getJDBCServerTraceCategories(); // @j1a //@SSa logical OR
// Determine if a QAQQINI library name was specified. The library can be set using //@K2A
// a JDBC property. //@k2A
qaqqiniLibrary_ = properties_.getString(JDProperties.QAQQINILIB); //@K2A
String queryTimeoutMechanismString = properties_.getString(JDProperties.QUERY_TIMEOUT_MECHANISM);
if (queryTimeoutMechanismString != null) {
queryTimeoutMechanismString = queryTimeoutMechanismString.trim().toLowerCase();
if (queryTimeoutMechanismString.equals(JDProperties.QUERY_TIMEOUT_MECHANISM_CANCEL)) {
queryTimeoutMechanism_ = QUERY_TIMEOUT_CANCEL;
} else {
queryTimeoutMechanism_ = QUERY_TIMEOUT_QQRYTIMLMT;
}
}
String queryReplaceTruncatedParameterString = properties_.getString(JDProperties.QUERY_REPLACE_TRUNCATED_PARAMETER);
if (queryReplaceTruncatedParameterString != null) {
queryReplaceTruncatedParameterString = queryReplaceTruncatedParameterString.trim();
if (queryReplaceTruncatedParameterString.equals(JDProperties.QUERY_REPLACE_TRUNCATED_PARAMETER_STRING_DEFAULT)) {
queryReplaceTruncatedParameter_ = null;
} else {
queryReplaceTruncatedParameter_ = queryReplaceTruncatedParameterString;
}
}
// Default value of data truncation is "true"
boolean dataTruncation = properties_.getBoolean(
JDProperties.DATA_TRUNCATION);
// Default value of data truncation is "default"
String characterTruncation = properties_.getString(
JDProperties.CHARACTER_TRUNCATION);
// if characterTruncation is default, then use the dataTruncation setting
// otherwise use the characterTruncation setting
if (characterTruncation == null || characterTruncation == JDProperties.CHARACTER_TRUNCATION_DEFAULT) {
if (dataTruncation) {
characterTruncation_ = CHARACTER_TRUNCATION_DEFAULT;
} else {
characterTruncation_ = CHARACTER_TRUNCATION_NONE;
}
} else if (characterTruncation.equals(JDProperties.CHARACTER_TRUNCATION_WARNING)) {
characterTruncation_ = CHARACTER_TRUNCATION_WARNING;
} else if (characterTruncation.equals(JDProperties.CHARACTER_TRUNCATION_NONE)) {
characterTruncation_ = CHARACTER_TRUNCATION_NONE;
}
String numericRangeError = properties_.getString(JDProperties.NUMERIC_RANGE_ERROR);
if (numericRangeError == null) numericRangeError = JDProperties.NUMERIC_RANGE_ERROR_DEFAULT;
if (numericRangeError.equals(JDProperties.NUMERIC_RANGE_ERROR_DEFAULT)) {
numericRangeError_ = NUMERIC_RANGE_ERROR_DEFAULT;
} else if (numericRangeError.equals(JDProperties.NUMERIC_RANGE_ERROR_WARNING)) {
numericRangeError_ = NUMERIC_RANGE_ERROR_WARNING;
} else if (numericRangeError.equals(JDProperties.NUMERIC_RANGE_ERROR_NONE)) {
numericRangeError_ = NUMERIC_RANGE_ERROR_NONE;
}
//@A3D
// Initialize the conversation.
//open ();
//@A3A
// Connect.
if (JDTrace.isTraceOn()) // @F6a
{ // @F6a
JDTrace.logInformation("Toolbox for Java - " + Copyright.version); // @F6a
JDTrace.logInformation("JDBC Level: " + JDUtilities.JDBCLevel_); // @F6a
} // @F6a
if (!TESTING_THREAD_SAFETY) // in certain testing modes, we don't contact IBM i system
{
try
{
server_ = as400_.getConnection (AS400.DATABASE, -1, newServer, skipSignonServer);
}
catch (AS400SecurityException e)
{
JDError.throwSQLException (this, JDError.EXC_CONNECTION_REJECTED, e);
}
catch (IOException e)
{
JDError.throwSQLException (this, JDError.EXC_CONNECTION_UNABLE, e);
}
}
// Initialize the catalog name at this point to be the system
// name. After we exchange attributes, we can change it to
// the actual name.
catalog_ = dataSourceUrl.getServerName(); // @D7A
if (catalog_.length() == 0) // @D7A
catalog_ = as400_.getSystemName ().toUpperCase (); // @A3A
setServerAttributes ();
libraryList.addOnServer (this, id_);
boolean useDRDAversion = properties_.getBoolean(JDProperties.USE_DRDA_METADATA_VERSION);
// @E7D // Initialize a transaction manager for this connection. Turn on @E7A
// @E7D // new auto-commit support when the server functional level is @E7A
// @E7D // greater than or equal to 3. @E7A
// @E7D boolean newAutoCommitSupport = (serverFunctionalLevel_ >= 3); // @E7A
// @E7D transactionManager_.setNewAutoCommitSupport(newAutoCommitSupport); // @E7A
// We keep a metadata object around for quick access.
// The metadata object should share the id of the
// connection, since it operates on a connection-wide
// scope.
metaData_ = new AS400JDBCDatabaseMetaData (this, id_, useDRDAversion);
// The conversation was initialized to a certain
// transaction isolation. It is now time to turn on auto-
// commit by default.
if(newAutoCommitSupport_ == 0) //KBA V5R2 or less so do what we always have
transactionManager_.setAutoCommit (true);
// Initialize the package manager.
packageManager_ = new JDPackageManager (this, id_, properties_,
transactionManager_.getCommitMode ());
// Trace messages.
if (JDTrace.isTraceOn())
{
JDTrace.logOpen (this, null); // @J33a
JDTrace.logProperty (this, "setProperties", "Auto commit", transactionManager_.getAutoCommit ());
JDTrace.logProperty (this, "setProperties", "Read only", readOnly_);
JDTrace.logProperty (this, "setProperties", "Transaction isolation", transactionManager_.getIsolation ());
if (packageManager_.isEnabled ())
JDTrace.logInformation (this, "SQL package = "
+ packageManager_.getLibraryName() + "/"
+ packageManager_.getName ());
}
// @j1a Trace the server job if the user asked us to. Tracing
// can be turned on via a URL property, the Trace class, the DataSource
// object, or a system property.
if (traceServer_ > 0)
{
// Get the server job id. We will both dump this to the trace
// and use it to uniquely label some of the files.
String serverJobIdentifier = getServerJobIdentifier();
String serverJobId = serverJobIdentifier.substring(20).trim() + "/" +
serverJobIdentifier.substring(10, 19).trim() + "/" +
serverJobIdentifier.substring( 0, 10).trim();
// Dump the server job id
JDTrace.logDataEvenIfTracingIsOff(this, Copyright.version);
JDTrace.logDataEvenIfTracingIsOff(this, serverJobId);
JDTrace.logDataEvenIfTracingIsOff(this, "Server functional level: " + getServerFunctionalLevel()); // @E7A
// Determine system level. Some commands are slightly different
// to v5r1 machines.
boolean preV5R1 = true;
boolean SQLNaming = properties_.getString(JDProperties.NAMING).equals(JDProperties.NAMING_SQL);
try
{
preV5R1 = getVRM() <= JDUtilities.vrm450;
}
catch (Exception e)
{
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to start server job tracing failed, could not get server VRM");
}
// Start client tracing if the flag is on and trace isn't already running
if (((traceServer_ & ServerTrace.JDBC_TRACE_CLIENT) > 0) && (! JDTrace.isTraceOn()))
JDTrace.setTraceOn(true);
// No matter what type of tracing is turned on, alter the server
// job so more stuff is saved in the job log.
try
{
JDUtilities.runCommand(this, "QSYS/CHGJOB LOG(4 00 *SECLVL) LOGCLPGM(*YES)", SQLNaming);
}
catch (Exception e)
{
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to start server job tracing failed, could not change log level");
}
// Optionally start debug on the database server job
if ((traceServer_ & ServerTrace.JDBC_DEBUG_SERVER_JOB) > 0)
{
try
{
JDUtilities.runCommand(this, "QSYS/STRDBG UPDPROD(*YES)", SQLNaming);
}
catch (Exception e)
{
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to start server job tracing failed, could not start debug on server job ");
}
}
// Optionally start the database monitor
if ((traceServer_ & ServerTrace.JDBC_START_DATABASE_MONITOR) > 0)
{
try
{
JDUtilities.runCommand(this, "QSYS/STRDBMON OUTFILE(QUSRSYS/QJT" +
serverJobIdentifier.substring(20) +
") JOB(*) TYPE(*DETAIL)", SQLNaming );
}
catch (Exception e)
{
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to start server job tracing failed, could not start database monitor");
}
}
boolean traceServerJob = ((traceServer_ & ServerTrace.JDBC_TRACE_SERVER_JOB) > 0); //@540
//@540 Database Host Server Trace is supported on V5R3 and later systems
boolean traceDatabaseHostServer = ((getVRM() >= JDUtilities.vrm530) && ((traceServer_ & ServerTrace.JDBC_TRACE_DATABASE_HOST_SERVER) > 0)); //@540
// Optionally start trace on the database server job or database host server
//@540D if ((traceServer_ & ServerTrace.JDBC_TRACE_SERVER_JOB) > 0)
if(traceServerJob || traceDatabaseHostServer) //@540
{
try
{
if (preV5R1 && traceServerJob) //@540 added check for traceServerJob
JDUtilities.runCommand(this, "QSYS/TRCJOB MAXSTG(16000)", SQLNaming);
else{
if(!traceDatabaseHostServer){ //@540 trace only server job
JDUtilities.runCommand(this, "QSYS/STRTRC SSNID(QJT" +
serverJobIdentifier.substring(20) +
") JOB(*) MAXSTG(128000)", SQLNaming);
}
else if(!traceServerJob){ //@540 trace only database host server
if(getVRM() == JDUtilities.vrm530){ //@540 run command for V5R3
JDUtilities.runCommand(this, "QSYS/STRTRC SSNID(QJT" + //@540
serverJobIdentifier.substring(20) + //@540
") JOB(*) MAXSTG(128000) JOBTRCTYPE(*TRCTYPE) " + //@540
"TRCTYPE((TESTA *INFO))", SQLNaming); //@540
}
else{ //@540 run command for V5R4 and higher
JDUtilities.runCommand(this, "QSYS/STRTRC SSNID(QJT" + //@540
serverJobIdentifier.substring(20) + //@540
") JOB(*) MAXSTG(128000) JOBTRCTYPE(*TRCTYPE) " + //@540
"TRCTYPE((*DBHSVR *INFO))", SQLNaming); //@540
}
} //@540
else{ //@540 start both server job and database host server trace
if(getVRM() == JDUtilities.vrm530){ //@540 run command for V5R3
JDUtilities.runCommand(this, "QSYS/STRTRC SSNID(QJT" + //@540
serverJobIdentifier.substring(20) + //@540
") JOB(*) MAXSTG(128000) JOBTRCTYPE(*ALL) " + //@540
"TRCTYPE((TESTA *INFO))", SQLNaming); //@540
}
else{ //@540 run V5R4 and higher command
JDUtilities.runCommand(this, "QSYS/STRTRC SSNID(QJT" + //@540
serverJobIdentifier.substring(20) + //@540
") JOB(*) MAXSTG(128000) JOBTRCTYPE(*ALL) " + //@540
"TRCTYPE((*DBHSVR *INFO))", SQLNaming); //@540
}
}
}
}
catch (Exception e)
{
if(traceServerJob && !traceDatabaseHostServer) //@540
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to start server job tracing failed, could not trace server job");
else if(traceDatabaseHostServer && !traceServerJob) //@540
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to start database host server tracing failed, could not trace server job"); //@540
else //@540
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to start server job and database host server tracing failed, could not trace server job"); //@540
}
}
}
//@K2A Issue Change Query Attributes command if user specified QAQQINI library name
if(qaqqiniLibrary_.length() > 0 && !qaqqiniLibrary_.equals("null"))
{
boolean SQLNaming = properties_.getString(JDProperties.NAMING).equals(JDProperties.NAMING_SQL);
try
{
JDUtilities.runCommand(this, "CHGQRYA QRYOPTLIB(" + qaqqiniLibrary_ + ")", SQLNaming );
}
catch (Exception e)
{
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to issue Change Query Attributes command using QAQQINI Library name failed.");
}
}
}
/**
Sets the read-only mode. This will provide read-only
access to the database. Read-only mode can be useful by
enabling certain database optimizations. If the caller
specified "read only" or "read call" for the "access" property,
then the read-only mode cannot be set to false. The read-only
mode cannot be changed while in the middle of a transaction.
This method can not be called when the connection is part
of a distributed transaction. See
AS400JDBCXAResource for more information.
@exception SQLException If the connection is not open,
a transaction is active, or the
"access" property is set to "read
only".
**/
public void setReadOnly (boolean readOnly)
throws SQLException
{
checkOpen ();
if (transactionManager_.isLocalActive () || transactionManager_.isGlobalActive()) // @E4C
JDError.throwSQLException (this, JDError.EXC_TXN_STATE_INVALID); // @E4C
if ((readOnly == false)
&& ((properties_.getString (JDProperties.ACCESS).equalsIgnoreCase (JDProperties.ACCESS_READ_ONLY))
|| (properties_.getString (JDProperties.ACCESS).equalsIgnoreCase (JDProperties.ACCESS_READ_CALL))))
JDError.throwSQLException (this, JDError.EXC_ACCESS_MISMATCH);
readOnly_ = readOnly;
if (JDTrace.isTraceOn())
JDTrace.logProperty (this, "setProperties", "Read only", readOnly_);
}
// @E10 new method
/**
* Creates an unnamed savepoint in the current transaction and returns the new Savepoint object that represents it.
*
* - Named savepoints must be unique. A savepoint name cannot be reused until the savepoint is released, committed, or rolled back.
*
- Savepoints are valid only if autocommit is off. An exception is thrown if autocommit is enabled.
*
- Savepoints are not valid across XA connections. An exception is thrown if the connection is an XA connection.
*
- Savepoints require OS/400 V5R2 or IBM i. An exception is thrown if connecting to OS/400 V5R1 or earlier.
*
- If the connection option is set to keep cursors open after a traditional rollback, cursors will remain open after a rollback to a savepoint.
*
*
* @return The new Savepoint object.
* @exception SQLException if a database access error occurs or this Connection object is currently in auto-commit mode.
* @since Modification 5
**/
public Savepoint setSavepoint()
throws SQLException
{
return setSavepoint(null, AS400JDBCSavepoint.getNextId());
}
// @E10 new method
/**
* Creates a named savepoint in the current transaction and returns the new Savepoint object that represents it.
*
* - Named savepoints must be unique. A savepoint name cannot be reused until the savepoint is released, committed, or rolled back.
*
- Savepoints are valid only if autocommit is off. An exception is thrown if autocommit is enabled.
*
- Savepoints are not valid across XA connections. An exception is thrown if the connection is an XA connection.
*
- Savepoints require OS/400 V5R2 or IBM i. An exception is thrown if connecting to OS/400 V5R1 or earlier.
*
- If the connection option is set to keep cursors open after a traditional rollback, cursors will remain open after a rollback to a savepoint.
*
* @param name A String containing the name of the savepoint
* @return The new Savepoint object.
* @exception SQLException if a database access error occurs or this Connection object is currently in auto-commit mode.
* @since Modification 5
**/
public Savepoint setSavepoint(String name)
throws SQLException
{
if (name == null)
throw new NullPointerException("name");
return setSavepoint(name, 0);
}
// @E10 new method
public Savepoint setSavepoint(String name, int id)
throws SQLException
{
if (id > 0)
name = "T_JDBCINTERNAL_" + id;
// When creating the savepoint specify retain cursors. That is the
// only option supported by the IBM i system at this time. We have to specify
// it because the SQL default is close cursors. Since we need to use
// an option other than the default we have to specify it on the statement.
// Plus, the system will return an error if we don't specify it.
processSavepointRequest("SAVEPOINT " + name + " ON ROLLBACK RETAIN CURSORS" );
return(Savepoint)(Object) new AS400JDBCSavepoint(name, id);
}
/**
Sets the server attributes.
@exception SQLException If an error occurs.
**/
public void setServerAttributes ()
throws SQLException
{
if (TESTING_THREAD_SAFETY) return; // in certain testing modes, don't contact IBM i system
DBReplyRequestedDS reply = null;
try
{
if (as400_ == null) {
throw new NullPointerException("as400_ not set");
}
vrm_ = as400_.getVRM(); // @D0A @ECM
//@P0C
DBSQLAttributesDS request = null;
int decimalSeparator, dateFormat, dateSeparator, timeFormat, timeSeparator;
int decimalDataErrors;
DBReplyServerAttributes serverAttributes = null;
try
{
request = DBDSPool.getDBSQLAttributesDS (DBSQLAttributesDS.FUNCTIONID_SET_ATTRIBUTES,
id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA
+ DBBaseRequestDS.ORS_BITMAP_SERVER_ATTRIBUTES, 0); //@P0C
// We need to set a temporary CCSID just for this
// request, since we use this request to get the
// actual CCSID.
//@P0D ConverterImplRemote tempConverter =
//@P0D ConverterImplRemote.getConverter (as400_.getCcsid(), as400_);
// We can safely use ccsid 37 as long as the fields in the request are tagged with
// CCSID 37. /*@V1A*/
int thisRequestCcsid = 37;
// The server does not properly handle the case where the job CCSID does
// not match the specified CCSID. Try to use the CCSID from the as400 object,
// if available. Here is an example of the error evident in the SetAttributes
// response. (Trace displays CCSID 37 and data passed in CCSID 37.
//
// Error Return Code: 1301 - At least one library not added to the library list.
// Server CCSID: 277
// Default SQL Library: XL?KODTA -- E7 D3 80 D2 D6 C4 E3 C1
// Default SQL Collection: (ll=8) XL@KODTA -- E7 D3 7C D2 D6 C4 E3 C1
// In CCSID 277 7C is ?
//
// @AB3A
if ((as400_ != null) && (portNumber == 0)) {
// getCcsid will contact the server, so we only want to do that if the port is not set.
thisRequestCcsid = as400_.getCcsid();
}
ConvTable libraryNameConverter = ConvTable.getTable(thisRequestCcsid, null); //@P0A
ConvTable ccsid37Converter = ConvTable.getTable(37, null);
// @E2D // Do not set the client CCSID. We do not want
// @E2D // the system to convert data, since we are going
// @E2D // to do all conersion on the client. By not telling
// @E2D // the system our CCSID, then we achieve this.
// @E2D //
// @E2D // Note that the database host server documentation
// @E2D // states that when we do this, the CCSID values
// @E2D // in data formats may be incorrect and that we
// @E2D // should always use the server job's CCSID.
// Set the client CCSID to Unicode. // @E2A
// @M0C - As of v5r3m0 we allow the client CCSID to be 1200 (UTF-16) which
// will cause our statement to flow in 1200 and our package to be 1200
//Bidi-HCG allow any ccsid or "system" to use ccsid of AS400 object
//Bidi-HCG start
String sendCCSID = properties_.getString(JDProperties.PACKAGE_CCSID);
int sendCCSIDInt;
int default_ccsid = Integer.parseInt(JDProperties.PACKAGE_CCSID_UCS2);
if( sendCCSID.equalsIgnoreCase("system")) {
// Only look up host CCSID if needed
int hostCCSID;
if(as400PublicClassObj_ == null) //@pdcbidi
hostCCSID = 37;
else
hostCCSID = as400PublicClassObj_.getCcsid();
sendCCSIDInt = hostCCSID;
} else {
try{
if((sendCCSIDInt = Integer.valueOf(sendCCSID).intValue()) <= 0)
sendCCSIDInt = default_ccsid;
if(vrm_ < JDUtilities.vrm530 && sendCCSIDInt == 1200)
sendCCSIDInt = default_ccsid;
} catch(Exception e) {
sendCCSIDInt = default_ccsid;
}
}
packageCCSID_Converter = ConvTable.getTable(sendCCSIDInt, null);
properties_.setString(JDProperties.PACKAGE_CCSID, (new Integer(sendCCSIDInt)).toString());
request.setClientCCSID(sendCCSIDInt);
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "Client CCSID = " + sendCCSIDInt);
//Bidi-HCG end
// This language feature code is used to tell the
// system what language to send error messages in.
// If that language is not installed on the system,
// we get messages back in the default language that
// was installed on the system.
//
String nlv = as400_.getNLV(); // @F1C
request.setLanguageFeatureCode(nlv); // @EDC
if (JDTrace.isTraceOn ())
JDTrace.logInformation (this, "Setting server NLV = " + nlv);
String clientFunctionalLevel = CLIENT_FUNCTIONAL_LEVEL_;
request.setClientFunctionalLevel(clientFunctionalLevel); // @EDC
if (JDTrace.isTraceOn ()) // @EDC
JDTrace.logInformation (this, "Client functional level = " + CLIENT_FUNCTIONAL_LEVEL_); // @EDC
// Sort sequence.
// Moved below.. This must be set after setting the IASP, since the
// table may be on the IASP. @M6C
/*
if (! properties_.equals (JDProperties.SORT, JDProperties.SORT_HEX)) //@pdc only send if not default (hex)
{
JDSortSequence sortSequence = new JDSortSequence (
properties_.getString (JDProperties.SORT),
properties_.getString (JDProperties.SORT_LANGUAGE),
properties_.getString (JDProperties.SORT_TABLE),
properties_.getString (JDProperties.SORT_WEIGHT));
request.setNLSSortSequence (sortSequence.getType (),
sortSequence.getTableFile (),
sortSequence.getTableLibrary (),
sortSequence.getLanguageId (),
tempConverter);
}
*/
request.setTranslateIndicator (0xF0); // @E2C
request.setDRDAPackageSize (1);
//Note: newAutoCommitSupport is trueAutoCommitSupport
if(!(newAutoCommitSupport_ == 0)) //@KBA V5R3 or greater so run with new support
{ //@AC1
if(properties_.getBoolean(JDProperties.AUTO_COMMIT)) //@AC1
request.setAutoCommit(0xE8); //@KBA Turn on auto commit
else //@AC1
request.setAutoCommit(0xD5); //@AC1
} //@AC1
if((newAutoCommitSupport_ == 1) && (properties_.getBoolean(JDProperties.AUTO_COMMIT))) //@KBA //@AC1 (only set to *NONE if autocommit is on)
request.setCommitmentControlLevelParserOption(0); //@KBA Run under *NONE when in autocommit
else //@KBA Run under default isolation level
request.setCommitmentControlLevelParserOption (transactionManager_.getCommitMode ());
// Server attributes based on property values.
// These all match the index within the property's
// choices.
dateFormat = properties_.getIndex (JDProperties.DATE_FORMAT);
if (dateFormat != -1)
request.setDateFormatParserOption (dateFormat);
dateSeparator = properties_.getIndex (JDProperties.DATE_SEPARATOR);
if (dateSeparator != -1)
request.setDateSeparatorParserOption (dateSeparator);
timeFormat = properties_.getIndex (JDProperties.TIME_FORMAT);
if (timeFormat != -1)
request.setTimeFormatParserOption (timeFormat);
timeSeparator = properties_.getIndex (JDProperties.TIME_SEPARATOR);
if (timeSeparator != -1)
request.setTimeSeparatorParserOption (timeSeparator);
decimalSeparator = properties_.getIndex (JDProperties.DECIMAL_SEPARATOR);
if (decimalSeparator != -1)
request.setDecimalSeparatorParserOption (decimalSeparator);
request.setNamingConventionParserOption (properties_.getIndex (JDProperties.NAMING));
// Set the ignore decimal data error parser option.
decimalDataErrors = properties_.getIndex (JDProperties.DECIMAL_DATA_ERRORS);
if (decimalDataErrors != -1)
request.setIgnoreDecimalDataErrorParserOption(decimalDataErrors);
// If the system supports RLE data compression, then use it. @ECA
// Otherwise, use the old-style data compression. @ECA
if (properties_.getBoolean(JDProperties.DATA_COMPRESSION))
{ // @ECA
if (vrm_ >= JDUtilities.vrm510)
{ // @ECA
dataCompression_ = DATA_COMPRESSION_RLE_; // @ECA
request.setDataCompressionOption(0); // @ECA
if (JDTrace.isTraceOn ()) // @ECA
JDTrace.logInformation (this, "Data compression = RLE"); // @ECA
} // @ECA
else
{ // @ECA
dataCompression_ = DATA_COMPRESSION_OLD_; // @ECA
request.setDataCompressionOption(1); // @D3A @ECC
if (JDTrace.isTraceOn ()) // @ECA
JDTrace.logInformation (this, "Data compression = old"); // @ECA
} // @ECA
} // @ECA
else
{ // @ECA
dataCompression_ = DATA_COMPRESSION_NONE_; // @ECA
request.setDataCompressionOption(0); // @ECA
if (JDTrace.isTraceOn ()) // @ECA
JDTrace.logInformation (this, "Data compression = none"); // @ECA
} // @ECA
// Default SQL schema.
if (defaultSchema_ != null) {
request.setDefaultSQLLibraryName (defaultSchema_, libraryNameConverter);
}
// There is no need to tell the system what our code
// page is, nor is there any reason to get a translation
// table back from the system at this point. This
// will be handled later by the Converter class.
// I haven't found a good reason to set the ambiguous select
// option. ODBC sets it only when block criteria is "unless
// FOR UPDATE OF", but it causes some problems for JDBC.
// The difference is that ODBC has the luxury of setting cursor
// concurrency.
request.setPackageAddStatementAllowed (properties_.getBoolean (JDProperties.PACKAGE_ADD) ? 1 : 0);
// If the system is at V4R4 or later, then set some more attributes.
if (vrm_ >= JDUtilities.vrm440)
{ // @D0C @E9C
// @E9D || (FORCE_EXTENDED_FORMATS_)) {
if(vrm_ >= JDUtilities.vrm540) //@540 use new Super Extended Formats
request.setUseExtendedFormatsIndicator(0xF2); //@540
else //@540
request.setUseExtendedFormatsIndicator (0xF1);
// Although we publish a max lob threshold of 16777216, @E6A
// the system can only handle 15728640. We do it this @E6A
// way to match ODBC. @E6A
int lobThreshold = properties_.getInt (JDProperties.LOB_THRESHOLD); // @E6A
if (lobThreshold <= 0) // @E6A
request.setLOBFieldThreshold(0); // @E6A
else if (lobThreshold >= 15728640) // @E6A
request.setLOBFieldThreshold(15728640); // @E6A
else // @E6A
request.setLOBFieldThreshold(lobThreshold); // @E6C
extendedFormats_ = true;
}
// Set the default select statement type to be read-only (OS/400 v5r1
// and earlier the default was updatable). If the app requests updatable
// statements we will now specify "updatable" on the RPB. Do this
// only to V5R1 systems with the needed PTF, and V5R2 and later systems
// because they have the fix needed to support
// altering the cursor type in the RPB. (AmbiguousSelectOption(1)
// means read-only)
if (vrm_ >= JDUtilities.vrm520) // @J3a
{ // @J3a
request.setAmbiguousSelectOption(1); // @J3a
mustSpecifyForUpdate_ = false; // @J31a
if (vrm_ > JDUtilities.vrm740) {
request.setClientSupportInformation(0xF6000000);
if(JDTrace.isTraceOn()){
JDTrace.logInformation(this, "ROWID supported = true");
JDTrace.logInformation(this, "True auto-commit supported = true");
JDTrace.logInformation(this, "128 byte column names supported = true");
JDTrace.logInformation(this, "128 length schema names supported = true");
JDTrace.logInformation(this, "client support 0x04000000 set");
JDTrace.logInformation(this, "client support 0x02000000 multiple SQLCAs");
}
} else if(vrm_ >= JDUtilities.vrm710){ //@710 //@128sch
//@710 - Client support information - indicate our support for ROWID data type, true autocommit
// and 128 byte column names and 128 length schemas
request.setClientSupportInformation(0xF2000000);
if(JDTrace.isTraceOn()){
JDTrace.logInformation(this, "ROWID supported = true");
JDTrace.logInformation(this, "True auto-commit supported = true");
JDTrace.logInformation(this, "128 byte column names supported = true");
JDTrace.logInformation(this, "128 length schema names supported = true");
JDTrace.logInformation(this, "client support 0x02000000 multiple SQLCAs");
}
}
else if(vrm_ >= JDUtilities.vrm540){ //@540 for IBM i V5R4 and later, 128 byte column names are supported
//@540 - Client support information - indicate our support for ROWID data type, true autocommit
// and 128 byte column names
request.setClientSupportInformation(0xE0000000);
if(JDTrace.isTraceOn()){
JDTrace.logInformation(this, "ROWID supported = true");
JDTrace.logInformation(this, "True auto-commit supported = true");
JDTrace.logInformation(this, "128 byte column names supported = true");
}
}
else if (vrm_ >= JDUtilities.vrm530) //@KBA For IBM i V5R3 and later true auto commit support is supported.
{
// @KBA - Client support information - indicate our support for ROWID data type and
// true auto-commit
request.setClientSupportInformation(0xC0000000); //@KBC
if(JDTrace.isTraceOn()) //@KBA
{ //@KBA
JDTrace.logInformation(this, "ROWID supported = true"); //@KBA
JDTrace.logInformation(this, "True auto-commit supported = true"); //@KBA
} //@KBA
} //@KBA
else //@KBA
{ //@KBA
// @M0A - Client support information - indicate our support for ROWID data type
request.setClientSupportInformation(0x80000000);
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "ROWID supported = true");
} //@KBA
}
// @M0A - added support for 63 digit decimal precision
if(vrm_ >= JDUtilities.vrm530)
{
int maximumPrecision = properties_.getInt(JDProperties.MAXIMUM_PRECISION);
int maximumScale = properties_.getInt(JDProperties.MAXIMUM_SCALE);
int minimumDivideScale = properties_.getInt(JDProperties.MINIMUM_DIVIDE_SCALE);
// make sure that if scale is >31 we set precision to 63
// this is a requirement of host server to avoid a PWS0009
if(maximumScale > 31)
maximumPrecision = 63;
request.setDecimalPrecisionIndicators(maximumPrecision, maximumScale, minimumDivideScale);
if(JDTrace.isTraceOn())
{
JDTrace.logInformation(this, "Maximum decimal precision = " + maximumPrecision);
JDTrace.logInformation(this, "Maximum decimal scale = " + maximumScale);
JDTrace.logInformation(this, "Minimum divide scale = " + minimumDivideScale);
}
// @M0A - added support of hex constant parser option
int parserOption = properties_.getIndex(JDProperties.TRANSLATE_HEX);
if(parserOption != -1)
{
request.setHexConstantParserOption(parserOption);
if(JDTrace.isTraceOn())
{
String msg = (parserOption == 0) ? "Translate hex = character" : "Translate hex = binary";
JDTrace.logInformation(this, msg);
}
}
//@KBL - added support for hold/not hold locators
// Specifies whether input locators should be allocated as type hold locators or not hold locators.
// If the locators are of type hold, they will not be released when a commit is done.
boolean holdLocators = properties_.getBoolean(JDProperties.HOLD_LOCATORS);
if(!holdLocators) // Only need to set it if it is false, by default host server sets them to hold.
{
request.setInputLocatorType(0xD5);
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "Hold Locators = " + holdLocators);
}
//@KBL - added support for locator persistance. The JDBC specification says locators should be
// scoped to the transaction (ie. commit, rollback, or connection.close()) if auto commit is off
// host server added two options for the optional Locator Persistence ('3830'x') connection attribute:
// 0 -- Locators without the hold property are freed when cursor closed (locators scoped to the cursor).
// 1 -- Locators without the hold property are freed when the transaction is completed (locators scoped to the transaction).
//
// By default this is set to 0 by the host server, but to comply with the JDBC specification,
// we should always set it to 1.
// Note: this only applies when auto commit is off. The property has no effect if auto commit is on.
// Locators are always scoped to the cursor when auto-commit is on.
request.setLocatorPersistence(1);
}
//@540
if(vrm_ >= JDUtilities.vrm540){
//Set the query optimization goal
// 0 = Optimize query for first block of data (*ALLIO) when extended dynamic packages are used; Optimize query for entire result set (*FIRSTIO) when packages are not used (default) //@PDC update comment to reflect host server default
// 1 = Optimize query for first block of data (*FIRSTIO)
// 2 = Optimize query for entire result set (*ALLIO)
int queryOptimizeGoal = properties_.getInt (JDProperties.QUERY_OPTIMIZE_GOAL);
if(queryOptimizeGoal != 0){ // Only need to send if we are not using the default
if(queryOptimizeGoal == 1)
request.setQueryOptimizeGoal(0xC6);
else if(queryOptimizeGoal == 2)
request.setQueryOptimizeGoal(0xC1);
}
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "query optimize goal = " + queryOptimizeGoal);
}
//@X1A
int enableClientAffinitiesList = properties_.getInt(JDProperties.ENABLE_CLIENT_AFFINITIES_LIST);
if (enableClientAffinitiesList > 0) {
String alternateServers = properties_.getString(JDProperties.CLIENT_REROUTE_ALTERNATE_SERVER_NAME);
if (alternateServers == null || alternateServers.length() == 0 ) {
// Request the list from the server
request.setRequestAlternateServer(1);
}
}
//@550 Query Storage Limit Support
if(vrm_ >= JDUtilities.vrm610){
//Set the query storage limit
int queryStorageLimit = properties_.getInt(JDProperties.QUERY_STORAGE_LIMIT);
if(queryStorageLimit != -1) // Only need to send if we are not using the default of *NOMAX (-1)
{
if(queryStorageLimit < -1)
request.setQueryStorageLimit(-1);
else if(queryStorageLimit > AS400JDBCDataSource.MAX_STORAGE_LIMIT) // if larger than the max just set to max
request.setQueryStorageLimit(2147352578);
else
request.setQueryStorageLimit(queryStorageLimit);
}
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "query storage limit = " + queryStorageLimit);
}
if (JDTrace.isTraceOn ())
{
if (extendedFormats_)
JDTrace.logInformation (this, "Using extended datastreams");
else
JDTrace.logInformation (this, "Using original datastreams");
}
// Send an RDB name to the system only if connecting to
// v5r2 and newer versions of IBM i
if (vrm_ >= JDUtilities.vrm520) // @J2a
{
// @J2a
StringBuffer RDBName = new StringBuffer(properties_.getString (JDProperties.DATABASE_NAME)); // @J2a
if (RDBName.length() > 0) // @J2a
{
// @J2a
RDBName.append(" "); // @J2a
RDBName.setLength(18); // @J2a
request.setRDBName(RDBName.toString().toUpperCase(), ccsid37Converter); // @J2a
if (JDTrace.isTraceOn ()) // @J2a
JDTrace.logInformation (this, "RDB Name = -->" + RDBName + "<--"); // @J2a
} // @J2a
} // @J2a
// Set the sort table after setting the RDB name @M6M
// This allows the used of a sort table in the IASP
// Sort sequence.
if (! properties_.equals (JDProperties.SORT, JDProperties.SORT_HEX)) //@pdc only send if not default (hex)
{
JDSortSequence sortSequence = new JDSortSequence (
properties_.getString (JDProperties.SORT),
properties_.getString (JDProperties.SORT_LANGUAGE),
properties_.getString (JDProperties.SORT_TABLE),
properties_.getString (JDProperties.SORT_WEIGHT));
request.setNLSSortSequence (sortSequence.getType (),
sortSequence.getTableFile (),
sortSequence.getTableLibrary (),
sortSequence.getLanguageId (),
ccsid37Converter);
}
//@PDA 550 client interface info settings
//These three settings cannot be updated by user apps.
//This gives driver information to host server for any logging or future diagnostics.
if (vrm_ >= JDUtilities.vrm610)
{
//these strings are not mri translated for future diagnostic tools, searching etc on host server
request.setInterfaceType( "JDBC", ccsid37Converter);
request.setInterfaceName( "IBM Toolbox for Java", ccsid37Converter);
request.setInterfaceLevel( AS400JDBCDriver.DRIVER_LEVEL_, ccsid37Converter);
//@DFA 550 decfloat rounding mode
short roundingMode = 0; //@DFA
String roundingModeStr = properties_.getString(JDProperties.DECFLOAT_ROUNDING_MODE); //@DFA
if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_HALF_EVEN)) //@DFA
roundingMode = 0; //@DFA
else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_UP)) //@DFA
roundingMode = 6; //@DFA
else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_DOWN)) //@DFA
roundingMode = 2; //@DFA
else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_CEILING)) //@DFA
roundingMode = 3; //@DFA
else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_FLOOR)) //@DFA
roundingMode = 4; //@DFA
else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_HALF_UP)) //@DFA
roundingMode = 1; //@DFA
else if ( roundingModeStr.equals(JDProperties.DECFLOAT_ROUNDING_MODE_HALF_DOWN)) //@DFA
roundingMode = 5; //@DFA
//only need to send request if not default 0 (half even)
if(roundingMode != 0) //@DFA
request.setDecfloatRoundingMode(roundingMode); //@DFA
//@eof Close on EOF
request.setCloseEOF( 0xE8) ;
}
//@710
if (vrm_ >= JDUtilities.vrm710)
{
int car = properties_.getInt(JDProperties.CONCURRENT_ACCESS_RESOLUTION); //@cc1
if( !(properties_.getString(JDProperties.CONCURRENT_ACCESS_RESOLUTION)).equals( JDProperties.CONCURRENTACCESS_NOT_SET )) //@cc1
{ //@cc1
request.setConcurrentAccessResolution( car ); //@cc1
//Use instance variable to to "current setting".
//This will allow the Connection setting to override DataSource
//setting for future updates to this property from the Connection object. //@cc1
concurrentAccessResolution_ = car; //@cc1
} //@cc1
}
// Send the request and process the reply.
reply = sendAndReceive (request);
int errorClass = reply.getErrorClass();
int returnCode = reply.getReturnCode();
// Sort sequence attribute cannot be set.
if ((errorClass == 7)
&& ((returnCode == 301) || (returnCode == 303)))
postWarning (JDError.getSQLWarning (this, id_, errorClass, returnCode));
// Language feature code id was not changed. This is caused
// when the secondary language can not be added to the library
// list, and shows up as a PWS0003.
else if ((errorClass == 7) && (returnCode == 304))
postWarning (JDError.getSQLWarning (this, id_, errorClass, returnCode));
// -704 is RDB (IASP) does not exist. We do not go back to the system to get
// error info since they are sending an invalid attribute exception when the
// IASP is not found. We can create a better error than that.
else if ((errorClass == 7) && (returnCode == -704)) // @J2a
{ // @J2a
try // @J2a
{ // @J2a
close(); // @J2a
} // @J2a
catch (Exception e) {} // eat errors on close // @J2a
JDError.throwSQLException(this, JDError.EXC_RDB_DOES_NOT_EXIST); // @J2a
} // @J2a
// Other system errors.
else if (errorClass != 0)
JDError.throwSQLException (this, this, id_, errorClass, returnCode);
// Process the returned server attributes.
serverAttributes = reply.getServerAttributes ();
}
finally
{
if (request != null) {
request.returnToPool(); request = null;
}
// We cannot return the reply to the pool while it is still being used in the serverAttributes structure
// if (reply != null) reply.returnToPool();
}
// Check to see if we got back alternate server @X1A
String alternateServer = reply.getAlternateServer();
if (alternateServer != null && alternateServer.length() > 0) {
alternateServer_ = alternateServer;
} else {
alternateServer_ = null;
}
// The CCSID that comes back is a mixed CCSID (i.e. mixed
// SBCS and DBCS). This will be the CCSID that all
// non-graphic data will be returned as for this
// connection, so we own the converter here.
int serverCCSID = serverAttributes.getServerCCSID();
vrm_ = serverAttributes.getVRM();
//@P0D converter_ = ConverterImplRemote.getConverter (serverCCSID, as400_);
converter_ = ConvTable.getTable(serverCCSID, null); //@P0A
// If we did not user the signon server, fix the signon information
// in the as400 object. /*@V1A*/
if (as400PublicClassObj_ != null) {
if (as400PublicClassObj_.skipSignonServer) {
as400PublicClassObj_.setSignonInfo(serverCCSID, vrm_, as400_.getUserId()) ;
}
}
// Get the server functional level. It comes back as in the @E7A
// format VxRxMx9999. @E7A
String serverFunctionalLevelAsString = serverAttributes.getServerFunctionalLevel(converter_); // @E7A
try
{ // @E7A
serverFunctionalLevel_ = Integer.parseInt(serverFunctionalLevelAsString.substring(6)); // @E7A
} // @E7A
catch (NumberFormatException e)
{ // @E7A
serverFunctionalLevel_ = 0; // @E7A
} // @E7A
// Get the job number, but only if . @E8A
if (serverFunctionalLevel_ >= 5) // @E8A
serverJobIdentifier_ = serverAttributes.getServerJobIdentifier(converter_); // @E8A
// User no longer needs to specify "for update" on their SQL
// statements if running to v5r1 with a PTF. (V5R2 and later
// is handled in another piece of code)
if ((vrm_ == JDUtilities.vrm510) && //@J31a
( serverFunctionalLevel_ >= 10)) //@J31a
mustSpecifyForUpdate_ = false; //@J31a
if (JDTrace.isTraceOn ())
{ // @C2C
int v = (vrm_ & 0xffff0000) >>> 16; // @D1A
int r = (vrm_ & 0x0000ff00) >>> 8; // @D1A
int m = (vrm_ & 0x000000ff); // @D1A
JDTrace.logInformation (this, "JDBC driver major version = " // @C2A
+ AS400JDBCDriver.MAJOR_VERSION_); // @C2A
//Check version - V5R2 and earlier run on OS/400, V5R3 and later run on IBM i
if(((v==5) && (r>=3)) || (v>5))
JDTrace.logInformation(this, "IBM i VRM = V" + v
+ "R" + r + "M" + m);
else
JDTrace.logInformation (this, "OS/400 VRM = V" + v // @C2A
+ "R" + r + "M" + m); // @C2A
JDTrace.logInformation (this, "Server CCSID = " + serverCCSID);
JDTrace.logInformation(this, "Server functional level = " // @E7A
+ serverFunctionalLevelAsString // @E7A
+ " (" + serverFunctionalLevel_ + ")"); // @E7A
StringBuffer buffer = new StringBuffer(); // @E8A
if (serverJobIdentifier_ == null) // @E8A
buffer.append("Not available"); // @E8A
else
{ // @E8A
buffer.append(serverJobIdentifier_.substring(20, 26).trim()); // job number // @E8A
buffer.append('/'); // @E8A
buffer.append(serverJobIdentifier_.substring(10, 20).trim()); // user name // @E8A
buffer.append('/'); // @E8A
buffer.append(serverJobIdentifier_.substring(0, 10).trim()); // job name // @E8A
} // @E8A
JDTrace.logInformation(this, "Server job identifier = " + buffer); // @E8A
} // @C2A
// @E2D // Wait to load graphic converter until it is needed.
// @E2D graphicConverter_ = null;
// @E2D graphicConverterLoaded_ = false;
// Get the catalog name from the RDB entry. If no RDB entry is
// set on the system, then use the system name from the AS400 object
// (which originally came from the URL).
String rdbEntry = serverAttributes.getRelationalDBName (converter_).trim();
if ((rdbEntry.length() > 0) && (! rdbEntry.equalsIgnoreCase ("*N")))
catalog_ = rdbEntry;
// In the cases where defaults come from the server
// job, get the defaults for properties that were not set.
if (decimalSeparator == -1)
{
switch (serverAttributes.getDecimalSeparatorPO ())
{
case 0:
properties_.setString (JDProperties.DECIMAL_SEPARATOR, JDProperties.DECIMAL_SEPARATOR_PERIOD);
break;
case 1:
properties_.setString (JDProperties.DECIMAL_SEPARATOR, JDProperties.DECIMAL_SEPARATOR_COMMA);
break;
}
}
if (dateFormat == -1)
{
switch (serverAttributes.getDateFormatPO ())
{
case 0:
properties_.setString (JDProperties.DATE_FORMAT, JDProperties.DATE_FORMAT_JULIAN);
break;
case 1:
properties_.setString (JDProperties.DATE_FORMAT, JDProperties.DATE_FORMAT_MDY);
break;
case 2:
properties_.setString (JDProperties.DATE_FORMAT, JDProperties.DATE_FORMAT_DMY);
break;
case 3:
properties_.setString (JDProperties.DATE_FORMAT, JDProperties.DATE_FORMAT_YMD);
break;
case 4:
properties_.setString (JDProperties.DATE_FORMAT, JDProperties.DATE_FORMAT_USA);
break;
case 5:
properties_.setString (JDProperties.DATE_FORMAT, JDProperties.DATE_FORMAT_ISO);
break;
case 6:
properties_.setString (JDProperties.DATE_FORMAT, JDProperties.DATE_FORMAT_EUR);
break;
case 7:
properties_.setString (JDProperties.DATE_FORMAT, JDProperties.DATE_FORMAT_JIS);
break;
}
}
if (dateSeparator == -1)
{
switch (serverAttributes.getDateSeparatorPO ())
{
case 0:
properties_.setString (JDProperties.DATE_SEPARATOR, JDProperties.DATE_SEPARATOR_SLASH);
break;
case 1:
properties_.setString (JDProperties.DATE_SEPARATOR, JDProperties.DATE_SEPARATOR_DASH);
break;
case 2:
properties_.setString (JDProperties.DATE_SEPARATOR, JDProperties.DATE_SEPARATOR_PERIOD);
break;
case 3:
properties_.setString (JDProperties.DATE_SEPARATOR, JDProperties.DATE_SEPARATOR_COMMA);
break;
case 4:
properties_.setString (JDProperties.DATE_SEPARATOR, JDProperties.DATE_SEPARATOR_SPACE);
break;
}
}
if (timeFormat == -1)
{
switch (serverAttributes.getTimeFormatPO ())
{
case 0:
properties_.setString (JDProperties.TIME_FORMAT, JDProperties.TIME_FORMAT_HMS);
break;
case 1:
properties_.setString (JDProperties.TIME_FORMAT, JDProperties.TIME_FORMAT_USA);
break;
case 2:
properties_.setString (JDProperties.TIME_FORMAT, JDProperties.TIME_FORMAT_ISO);
break;
case 3:
properties_.setString (JDProperties.TIME_FORMAT, JDProperties.TIME_FORMAT_EUR);
break;
case 4:
properties_.setString (JDProperties.TIME_FORMAT, JDProperties.TIME_FORMAT_JIS);
break;
}
}
if (timeSeparator == -1)
{
switch (serverAttributes.getTimeSeparatorPO ())
{
case 0:
properties_.setString (JDProperties.TIME_SEPARATOR, JDProperties.TIME_SEPARATOR_COLON);
break;
case 1:
properties_.setString (JDProperties.TIME_SEPARATOR, JDProperties.TIME_SEPARATOR_PERIOD);
break;
case 2:
properties_.setString (JDProperties.TIME_SEPARATOR, JDProperties.TIME_SEPARATOR_COMMA);
break;
case 3:
properties_.setString (JDProperties.TIME_SEPARATOR, JDProperties.TIME_SEPARATOR_SPACE);
break;
}
}
}
catch (DBDataStreamException e)
{
JDError.throwSQLException (this, JDError.EXC_INTERNAL, e);
}
// @J5D catch (IOException e) {
catch (UnsupportedEncodingException e)
{ // @J5C
JDError.throwSQLException (this, JDError.EXC_INTERNAL, e);
}
finally
{
// Don't return the reply to the pool until the very end,
// as it is used by the DBReplyServerAttributes object
if (reply != null) { reply.returnToPool(); reply = null; }
}
}
//@A3A
// Implementation note: Don't use this object internally because we could be running in a proxy environment
// The purpose of this method is to simply hold the full AS400 object so it can be retrieved from the Connection
public void setSystem (AS400 as400)
throws SQLException // @EGA
{
as400PublicClassObj_ = as400;
}
// @D2C
/**
Sets the transaction isolation level. The transaction
isolation level cannot be changed while in the middle of
a transaction.
JDBC and DB2 for IBM i use different terminology for transaction
isolation levels. The following table provides a terminology
mapping:
IBM i isolation level JDBC transaction isolation level
*CHG TRANSACTION_READ_UNCOMMITTED
*CS TRANSACTION_READ_COMMITTED
*ALL TRANSACTION_READ_REPEATABLE_READ
*RR TRANSACTION_SERIALIZABLE
@param level The transaction isolation level. Possible
values are:
- TRANSACTION_READ_UNCOMMITTED
- TRANSACTION_READ_COMMITTED
- TRANSACTION_REPEATABLE_READ
- TRANSACTION_SERIALIZABLE
@exception SQLException If the connection is not open,
the input level is not valid
or unsupported, or a transaction
is active.
**/
public void setTransactionIsolation (int level)
throws SQLException
{
checkOpen ();
transactionManager_.setIsolation (level);
if (JDTrace.isTraceOn())
JDTrace.logProperty (this, "setTransactionIsolation", "Transaction isolation", transactionManager_.getIsolation ());
}
// JDBC 2.0
/**
Sets the type map to be used for distinct and structured
types.
Note: Distinct types are supported by DB2 for IBM i, but
are not externalized by the IBM Toolbox for Java JDBC driver.
In other words, distinct types behave as if they are the underlying
type. Structured types are not supported by DB2 for IBM i.
Consequently, this driver does not support the type map.
@param typeMap The type map.
@exception SQLException This exception is always thrown.
**/
public void setTypeMap (Map typeMap)
throws SQLException
{
JDError.throwSQLException (this, JDError.EXC_FUNCTION_NOT_SUPPORTED);
}
/**
Returns the connection's catalog name. This is the
name of the IBM i system.
@return The catalog name.
**/
public String toString ()
{
return catalog_;
}
/**
Indicates if the connection is using extended formats.
@return true if the connection is using extended formats, false
otherwise.
**/
public boolean useExtendedFormats ()
throws SQLException // @EGA
{
return extendedFormats_;
}
//@pda jdbc40
public String[] getValidWrappedList()
{
return new String[] { "com.ibm.as400.access.AS400JDBCConnection", "java.sql.Connection" };
}
//@PDA jdbc40
//JDBC40DOC /**
//JDBC40DOC * Returns true if the connection has not been closed and is still valid.
//JDBC40DOC * The driver shall submit a query on the connection or use some other
//JDBC40DOC * mechanism that positively verifies the connection is still valid when
//JDBC40DOC * this method is called.
//JDBC40DOC *
//JDBC40DOC * The query submitted by the driver to validate the connection shall be
//JDBC40DOC * executed in the context of the current transaction.
//JDBC40DOC *
//JDBC40DOC * @param timeout - The time in seconds to wait for the database operation
//JDBC40DOC * used to validate the connection to complete. If
//JDBC40DOC * the timeout period expires before the operation
//JDBC40DOC * completes, this method returns false. A value of
//JDBC40DOC * 0 indicates a timeout is not applied to the
//JDBC40DOC * database operation.
//JDBC40DOC *
//JDBC40DOC * @return true if the connection is valid, false otherwise
//JDBC40DOC * @exception SQLException if a database access error occurs.
//JDBC40DOC */
/* ifdef JDBC40
public boolean isValid(int timeout) throws SQLException
{
DBSQLRequestDS request = null;
DBReplyRequestedDS reply = null;
int errorClass = 0;
int returnCode = 0;
ReentrantLock lock = new ReentrantLock();
// Return exception if timeout is less than 0.. @D6A
if (timeout < 0) {
JDError.throwSQLException( this, JDError.EXC_ATTRIBUTE_VALUE_INVALID);
}
try
{
// inner class to run timer in sep thread
class CommTimer implements Runnable
{
Thread otherThread;
ReentrantLock lock;
int timeout;
public void run()
{
try
{
Thread.sleep(timeout * 1000);
lock.lockInterruptibly(); //lock, so only one thread can call interrupt
otherThread.interrupt();
lock.unlock();
}catch(InterruptedException ie)
{
//interrupted from notifyThread because request/reply is done. just return from run()
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Connection.isValid timer interrupted and stopped");
}
}
public CommTimer(Thread otherThread, int timeout, ReentrantLock lock )
{
this.otherThread = otherThread;
this.timeout = timeout;
this.lock = lock;
}
};
CommTimer timer = null;
Thread t = null;
// Only use timeout if > 0. @D6A
if (timeout > 0) {
timer = new CommTimer( Thread.currentThread(), timeout, lock); //pass in ref to main thread so timer can interrupt if blocked on IO
t = new Thread(timer);
t.start(); //sleeps for timeout and then interrupts main thread if it is still blocked on IO
}
try
{
request = DBDSPool.getDBSQLRequestDS(DBSQLRequestDS.FUNCTIONID_TEST_CONNECTION, id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA, 0);
reply = sendAndReceive(request);
lock.lockInterruptibly(); //lock, so only one thread can call interrupt
if (t != null) t.interrupt(); //stop timer thread @D6C
lock.unlock();
errorClass = reply.getErrorClass();
returnCode = reply.getReturnCode();
} catch(Exception ex) {
try {
// Make sure timeout thread is stopped @D6A
lock.lockInterruptibly(); //lock, so only one thread can call interrupt
if (t != null) t.interrupt(); //stop timer thread
lock.unlock();
} catch (Exception ex2) {
}
//interruptedException is wrapped in sqlException
//if exception occurs, just return false since connection is not valid
//this happens if timer ends before sendAndReceive returns
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Connection.isValid timed out or could not verify valid connection");
return false;
}
if(errorClass == 7 && returnCode == -201)
return true;
else
return false;
}
catch(Exception e)
{
//implmentation note: if any exception happens, just return false, since conn is not valid
return false;
}
finally
{
if (request != null) {
request.returnToPool(); request = null;
}
if (reply != null) {
reply.returnToPool(); reply = null; // commented out code
}
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "Connection.isValid call complete");
}
}
endif */
//@PDA 550 client info
/**
* Sets the value of the client info property specified by name to the
* value specified by value.
*
* Applications may use the DatabaseMetaData.getClientInfoProperties
* method to determine the client info properties supported by the driver
* and the maximum length that may be specified for each property.
*
* The driver stores the value specified in a suitable location in the
* database. For example in a special register, session parameter, or
* system table column. For efficiency the driver may defer setting the
* value in the database until the next time a statement is executed or
* prepared. Other than storing the client information in the appropriate
* place in the database, these methods shall not alter the behavior of
* the connection in anyway. The values supplied to these methods are
* used for accounting, diagnostics and debugging purposes only.
*
* The driver shall generate a warning if the client info name specified
* is not recognized by the driver.
*
* If the value specified to this method is greater than the maximum
* length for the property the driver may either truncate the value and
* generate a warning or generate a SQLException
. If the driver
* generates a SQLException
, the value specified was not set on the
* connection.
*
* The following client info properties are supported in Toobox for Java.
*
* - ApplicationName - The name of the application currently utilizing
* the connection
* - ClientUser - The name of the user that the application using
* the connection is performing work for. This may
* not be the same as the user name that was used
* in establishing the connection.
* - ClientHostname - The hostname of the computer the application
* using the connection is running on.
* - ClientAccounting - Client accounting information.
* - ClientProgramID - The client program identification.
*
*
* @param name The name of the client info property to set
* @param value The value to set the client info property to. If the
* value is null, the current value of the specified
* property is cleared.
*
//JDBC40DOC * @throws SQLClientInfoException if the database returns an error while
//JDBC40DOC * setting the client info value on the database server.
*/
public void setClientInfo(String name, String value)
/* ifdef JDBC40
throws SQLClientInfoException
endif */
/* ifndef JDBC40 */
throws SQLException
/* endif */
{
DBSQLAttributesDS request = null;
DBReplyRequestedDS setClientInfoReply = null;
ConvTable tempConverter = null;
String oldValue = null; //save in case we get error from host db
// in order to reset if null value is passed in, use empty string
if (value == null)
value = "";
try
{
if (getVRM() >= JDUtilities.vrm610)
{
request = DBDSPool.getDBSQLAttributesDS(DBSQLAttributesDS.FUNCTIONID_SET_ATTRIBUTES, id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA + DBBaseRequestDS.ORS_BITMAP_SERVER_ATTRIBUTES, 0);
tempConverter = ConvTable.getTable(as400_.getCcsid(), null);
}
if (name.equals(applicationNamePropertyName_))
{
oldValue = applicationName_;
applicationName_ = value;
if (request != null )
request.setClientInfoApplicationName(value, tempConverter);
} else if (name.equals(clientUserPropertyName_))
{
oldValue = clientUser_;
clientUser_ = value;
if (request != null )
request.setClientInfoClientUser(value, tempConverter);
} else if (name.equals(clientAccountingPropertyName_))
{
oldValue = clientAccounting_;
clientAccounting_ = value;
if (request != null )
request.setClientInfoClientAccounting(value, tempConverter);
} else if (name.equals(clientHostnamePropertyName_))
{
oldValue = clientHostname_;
clientHostname_ = value;
if (request != null)
request.setClientInfoClientHostname(value, tempConverter);
} else if (name.equals(clientProgramIDPropertyName_)) //@PDA add block for ProgramID
{
oldValue = clientProgramID_;
clientProgramID_ = value;
if (request != null)
request.setClientInfoProgramID(value, tempConverter);
} else
{
oldValue = null;
// post generic syntax error for invalid clientInfo name
postWarning(JDError.getSQLWarning(JDError.EXC_SYNTAX_ERROR));
}
if ((getVRM() >= JDUtilities.vrm610) && (oldValue != null))
{
setClientInfoReply = sendAndReceive(request);
int errorClass = setClientInfoReply.getErrorClass();
//throw SQLException
if (errorClass != 0)
JDError.throwSQLException(this, this, id_, errorClass, setClientInfoReply.getReturnCode());
}
} catch (Exception e)
{
//reset old value
if (name.equals(applicationNamePropertyName_))
applicationName_ = oldValue;
else if (name.equals(clientUserPropertyName_))
clientUser_ = oldValue;
else if (name.equals(clientAccountingPropertyName_))
clientAccounting_ = oldValue;
else if (name.equals(clientHostnamePropertyName_))
clientHostname_ = oldValue;
else if (name.equals(clientProgramIDPropertyName_)) //@pda
clientProgramID_ = oldValue;
/* ifdef JDBC40
//@PDD jdbc40 merge HashMap m = new HashMap();
HashMap m = new HashMap();
m.put(name, ClientInfoStatus.REASON_UNKNOWN);
JDError.throwSQLClientInfoException( this, JDError.EXC_INTERNAL, e, m );
endif */
/* ifndef JDBC40 */
JDError.throwSQLException( this, JDError.EXC_INTERNAL, e);
/* endif */
} finally
{
if (request != null) {
request.returnToPool(); request = null;
}
if (setClientInfoReply != null) {
setClientInfoReply.returnToPool(); setClientInfoReply = null; // only error class used
}
}
}
//@PDA 550 client info
/**
* Sets the value of the connection's client info properties. The
* Properties
object contains the names and values of the
* client info properties to be set. The set of client info properties
* contained in the properties list replaces the current set of client info
* properties on the connection. If a property that is currently set on the
* connection is not present in the properties list, that property is
* cleared. Specifying an empty properties list will clear all of the
* properties on the connection. See
* setClientInfo (String, String)
for more information.
*
* If an error occurs in setting any of the client info properties, a
* ClientInfoException
is thrown. The
* ClientInfoException
contains information indicating which
* client info properties were not set. The state of the client information
* is unknown because some databases do not allow multiple client info
* properties to be set atomically. For those databases, one or more
* properties may have been set before the error occurred.
*
*
* The following client info properties are supported in Toobox for Java.
*
* - ApplicationName - The name of the application currently utilizing
* the connection
* - ClientUser - The name of the user that the application using
* the connection is performing work for. This may
* not be the same as the user name that was used
* in establishing the connection.
* - ClientHostname - The hostname of the computer the application
* using the connection is running on.
* - ClientAccounting - Client accounting information.
* - ClientProgramID - The client program identification.
*
*
*
* @param properties
* the list of client info properties to set
*
//JDBC40DOC * @throws SQLClientInfoException If there is a problem with the Client Info.
//JDBC40DOC * if the database returns an error while setting the
//JDBC40DOC * clientInfo values on the database
*
*/
public void setClientInfo(Properties properties)
/* ifdef JDBC40
throws SQLClientInfoException
endif */
/* ifndef JDBC40 */
throws SQLException
/* endif */
{
String newApplicationName = properties.getProperty(applicationNamePropertyName_);
String newClientHostname = properties.getProperty(clientHostnamePropertyName_);
String newClientUser = properties.getProperty(clientUserPropertyName_);
String newClientAccounting = properties.getProperty(clientAccountingPropertyName_);
String newClientProgramID = properties.getProperty(clientProgramIDPropertyName_); //@pda
//In order to reset if null value is passed in, use empty string
//per javadoc, clear its value if not specified in properties
if (newApplicationName == null)
newApplicationName = "";
if (newClientHostname == null)
newClientHostname = "";
if (newClientUser == null)
newClientUser = "";
if (newClientAccounting == null)
newClientAccounting = "";
if (newClientProgramID == null) //@PDA
newClientProgramID = "";
DBSQLAttributesDS request = null;
DBReplyRequestedDS setClientInfoReply = null;
ConvTable tempConverter = null;
try
{
if (getVRM() >= JDUtilities.vrm610)
{
request = DBDSPool.getDBSQLAttributesDS(DBSQLAttributesDS.FUNCTIONID_SET_ATTRIBUTES, id_, DBBaseRequestDS.ORS_BITMAP_RETURN_DATA + DBBaseRequestDS.ORS_BITMAP_SERVER_ATTRIBUTES, 0);
tempConverter = ConvTable.getTable(as400_.getCcsid(), null);
request.setClientInfoApplicationName(newApplicationName, tempConverter);
request.setClientInfoClientUser(newClientUser, tempConverter);
request.setClientInfoClientAccounting(newClientAccounting, tempConverter);
request.setClientInfoClientHostname(newClientHostname, tempConverter);
request.setClientInfoProgramID(newClientProgramID, tempConverter); //@pda
setClientInfoReply = sendAndReceive(request);
int errorClass = setClientInfoReply.getErrorClass();
if (errorClass != 0)
JDError.throwSQLException(this, this, id_, errorClass, setClientInfoReply.getReturnCode());
}
//update local values after request/reply in case of exception
applicationName_ = newApplicationName;
clientHostname_ = newClientHostname;
clientUser_ = newClientUser;
clientAccounting_ = newClientAccounting;
clientProgramID_ = newClientProgramID;
} catch( Exception e)
{
/* ifdef JDBC40
//create Map for exception constructor
//@PDD jdbc40 merge HashMap m = new HashMap();
HashMap m = new HashMap();
Enumeration clientInfoNames = properties.keys();
while( clientInfoNames.hasMoreElements())
{
String clientInfoName = (String)clientInfoNames.nextElement();
m.put(clientInfoName, ClientInfoStatus.REASON_UNKNOWN);
}
JDError.throwSQLClientInfoException( this, JDError.EXC_INTERNAL, e, m);
endif */
/* ifndef JDBC40 */
JDError.throwSQLException( this, JDError.EXC_INTERNAL, e);
/* endif */
} finally
{
if (request != null) {
request.returnToPool(); request = null;
}
if (setClientInfoReply != null) {
setClientInfoReply.returnToPool(); setClientInfoReply=null; // only error class used
}
}
}
//@PDA 550 client info
/**
* Returns the value of the client info property specified by name. This
* method may return null if the specified client info property has not
* been set and does not have a default value. This method will also
* return null if the specified client info property name is not supported
* by the driver.
*
* Applications may use the DatabaseMetaData.getClientInfoProperties
* method to determine the client info properties supported by the driver.
*
*
* The following client info properties are supported in Toobox for Java.
*
* - ApplicationName - The name of the application currently utilizing
* the connection
* - ClientUser - The name of the user that the application using
* the connection is performing work for. This may
* not be the same as the user name that was used
* in establishing the connection.
* - ClientHostname - The hostname of the computer the application
* using the connection is running on.
* - ClientAccounting - Client accounting information.
* - ClientProgramID - The client program identification.
*
*
* @param name The name of the client info property to retrieve
*
* @return The value of the client info property specified
*
* @throws SQLException if the database returns an error when
* fetching the client info value from the database.
*
* see java.sql.DatabaseMetaData#getClientInfoProperties
*/
public String getClientInfo(String name) throws SQLException
{
if (name.equals(applicationNamePropertyName_))
return applicationName_;
else if (name.equals(clientUserPropertyName_))
return clientUser_;
else if (name.equals(clientAccountingPropertyName_))
return clientAccounting_;
else if (name.equals(clientHostnamePropertyName_))
return clientHostname_;
else if (name.equals(clientProgramIDPropertyName_)) //@pda
return clientProgramID_;
else
{
//post generic syntax error for invalid clientInfo name
//since javadoc for setClientInfo(String,String) says to generate warning, we will do same here and return null
postWarning(JDError.getSQLWarning(JDError.EXC_SYNTAX_ERROR));
return null;
}
}
//@PDA 550 client info
/**
* Returns a list containing the name and current value of each client info
* property supported by the driver. The value of a client info property
* may be null if the property has not been set and does not have a
* default value.
*
*
* The following client info properties are supported in Toobox for Java.
*
* - ApplicationName - The name of the application currently utilizing
* the connection
* - ClientUser - The name of the user that the application using
* the connection is performing work for. This may
* not be the same as the user name that was used
* in establishing the connection.
* - ClientHostname - The hostname of the computer the application
* using the connection is running on.
* - ClientAccounting - Client accounting information.
* - ClientProgramID - The client program identification.
*
*
* @return A Properties
object that contains the name and current value of
* each of the client info properties supported by the driver.
*
* @throws SQLException if the database returns an error when
* fetching the client info values from the database
*/
public Properties getClientInfo() throws SQLException
{
Properties props = new Properties();
props.setProperty(applicationNamePropertyName_, applicationName_);
props.setProperty(clientAccountingPropertyName_, clientAccounting_);
props.setProperty(clientHostnamePropertyName_, clientHostname_);
props.setProperty(clientUserPropertyName_, clientUser_);
props.setProperty(clientProgramIDPropertyName_, clientProgramID_); //@pda
return props;
}
//@PDA jdbc40
/**
* Constructs an object that implements the Clob
interface. The object
* returned initially contains no data. The setAsciiStream
,
* setCharacterStream
and setString
methods of
* the Clob
interface may be used to add data to the Clob
.
* @return An object that implements the Clob
interface
* @throws SQLException if an object that implements the
* Clob
interface can not be constructed.
*
*/
public Clob createClob() throws SQLException
{
return new AS400JDBCClob("", AS400JDBCClob.MAX_LOB_SIZE);
}
//@PDA jdbc40
/**
* Constructs an object that implements the Blob
interface. The object
* returned initially contains no data. The setBinaryStream
and
* setBytes
methods of the Blob
interface may be used to add data to
* the Blob
.
* @return An object that implements the Blob
interface
* @throws SQLException if an object that implements the
* Blob
interface can not be constructed
*
*/
public Blob createBlob() throws SQLException
{
return new AS400JDBCBlob(new byte[0], AS400JDBCBlob.MAX_LOB_SIZE); //@pdc 0 len array
}
//@PDA jdbc40
//JDBC40DOC /**
//JDBC40DOC * Constructs an object that implements the NClob
interface. The object
//JDBC40DOC * returned initially contains no data. The setAsciiStream
,
//JDBC40DOC * setCharacterStream
and setString
methods of the NClob
interface may
//JDBC40DOC * be used to add data to the NClob
.
//JDBC40DOC * @return An object that implements the NClob
interface
//JDBC40DOC * @throws SQLException if an object that implements the
//JDBC40DOC * NClob
interface can not be constructed.
//JDBC40DOC *
//JDBC40DOC */
/*ifdef JDBC40
public NClob createNClob() throws SQLException
{
return new AS400JDBCNClob("", AS400JDBCNClob.MAX_LOB_SIZE);
}
endif */
//@PDA jdbc40
//JDBC40DOC /**
//JDBC40DOC * Constructs an object that implements the SQLXML
interface. The object
//JDBC40DOC * returned initially contains no data. The createXMLStreamWriter
object and
//JDBC40DOC * setString
method of the SQLXML
interface may be used to add data to the SQLXML
//JDBC40DOC * object.
//JDBC40DOC * @return An object that implements the SQLXML
interface
//JDBC40DOC * @throws SQLException if an object that implements the SQLXML
interface can not
//JDBC40DOC * be constructed
//JDBC40DOC */
/*ifdef JDBC40
public SQLXML createSQLXML() throws SQLException
{
return new AS400JDBCSQLXML(AS400JDBCSQLXML.MAX_XML_SIZE);
}
endif */
//@PDA //@array
/**
* Factory method for creating Array objects.
*
* @param typeName the SQL name of the type the elements of the array map to. The typeName is a
* database-specific name which may be the name of a built-in type, a user-defined type or a standard SQL type supported by this database. This
* is the value returned by Array.getBaseTypeName
* For Toolbox, the typeName will correspond to a typename in java.sql.Types.
*
* @param elements the elements that populate the returned object
* @return an Array object whose elements map to the specified SQL type
* @throws SQLException if a database error occurs, the typeName is null or this method is called on a closed connection
*/
public Array createArrayOf(String typeName, Object[] elements) throws SQLException
{
//@array
return new AS400JDBCArray(typeName, elements, this.vrm_, this);
}
//@PDA jdbc40
/**
* Factory method for creating Struct objects.
*
* @param typeName the SQL type name of the SQL structured type that this Struct
* object maps to. The typeName is the name of a user-defined type that
* has been defined for this database. It is the value returned by
* Struct.getSQLTypeName
.
* @param attributes the attributes that populate the returned object
* @return a Struct object that maps to the given SQL type and is populated with the given attributes
* @throws SQLException if a database error occurs, the typeName is null or this method is called on a closed connection
*/
public Struct createStruct(String typeName, Object[] attributes) throws SQLException
{
JDError.throwSQLException (this, JDError.EXC_FUNCTION_NOT_SUPPORTED);
return null;
}
//@2KRA
/**
* Starts or stops the Database Host Server trace for this connection.
* Note: This method is only supported when running to IBM i V5R3 or later
* and is ignored if you specified to turn on database host server tracing
* using the 'server trace' connection property.
* @param trace true to start database host server tracing, false to end it.
*/
public void setDBHostServerTrace(boolean trace){
try{
if(getVRM() >= JDUtilities.vrm530){
// See if tracing was specified by server trace property
// Server Job Trace
boolean traceServerJob = ((traceServer_ & ServerTrace.JDBC_TRACE_SERVER_JOB) > 0);
// Database Host Server Trace
boolean traceDatabaseHostServer = (((traceServer_ & ServerTrace.JDBC_TRACE_DATABASE_HOST_SERVER) > 0));
String serverJobIdentifier = getServerJobIdentifier();
boolean SQLNaming = properties_.getString(JDProperties.NAMING).equals(JDProperties.NAMING_SQL);
if(!traceDatabaseHostServer){ // database host server trace was not already started
if(trace) // user requested tracing be turned on
{
try{
if(getVRM() == JDUtilities.vrm530){ // run command for V5R3
JDUtilities.runCommand(this, "QSYS/STRTRC SSNID(QJT" +
serverJobIdentifier.substring(20) +
") JOB(*) MAXSTG(128000) JOBTRCTYPE(*TRCTYPE) " +
"TRCTYPE((TESTA *INFO))", SQLNaming);
}
else{ // run command for V5R4 and higher
JDUtilities.runCommand(this, "QSYS/STRTRC SSNID(QJT" +
serverJobIdentifier.substring(20) +
") JOB(*) MAXSTG(128000) JOBTRCTYPE(*TRCTYPE) " +
"TRCTYPE((*DBHSVR *INFO))", SQLNaming);
}
databaseHostServerTrace_ = true;
}catch(Exception e){
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to start database host server tracing failed, could not trace server job");
}
}
else // user requested tracing be turned off
{
// Only issue ENDTRC if not already done.
if(!traceServerJob) // turn off it we don't have to wait to turn off server job tracing
{
try{
JDUtilities.runCommand(this, "QSYS/ENDTRC SSNID(QJT" +
serverJobIdentifier.substring(20) +
") DTAOPT(*LIB) DTALIB(QUSRSYS) RPLDTA(*YES) PRTTRC(*YES)", SQLNaming );
JDUtilities.runCommand(this, "QSYS/DLTTRC DTAMBR(QJT" +
serverJobIdentifier.substring(20) +
") DTALIB(QUSRSYS)", SQLNaming );
databaseHostServerTrace_ = false;
}
catch(Exception e){
JDTrace.logDataEvenIfTracingIsOff(this, "Attempt to end database host server tracing failed.");
}
}
}
}
}
}catch(SQLException e){
if(JDTrace.isTraceOn())
JDTrace.logInformation(this, "Attempt to start/stop database host server tracing failed.");
}
}
//@A2A
public boolean doUpdateDeleteBlocking() {
return useBlockUpdate_;
}
// @A6A
public int getMaximumBlockedInputRows() {
return maximumBlockedInputRows_;
}
//JDBC40DOC /**
//JDBC40DOC * Terminates an open connection. Calling abort results in:
//JDBC40DOC *
//JDBC40DOC * - The connection marked as closed
//JDBC40DOC *
- Closes any physical connection to the database
//JDBC40DOC *
- Releases resources used by the connection
//JDBC40DOC *
- Insures that any thread that is currently accessing the connection will
//JDBC40DOC * either progress to completion or throw an SQLException.
//JDBC40DOC *
//JDBC40DOC *
//JDBC40DOC * Calling abort marks the connection closed and releases any resources.
//JDBC40DOC * Calling abort on a closed connection is a no-op.
//JDBC40DOC *
It is possible that the aborting and releasing of the resources that are
//JDBC40DOC * held by the connection can take an extended period of time.
//JDBC40DOC * When the abort method returns, the connection will have been marked as closed
//JDBC40DOC * and the Executor that was passed as a parameter to abort may still be executing
//JDBC40DOC * tasks to release resources.
//JDBC40DOC *
//JDBC40DOC * This method checks to see that there is an SQLPermission object before
//JDBC40DOC * allowing the method to proceed. If a SecurityManager exists and its
//JDBC40DOC * checkPermission method denies calling abort, this method throws a
//JDBC40DOC * java.lang.SecurityException.
//JDBC40DOC * @param executor The Executor implementation which will be used by abort.
//JDBC40DOC * @throws SQLException - if a database access error occurs or the executor is null
//JDBC40DOC * @throws SecurityException - if a security manager exists and its checkPermission
//JDBC40DOC * method denies calling abort
//JDBC40DOC */
/* ifdef JDBC40
public void abort(Executor executor) throws SQLException {
if (JDTrace.isTraceOn())
JDTrace.logInformation (this, "abort() called");
// Check for null executor
if (executor == null) {
JDError.throwSQLException(JDError.EXC_PARAMETER_TYPE_INVALID);
}
// Check for authority
SecurityManager security = System.getSecurityManager();
if (security != null) {
SQLPermission sqlPermission = new SQLPermission("callAbort");
security.checkPermission(sqlPermission);
}
// Calling on a close connection is a no-op
if (aborted_ || (server_ == null)) {
return;
}
//
// Mark the connection as aborted. Any call to closed will see that it is closed.
//
aborted_ = true;
//
// Prepare and start the executor to clean everything up.
//
Runnable runnable = new AS400JDBCConnectionAbortRunnable(this);
executor.execute(runnable);
}
endif */
/**
* Retrieves this Connection
object's current schema name.
* @return the current schema name or null if there is none
* @throws SQLException if a database access error occurs or this method is called on a closed connection
*/
public String getSchema() throws SQLException {
Statement s = createStatement();
String query;
boolean SQLNaming = properties_.getString(JDProperties.NAMING).equals(JDProperties.NAMING_SQL);
if (SQLNaming) {
query = "SELECT CURRENT SCHEMA FROM SYSIBM.SYSDUMMY1";
} else {
query = "SELECT CURRENT SCHEMA FROM SYSIBM/SYSDUMMY1";
}
ResultSet rs = s.executeQuery(query);
rs.next();
String schema = rs.getString(1);
rs.close();
s.close();
return schema;
}
/**
* Sets the maximum period a Connection or objects created from the
* Connection will wait for the database to reply to any one request. If
* any request remains unanswered, the waiting method will return with a
* SQLException, and the Connection or objects created from the
* Connection will be marked as closed. Any subsequent use of the objects,
* with the exception of the close, isClosed or Connection.isValid methods,
* will result in a SQLException.
*
*
In the JTOpen JDBC driver, this is implemented by setting the SoTimeout
* of the underlying socket.
*
Currently, setting the network timeout is only supported when the
* "thread used" property is false.
*
When the driver determines that the setNetworkTimeout timeout value
* has expired, the JDBC driver marks the connection closed and releases
* any resources held by the connection.
*
This method checks to see that there is an SQLPermission object before
* allowing the method to proceed.
* If a SecurityManager exists and its checkPermission method denies calling
* setNetworkTimeout, this method throws a java.lang.SecurityException.
*@param timeout - The time in milliseconds to wait for the database
* operation to complete. If the JDBC driver does not support milliseconds,
* the JDBC driver will round the value up to the nearest second.
* If the timeout period expires before the operation completes, a
* SQLException will be thrown. A value of 0 indicates that there is no
* timeout for database operations.
* @throws SQLException - if a database access error occurs, this method is
* called on a closed connection,or the value specified for seconds is less
* than 0.
* @throws SecurityException - if a security manager exists and its
* checkPermission method denies calling setNetworkTimeout.
* @see SecurityManager#checkPermission(java.security.Permission)
* @see Statement#setQueryTimeout(int)
* @see #getNetworkTimeout()
//JDBC40DOC * @see #abort(java.util.concurrent.Executor)
//JDBC40DOC * @see Executor
*/
public void setNetworkTimeout(int timeout) throws SQLException {
/* ifdef JDBC40
SecurityManager security = System.getSecurityManager();
if (security != null) {
SQLPermission sqlPermission = new SQLPermission("setNetworkTimeout");
security.checkPermission(sqlPermission);
}
endif */
// Make sure that the THREAD_USED property is false. The default is true
String threadUsedProperty = properties_.getString(JDProperties.THREAD_USED);
if (threadUsedProperty == null) {
if (timeout > 0 ) {
JDError.throwSQLException(JDError.EXC_FUNCTION_NOT_SUPPORTED,"thread used != false");
}
} else {
if (threadUsedProperty.equalsIgnoreCase("true")) {
if (timeout > 0 ) {
JDError.throwSQLException(JDError.EXC_FUNCTION_NOT_SUPPORTED,"thread used != false");
}
}
}
// Make sure value is not negative
if (timeout < 0) {
JDError.throwSQLException(JDError.EXC_PARAMETER_TYPE_INVALID);
}
// Calling on a closed connection is a no-op
checkOpen ();
try {
server_.setSoTimeout(timeout);
} catch (SocketException e) {
JDError.throwSQLException(JDError.EXC_COMMUNICATION_LINK_FAILURE, e);
}
}
/**
* Retrieves the number of milliseconds the driver will wait for a database request to complete. If the limit is exceeded, a SQLException is thrown.
* @return The current timeout limit in milliseconds; zero means there is no limit
* @throws SQLException - if a database access error occurs or this method is called on a closed Connection
* @since JTOpen 7.X
//JDBC40DOC * @see #setNetworkTimeout(java.util.concurrent.Executor, int)
*/
public int getNetworkTimeout() throws SQLException {
checkOpen ();
try {
return server_.getSoTimeout();
} catch (SocketException e) {
JDError.throwSQLException(JDError.EXC_COMMUNICATION_LINK_FAILURE, e);
return 0;
}
}
//JDBC40DOC /**
//JDBC40DOC * Sets the maximum period a Connection or objects created from the Connection will wait for the database to
//JDBC40DOC * reply to any one request. If any request remains unanswered, the waiting method will return with a
//JDBC40DOC * SQLException, and the Connection or objects created from the Connection will be marked as closed.
//JDBC40DOC * Any subsequent use of the objects, with the exception of the close, isClosed or Connection.isValid methods,
//JDBC40DOC * will result in a SQLException.
//JDBC40DOC *
Note: This method is intended to address a rare but serious condition where network partitions can
//JDBC40DOC * cause threads issuing JDBC calls to hang uninterruptedly in socket reads, until the OS TCP-TIMEOUT
//JDBC40DOC * (typically 10 minutes). This method is related to the abort() method which provides an administrator
//JDBC40DOC * thread a means to free any such threads in cases where the JDBC connection is accessible to the
//JDBC40DOC * administrator thread. The setNetworkTimeout method will cover cases where there is no administrator
//JDBC40DOC * thread, or it has no access to the connection. This method is severe in it's effects, and should be
//JDBC40DOC * given a high enough value so it is never triggered before any more normal timeouts,
//JDBC40DOC * such as transaction timeouts.
//JDBC40DOC *
JDBC driver implementations may also choose to support the setNetworkTimeout method to impose
//JDBC40DOC * a limit on database response time, in environments where no network is present.
//JDBC40DOC *
Drivers may internally implement some or all of their API calls with multiple internal driver-database
//JDBC40DOC * transmissions, and it is left to the driver implementation to determine whether the limit will be
//JDBC40DOC * applied always to the response to the API call, or to any single request made during the API call.
//JDBC40DOC *
This method can be invoked more than once, such as to set a limit for an area of JDBC code,
//JDBC40DOC * and to reset to the default on exit from this area. Invocation of this method has no impact on
//JDBC40DOC * already outstanding requests.
//JDBC40DOC *
The Statement.setQueryTimeout() timeout value is independent of the timeout value specified in
//JDBC40DOC * setNetworkTimeout. If the query timeout expires before the network timeout then the statement execution
//JDBC40DOC * will be canceled. If the network is still active the result will be that both the statement and connection
//JDBC40DOC * are still usable. However if the network timeout expires before the query timeout or if the statement timeout
//JDBC40DOC * fails due to network problems, the connection will be marked as closed, any resources held by the connection
//JDBC40DOC * will be released and both the connection and statement will be unusable.
//JDBC40DOC *
When the driver determines that the setNetworkTimeout timeout value has expired, the JDBC driver marks
//JDBC40DOC * the connection closed and releases any resources held by the connection.
//JDBC40DOC *
This method checks to see that there is an SQLPermission object before allowing the method to proceed.
//JDBC40DOC * If a SecurityManager exists and its checkPermission method denies calling setNetworkTimeout, this method
//JDBC40DOC * throws a java.lang.SecurityException.
//JDBC40DOC *@param executor - The Executor implementation which will be used by setNetworkTimeout.
//JDBC40DOC *@param milliseconds - The time in milliseconds to wait for the database operation to complete. If the
//JDBC40DOC * JDBC driver does not support milliseconds, the JDBC driver will round the value up to the nearest second.
//JDBC40DOC * If the timeout period expires before the operation completes, a SQLException will be thrown. A value of
//JDBC40DOC * 0 indicates that there is not timeout for database operations.
//JDBC40DOC * @throws SQLException - if a database access error occurs, this method is called on a closed connection,
//JDBC40DOC * the executor is null, or the value specified for seconds is less than 0.
//JDBC40DOC * @throws SecurityException - if a security manager exists and its checkPermission method denies calling
//JDBC40DOC * setNetworkTimeout.
//JDBC40DOC * @see SecurityManager#checkPermission(java.security.Permission)
//JDBC40DOC * @see Statement#setQueryTimeout(int)
//JDBC40DOC * @see #getNetworkTimeout()
//JDBC40DOC * @see #abort(java.util.concurrent.Executor)
//JDBC40DOC * @see Executor
//JDBC40DOC **/
/* ifdef JDBC40
public void setNetworkTimeout(Executor executor, int milliseconds)
throws SQLException {
// Make sure value is not negative
if (milliseconds < 0) {
JDError.throwSQLException(JDError.EXC_PARAMETER_TYPE_INVALID,"milliseconds<0");
}
// Check for null executor
if (executor == null) {
JDError.throwSQLException(JDError.EXC_PARAMETER_TYPE_INVALID,"executor=null");
}
// Check for authority
SecurityManager security = System.getSecurityManager();
if (security != null) {
SQLPermission sqlPermission = new SQLPermission("setNetworkTimeout");
security.checkPermission(sqlPermission);
}
// Make sure that the THREAD_USED property is false. The default is true
String threadUsedProperty = properties_.getString(JDProperties.THREAD_USED);
if (threadUsedProperty == null) {
if (milliseconds > 0 ) {
JDError.throwSQLException(JDError.EXC_FUNCTION_NOT_SUPPORTED,"thread used != false");
}
} else {
if (threadUsedProperty.equalsIgnoreCase("true")) {
if (milliseconds > 0 ) {
JDError.throwSQLException(JDError.EXC_FUNCTION_NOT_SUPPORTED,"thread used != false");
}
}
}
checkOpen ();
try {
server_.setSoTimeout(milliseconds);
} catch (java.net.SocketException socketException) {
JDError.throwSQLException(JDError.EXC_COMMUNICATION_LINK_FAILURE, socketException);
}
}
endif */
/**
*Sets the given schema name to access.
*
* Calling setSchema has no effect on previously created or prepared Statement objects.
* For the toolbox driver, the DBMS prepare operation takes place immediately when the
* Connection method prepareStatement or prepareCall is invoked.
* For maximum portability, setSchema should be called before a Statement is created or prepared.
*
* @param schema The name of the schema to use for the connection
* @throws SQLException If a database access error occurs or this method is
* called on a closed connection
*
*/
public void setSchema(String schema) throws SQLException {
checkOpen ();
if (schema.length() > 0 && schema.charAt(0) == '"') {
// If delimited name pass as is
} else {
// Name is not delimited, make sure it is upper case
schema = schema.toUpperCase().trim();
}
PreparedStatement ps;
// If system naming is in used and *LIBL is passed, change the schema
// to DEFAULT.
// This is to prevent problem with connection pools that call getSchema (which returns *LIBL)
// followed by setSchema(*LIBL) @S6A
boolean SQLNaming = properties_.getString(JDProperties.NAMING).equals(JDProperties.NAMING_SQL);
if ("DEFAULT".equals(schema) ||
((!SQLNaming) && ("*LIBL".equals(schema)))) {
ps = prepareStatement("SET CURRENT SCHEMA DEFAULT ");
} else {
ps = prepareStatement("SET CURRENT SCHEMA ? ");
ps.setString(1, schema);
}
ps.executeUpdate();
ps.close();
}
/**
* Is SQL cancel used for the query timeout mechanism
* @return true if cancel will be used as the query timeout mechanism
*/
public boolean isQueryTimeoutMechanismCancel() {
return queryTimeoutMechanism_ == QUERY_TIMEOUT_CANCEL;
}
/**
* Setup the variableFieldCompression flags @K3A
*/
public void setupVariableFieldCompression() {
if (!variableFieldCompressionPropertyEvaluated_) {
boolean variableFieldInsertCompressionAvailable = false;
if (serverFunctionalLevel_ >= 16) {
variableFieldInsertCompressionAvailable = true;
}
if (serverFunctionalLevel_ >= 14) {
String property = null;
try {
property = getProperties().getString(
JDProperties.VARIABLE_FIELD_COMPRESSION);
} catch (Exception e) {
// Just use defaults
}
if (property == null)
property = "default";
property = property.toLowerCase().trim();
if ("false".equals(property)) {
useVariableFieldCompression_ = false;
useVariableFieldInsertCompression_ = false;
variableFieldCompressionPropertyEvaluated_ = true;
} else if ("true".equals(property)) {
useVariableFieldCompression_ = true;
useVariableFieldInsertCompression_ = false;
variableFieldCompressionPropertyEvaluated_ = true;
} else if ("insert".equals(property)) {
useVariableFieldCompression_ = false;
useVariableFieldInsertCompression_ = variableFieldInsertCompressionAvailable;
variableFieldCompressionPropertyEvaluated_ = true;
} else {
// Default is to use all possible compression
useVariableFieldCompression_ = true;
useVariableFieldInsertCompression_ = variableFieldInsertCompressionAvailable;
variableFieldCompressionPropertyEvaluated_ = true;
}
} else {
// server does not support any form of compression
useVariableFieldCompression_ = false;
useVariableFieldInsertCompression_ = false;
variableFieldCompressionPropertyEvaluated_ = true;
}
}
}
public boolean useVariableFieldCompression() {
if (!variableFieldCompressionPropertyEvaluated_) {
setupVariableFieldCompression();
}
return useVariableFieldCompression_;
}
public boolean useVariableFieldInsertCompression() {
if (!variableFieldCompressionPropertyEvaluated_) {
setupVariableFieldCompression();
}
return useVariableFieldInsertCompression_;
}
//@L9A
public void setDisableCompression(boolean disableCompression_) {
this.disableCompression_ = disableCompression_;
}
public void dumpStatementCreationLocation() {
if (JDTrace.isTraceOn()) {
JDTrace.logInformation(this, "Dumping creation information for statements");
Vector statements = (Vector)statements_.clone();
Enumeration list = statements.elements();
while (list.hasMoreElements())
{
AS400JDBCStatement statement = (AS400JDBCStatement)list.nextElement();
if (statement.creationLocation_ == null) {
JDTrace.logInformation(statement, "No creation information");
} else {
JDTrace.logException(statement, "Creation information", statement.creationLocation_);
}
}
}
}
/**
* Tests if a DataTruncation occurred on the write of a piece of data and
* throws a DataTruncation exception if so. The data truncation flag is also
* taken into consideration for string data. The rules are:
* 1) If updating or querying database with numeric data and data truncated,
* throw exception
* 2) If string data and suppress truncation, return
* 3) If updating database with string data and check truncation and data
* truncated, throw exception
* 4) If string data is part of a query and check truncation and data truncated,
* post warning
*
* @param parameterIndex
* The index (1-based).
* @param data
* The data that was written or null for SQL NULL.
**/
public boolean testDataTruncation(AS400JDBCStatement statementWarningObject,
AS400JDBCResultSet resultSetWarningObject,
int parameterIndex, boolean isParameter, SQLData data, JDSQLStatement sqlStatement)
throws SQLException // @trunc @X4C
{
boolean checkRawBytes = false;
if (data != null) {
if (data.getOutOfBounds()) {
// Clear the error so it is not reported twice
data.clearOutOfBounds();
switch (numericRangeError_) {
case NUMERIC_RANGE_ERROR_DEFAULT:
// We now always throw a data type mismatch for a range error.
// In some cases, a truncation exception was being thrown.
// To be consistent, we will now throw the same error.
JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH, "P#="+parameterIndex);
break;
case NUMERIC_RANGE_ERROR_WARNING:
if (statementWarningObject != null) {
statementWarningObject.postWarning( JDError.getSQLWarning(JDError.EXC_DATA_TYPE_MISMATCH));
} else if (resultSetWarningObject != null ) {
resultSetWarningObject.postWarning( JDError.getSQLWarning(JDError.EXC_DATA_TYPE_MISMATCH));
}
break;
case NUMERIC_RANGE_ERROR_NONE:
break;
}
}
}
if (data != null && (characterTruncation_ != CHARACTER_TRUNCATION_NONE ) && data.isText()) {
// The SQLData object determined if data was truncated as part of the
// setValue() processing.
int truncated = data.getTruncated();
if (truncated > 0) {
// Clear the truncation so it is not reported twice
data.clearTruncated();
int actualSize = data.getActualSize();
// boolean isRead = sqlStatement_.isSelect(); //@pda jdbc40 //@pdc same
// as native (only select is read) //@trunc //@pdc match native
DataTruncation dt = new DataTruncation(parameterIndex, isParameter, false,
actualSize + truncated, actualSize); // @pdc jdbc40 //@trunc //@pdc
// match native
// if 610 and number data type, then throw DataTruncation
// if text, then use old code path and post/throw DataTruncation
if ((getVRM() >= JDUtilities.vrm610)
&& (data.isText() == false)) // @trunc2
{ // @trunc2
if (characterTruncation_ == CHARACTER_TRUNCATION_WARNING) {
if (statementWarningObject != null) {
statementWarningObject.postWarning( dt);
} else if (resultSetWarningObject != null ) {
resultSetWarningObject.postWarning( dt);
}
} else {
throw dt; // @trunc2
}
} // @trunc2
else if ((sqlStatement != null) && (sqlStatement.isSelect())
&& (!sqlStatement.isSelectFromInsert())) // @trunc2 //@selins1
{
if (statementWarningObject != null) {
statementWarningObject.postWarning( dt);
} else if (resultSetWarningObject != null ) {
resultSetWarningObject.postWarning( dt);
}
// If we want the data replace on a warning. Go ahead and
// do the replacement.
if (queryReplaceTruncatedParameter_ != null) {
data.set(queryReplaceTruncatedParameter_, null, 0);
}
} else {
if (characterTruncation_ == CHARACTER_TRUNCATION_WARNING) {
if (statementWarningObject != null ) {
statementWarningObject.postWarning( dt);
checkRawBytes = true;
} else if (resultSetWarningObject != null ) {
resultSetWarningObject.postWarning( dt);
}
} else {
throw dt;
}
}
}
/* @X4A */
} else if (data != null && (characterTruncation_ == CHARACTER_TRUNCATION_NONE ) && data.isText()) {
int truncated = data.getTruncated();
if (truncated > 0) {
// Clear the truncation so it is not reported twice
data.clearTruncated();
checkRawBytes = true;
}
}
return checkRawBytes; /*@X4A*/
}
public ConvTable getConverter() {
return converter_;
}
public void setLastServerSQLState(String lastSqlState) {
lastServerSQLState_ = lastSqlState;
}
public String getLastServerSQLState() {
return lastServerSQLState_;
}
public ConvTable getPackageCCSID_Converter() {
return packageCCSID_Converter;
}
/**
* transfer objects associated with this connection to a new connection.
* @param newConnection
*/
void transferObjects(AS400JDBCConnectionImpl newConnection) {
for (int i =0; i< MAX_STATEMENTS_; i++) {
newConnection.assigned_[i] = assigned_[i];
}
newConnection.statements_ = statements_;
statements_ = new Vector();
}
/**
* close all the current result sets in preparation for moving the
* statements to another connection.
*/
void closeAllResultSets() {
if (statements_ != null) {
Enumeration statementsEnum = statements_.elements();
while (statementsEnum.hasMoreElements()){
AS400JDBCStatement statement = (AS400JDBCStatement) statementsEnum.nextElement();
try {
statement.closeResultSet(JDCursor.REUSE_NO);
} catch (SQLException e) {
}
}
}
}
/**
* mark the statements so they know that the connection was reset.
* If the connection is reset, any prepared statements will be
* lazily reprepared.
* Also see the transaction manager for the statement.
*/
void resetStatements(JDTransactionManager tm) {
if (statements_ != null) {
Enumeration statementsEnum = statements_.elements();
while (statementsEnum.hasMoreElements()){
AS400JDBCStatement statement = (AS400JDBCStatement) statementsEnum.nextElement();
statement.setConnectionReset(true);
statement.transactionManager_ = tm;
}
}
}
public boolean getReadOnly() {
return readOnly_;
}
public boolean getCheckStatementHoldability() {
return checkStatementHoldability_;
}
int getNewAutoCommitSupport() {
return newAutoCommitSupport_;
}
/**
* Can the operation be retried after EXC_CONNECTION_REESTABLISHED.
*
* The rules for being able to retry are the following.
*
* - The connection was not being used for a transaction at the time the failure occurred.
*
- There are no outstanding global resources, such as global temporary tables or
open, held cursors, or connection states that prevent a seamless failover to another server.
*
*/
boolean canSeamlessFailover() {
if (transactionManager_ != null) {
if (transactionManager_.isLocalActive()) {
return false;
}
if (transactionManager_.isGlobalActive()) {
return false;
}
}
return true;
}
String[] emptyStringArray = null;
public String[] getReconnectURLs() {
if (emptyStringArray == null) {
emptyStringArray = new String[0];
}
return emptyStringArray;
}
// @X1A
public String getAlternateServer() {
return alternateServer_;
}
public String getHostName() {
return systemName_;
}
public String getPort() {
return portNumberString;
}
}