com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolProxy Maven / Gradle / Ivy
Show all versions of mssql-jdbc Show documentation
/*
* Microsoft JDBC Driver for SQL Server
*
* Copyright(c) Microsoft Corporation All rights reserved.
*
* This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information.
*/
package com.microsoft.sqlserver.jdbc;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLPermission;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.text.MessageFormat;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
/**
* SQLServerConnectionPoolProxy is a wrapper around SQLServerConnection object. When returning a connection object from PooledConnection.getConnection
* we return this proxy per SPEC.
*
* This class's public functions need to be kept identical to the SQLServerConnection's.
*
* The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API interfaces javadoc for those
* details.
*/
class SQLServerConnectionPoolProxy implements ISQLServerConnection {
private SQLServerConnection wrappedConnection;
private boolean bIsOpen;
static private final AtomicInteger baseConnectionID = new AtomicInteger(0); // connection id dispenser
final private String traceID;
// Permission targets
// currently only callAbort is implemented
private static final String callAbortPerm = "callAbort";
/**
* Generate the next unique connection id.
*
* @return the next conn id
*/
/* L0 */ private static int nextConnectionID() {
return baseConnectionID.incrementAndGet();
}
public String toString() {
return traceID;
}
/* L0 */ SQLServerConnectionPoolProxy(SQLServerConnection con) {
traceID = " ProxyConnectionID:" + nextConnectionID();
wrappedConnection = con;
// the Proxy is created with an open conn
con.setAssociatedProxy(this);
bIsOpen = true;
}
/* L0 */ void checkClosed() throws SQLServerException {
if (!bIsOpen) {
SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_connectionIsClosed"), null, false);
}
}
/* L0 */ public Statement createStatement() throws SQLServerException {
checkClosed();
return wrappedConnection.createStatement();
}
/* L0 */ public PreparedStatement prepareStatement(String sql) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareStatement(sql);
}
/* L0 */ public CallableStatement prepareCall(String sql) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareCall(sql);
}
/* L0 */ public String nativeSQL(String sql) throws SQLServerException {
checkClosed();
return wrappedConnection.nativeSQL(sql);
}
public void setAutoCommit(boolean newAutoCommitMode) throws SQLServerException {
checkClosed();
wrappedConnection.setAutoCommit(newAutoCommitMode);
}
/* L0 */ public boolean getAutoCommit() throws SQLServerException {
checkClosed();
return wrappedConnection.getAutoCommit();
}
public void commit() throws SQLServerException {
checkClosed();
wrappedConnection.commit();
}
/**
* Rollback a transaction.
*
* @throws SQLServerException
* if no transaction exists or if the connection is in auto-commit mode.
*/
public void rollback() throws SQLServerException {
checkClosed();
wrappedConnection.rollback();
}
public void abort(Executor executor) throws SQLException {
if (!bIsOpen || (null == wrappedConnection))
return;
if (null == executor) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument"));
Object[] msgArgs = {"executor"};
SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, false);
}
// check for callAbort permission
SecurityManager secMgr = System.getSecurityManager();
if (secMgr != null) {
try {
SQLPermission perm = new SQLPermission(callAbortPerm);
secMgr.checkPermission(perm);
}
catch (SecurityException ex) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_permissionDenied"));
Object[] msgArgs = {callAbortPerm};
throw new SQLServerException(form.format(msgArgs), null, 0, ex);
}
}
bIsOpen = false;
executor.execute(new Runnable() {
public void run() {
if (wrappedConnection.getConnectionLogger().isLoggable(Level.FINER))
wrappedConnection.getConnectionLogger().finer(toString() + " Connection proxy aborted ");
try {
wrappedConnection.poolCloseEventNotify();
wrappedConnection = null;
}
catch (SQLException e) {
throw new RuntimeException(e);
}
}
});
}
/* L0 */ public void close() throws SQLServerException {
if (bIsOpen && (null != wrappedConnection)) {
if (wrappedConnection.getConnectionLogger().isLoggable(Level.FINER))
wrappedConnection.getConnectionLogger().finer(toString() + " Connection proxy closed ");
wrappedConnection.poolCloseEventNotify();
wrappedConnection = null;
}
bIsOpen = false;
}
/* L0 */ void internalClose() {
bIsOpen = false;
wrappedConnection = null;
}
/* L0 */ public boolean isClosed() throws SQLServerException {
return !bIsOpen;
}
/* L0 */ public DatabaseMetaData getMetaData() throws SQLServerException {
checkClosed();
return wrappedConnection.getMetaData();
}
/* L0 */ public void setReadOnly(boolean readOnly) throws SQLServerException {
checkClosed();
wrappedConnection.setReadOnly(readOnly);
}
/* L0 */ public boolean isReadOnly() throws SQLServerException {
checkClosed();
return wrappedConnection.isReadOnly();
}
/* L0 */ public void setCatalog(String catalog) throws SQLServerException {
checkClosed();
wrappedConnection.setCatalog(catalog);
}
/* L0 */ public String getCatalog() throws SQLServerException {
checkClosed();
return wrappedConnection.getCatalog();
}
/* L0 */ public void setTransactionIsolation(int level) throws SQLServerException {
checkClosed();
wrappedConnection.setTransactionIsolation(level);
}
/* L0 */ public int getTransactionIsolation() throws SQLServerException {
checkClosed();
return wrappedConnection.getTransactionIsolation();
}
/* L0 */ public SQLWarning getWarnings() throws SQLServerException {
checkClosed();
return wrappedConnection.getWarnings(); // Warnings support added
}
/* L2 */ public void clearWarnings() throws SQLServerException {
checkClosed();
wrappedConnection.clearWarnings();
}
// --------------------------JDBC 2.0-----------------------------
/* L2 */ public Statement createStatement(int resultSetType,
int resultSetConcurrency) throws SQLException {
checkClosed();
return wrappedConnection.createStatement(resultSetType, resultSetConcurrency);
}
/* L2 */ public PreparedStatement prepareStatement(String sSql,
int resultSetType,
int resultSetConcurrency) throws SQLException {
checkClosed();
return wrappedConnection.prepareStatement(sSql, resultSetType, resultSetConcurrency);
}
/* L2 */ public CallableStatement prepareCall(String sql,
int resultSetType,
int resultSetConcurrency) throws SQLException {
checkClosed();
return wrappedConnection.prepareCall(sql, resultSetType, resultSetConcurrency);
}
/* L2 */ public void setTypeMap(java.util.Map> map) throws SQLServerException {
checkClosed();
wrappedConnection.setTypeMap(map);
}
public java.util.Map> getTypeMap() throws SQLServerException {
checkClosed();
return wrappedConnection.getTypeMap();
}
/* L3 */ public Statement createStatement(int nType,
int nConcur,
int nHold) throws SQLServerException {
checkClosed();
return wrappedConnection.createStatement(nType, nConcur, nHold);
}
/**
* Creates a Statement
object that will generate ResultSet
objects with the given type, concurrency, and holdability.
* This method is the same as the createStatement
method above, but it allows the default result set type, concurrency, and
* holdability to be overridden.
*
* @param nType
* one of the following ResultSet
constants: ResultSet.TYPE_FORWARD_ONLY
,
* ResultSet.TYPE_SCROLL_INSENSITIVE
, or ResultSet.TYPE_SCROLL_SENSITIVE
* @param nConcur
* one of the following ResultSet
constants: ResultSet.CONCUR_READ_ONLY
or
* ResultSet.CONCUR_UPDATABLE
* @param nHold
* one of the following ResultSet
constants: ResultSet.HOLD_CURSORS_OVER_COMMIT
or
* ResultSet.CLOSE_CURSORS_AT_COMMIT
* @param stmtColEncSetting
* Specifies how data will be sent and received when reading and writing encrypted columns.
* @return a new Statement
object that will generate ResultSet
objects with the given type, concurrency, and holdability
* @exception SQLException
* if a database access error occurs, this method is called on a closed connection or the given parameters are not
* ResultSet
constants indicating type, concurrency, and holdability
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method or this method is not supported for the specified result set type, result set
* holdability and result set concurrency.
*/
public Statement createStatement(int nType,
int nConcur,
int nHold,
SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException {
checkClosed();
return wrappedConnection.createStatement(nType, nConcur, nHold, stmtColEncSetting);
}
/* L3 */ public PreparedStatement prepareStatement(java.lang.String sql,
int nType,
int nConcur,
int nHold) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareStatement(sql, nType, nConcur, nHold);
}
/**
* Creates a PreparedStatement
object that will generate ResultSet
objects with the given type, concurrency, and
* holdability.
*
* This method is the same as the prepareStatement
method above, but it allows the default result set type, concurrency, and
* holdability to be overridden.
*
* @param sql
* a String
object that is the SQL statement to be sent to the database; may contain one or more '?' IN parameters
* @param nType
* one of the following ResultSet
constants: ResultSet.TYPE_FORWARD_ONLY
,
* ResultSet.TYPE_SCROLL_INSENSITIVE
, or ResultSet.TYPE_SCROLL_SENSITIVE
* @param nConcur
* one of the following ResultSet
constants: ResultSet.CONCUR_READ_ONLY
or
* ResultSet.CONCUR_UPDATABLE
* @param nHold
* one of the following ResultSet
constants: ResultSet.HOLD_CURSORS_OVER_COMMIT
or
* ResultSet.CLOSE_CURSORS_AT_COMMIT
* @param stmtColEncSetting
* Specifies how data will be sent and received when reading and writing encrypted columns.
* @return a new PreparedStatement
object, containing the pre-compiled SQL statement, that will generate ResultSet
* objects with the given type, concurrency, and holdability
* @exception SQLException
* if a database access error occurs, this method is called on a closed connection or the given parameters are not
* ResultSet
constants indicating type, concurrency, and holdability
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method or this method is not supported for the specified result set type, result set
* holdability and result set concurrency.
*/
public PreparedStatement prepareStatement(String sql,
int nType,
int nConcur,
int nHold,
SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareStatement(sql, nType, nConcur, nHold, stmtColEncSetting);
}
/* L3 */ public CallableStatement prepareCall(String sql,
int nType,
int nConcur,
int nHold) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareCall(sql, nType, nConcur, nHold);
}
/**
* Creates a CallableStatement
object that will generate ResultSet
objects with the given type and concurrency. This
* method is the same as the prepareCall
method above, but it allows the default result set type, result set concurrency type and
* holdability to be overridden.
*
* @param sql
* a String
object that is the SQL statement to be sent to the database; may contain on or more '?' parameters
* @param nType
* one of the following ResultSet
constants: ResultSet.TYPE_FORWARD_ONLY
,
* ResultSet.TYPE_SCROLL_INSENSITIVE
, or ResultSet.TYPE_SCROLL_SENSITIVE
* @param nConcur
* one of the following ResultSet
constants: ResultSet.CONCUR_READ_ONLY
or
* ResultSet.CONCUR_UPDATABLE
* @param nHold
* one of the following ResultSet
constants: ResultSet.HOLD_CURSORS_OVER_COMMIT
or
* ResultSet.CLOSE_CURSORS_AT_COMMIT
* @param stmtColEncSetting
* Specifies how data will be sent and received when reading and writing encrypted columns.
* @return a new CallableStatement
object, containing the pre-compiled SQL statement, that will generate ResultSet
* objects with the given type, concurrency, and holdability
* @exception SQLException
* if a database access error occurs, this method is called on a closed connection or the given parameters are not
* ResultSet
constants indicating type, concurrency, and holdability
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method or this method is not supported for the specified result set type, result set
* holdability and result set concurrency.
*/
public CallableStatement prepareCall(String sql,
int nType,
int nConcur,
int nHold,
SQLServerStatementColumnEncryptionSetting stmtColEncSetiing) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareCall(sql, nType, nConcur, nHold, stmtColEncSetiing);
}
/* JDBC 3.0 Auto generated keys */
/* L3 */ public PreparedStatement prepareStatement(String sql,
int flag) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareStatement(sql, flag);
}
/**
* Creates a default PreparedStatement
object that has the capability to retrieve auto-generated keys. The given constant tells the
* driver whether it should make auto-generated keys available for retrieval. This parameter is ignored if the SQL statement is not an
* INSERT
statement, or an SQL statement able to return auto-generated keys (the list of such statements is vendor-specific).
*
* Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports
* precompilation, the method prepareStatement
will send the statement to the database for precompilation. Some drivers may not
* support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement
object is
* executed. This has no direct effect on users; however, it does affect which methods throw certain SQLExceptions.
*
* Result sets created using the returned PreparedStatement
object will by default be type TYPE_FORWARD_ONLY
and have a
* concurrency level of CONCUR_READ_ONLY
. The holdability of the created result sets can be determined by calling
* {@link #getHoldability}.
*
* @param sql
* an SQL statement that may contain one or more '?' IN parameter placeholders
* @param flag
* a flag indicating whether auto-generated keys should be returned; one of Statement.RETURN_GENERATED_KEYS
or
* Statement.NO_GENERATED_KEYS
* @param stmtColEncSetting
* Specifies how data will be sent and received when reading and writing encrypted columns.
* @return a new PreparedStatement
object, containing the pre-compiled SQL statement, that will have the capability of returning
* auto-generated keys
* @exception SQLException
* if a database access error occurs, this method is called on a closed connection or the given parameter is not a
* Statement
constant indicating whether auto-generated keys should be returned
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method with a constant of Statement.RETURN_GENERATED_KEYS
*/
public PreparedStatement prepareStatement(String sql,
int flag,
SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareStatement(sql, flag, stmtColEncSetting);
}
/* L3 */ public PreparedStatement prepareStatement(String sql,
int[] columnIndexes) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareStatement(sql, columnIndexes);
}
/**
* Creates a default PreparedStatement
object capable of returning the auto-generated keys designated by the given array. This array
* contains the indexes of the columns in the target table that contain the auto-generated keys that should be made available. The driver will
* ignore the array if the SQL statement is not an INSERT
statement, or an SQL statement able to return auto-generated keys (the list
* of such statements is vendor-specific).
*
* An SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement
object. This object can then
* be used to efficiently execute this statement multiple times.
*
* Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports
* precompilation, the method prepareStatement
will send the statement to the database for precompilation. Some drivers may not
* support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement
object is
* executed. This has no direct effect on users; however, it does affect which methods throw certain SQLExceptions.
*
* Result sets created using the returned PreparedStatement
object will by default be type TYPE_FORWARD_ONLY
and have a
* concurrency level of CONCUR_READ_ONLY
. The holdability of the created result sets can be determined by calling
* {@link #getHoldability}.
*
* @param sql
* an SQL statement that may contain one or more '?' IN parameter placeholders
* @param columnIndexes
* an array of column indexes indicating the columns that should be returned from the inserted row or rows
* @param stmtColEncSetting
* Specifies how data will be sent and received when reading and writing encrypted columns.
* @return a new PreparedStatement
object, containing the pre-compiled statement, that is capable of returning the auto-generated
* keys designated by the given array of column indexes
* @exception SQLException
* if a database access error occurs or this method is called on a closed connection
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method
*/
public PreparedStatement prepareStatement(String sql,
int[] columnIndexes,
SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareStatement(sql, columnIndexes, stmtColEncSetting);
}
/* L3 */ public PreparedStatement prepareStatement(String sql,
String[] columnNames) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareStatement(sql, columnNames);
}
/**
* Creates a default PreparedStatement
object capable of returning the auto-generated keys designated by the given array. This array
* contains the names of the columns in the target table that contain the auto-generated keys that should be returned. The driver will ignore the
* array if the SQL statement is not an INSERT
statement, or an SQL statement able to return auto-generated keys (the list of such
* statements is vendor-specific).
*
* An SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement
object. This object can then
* be used to efficiently execute this statement multiple times.
*
* Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports
* precompilation, the method prepareStatement
will send the statement to the database for precompilation. Some drivers may not
* support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement
object is
* executed. This has no direct effect on users; however, it does affect which methods throw certain SQLExceptions.
*
* Result sets created using the returned PreparedStatement
object will by default be type TYPE_FORWARD_ONLY
and have a
* concurrency level of CONCUR_READ_ONLY
. The holdability of the created result sets can be determined by calling
* {@link #getHoldability}.
*
* @param sql
* an SQL statement that may contain one or more '?' IN parameter placeholders
* @param columnNames
* an array of column names indicating the columns that should be returned from the inserted row or rows
* @param stmtColEncSetting
* Specifies how data will be sent and received when reading and writing encrypted columns.
* @return a new PreparedStatement
object, containing the pre-compiled statement, that is capable of returning the auto-generated
* keys designated by the given array of column names
* @exception SQLException
* if a database access error occurs or this method is called on a closed connection
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method
*/
public PreparedStatement prepareStatement(String sql,
String[] columnNames,
SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException {
checkClosed();
return wrappedConnection.prepareStatement(sql, columnNames, stmtColEncSetting);
}
/* JDBC 3.0 Savepoints */
/* L3 */ public void releaseSavepoint(Savepoint savepoint) throws SQLServerException {
checkClosed();
wrappedConnection.releaseSavepoint(savepoint);
}
/* L3 */ public Savepoint setSavepoint(String sName) throws SQLServerException {
checkClosed();
return wrappedConnection.setSavepoint(sName);
}
/* L3 */ public Savepoint setSavepoint() throws SQLServerException {
checkClosed();
return wrappedConnection.setSavepoint();
}
/* L3 */ public void rollback(Savepoint s) throws SQLServerException {
checkClosed();
wrappedConnection.rollback(s);
}
/* L3 */ public int getHoldability() throws SQLServerException {
checkClosed();
return wrappedConnection.getHoldability();
}
/* L3 */ public void setHoldability(int nNewHold) throws SQLServerException {
checkClosed();
wrappedConnection.setHoldability(nNewHold);
}
public int getNetworkTimeout() throws SQLException {
checkClosed();
return wrappedConnection.getNetworkTimeout();
}
public void setNetworkTimeout(Executor executor,
int timeout) throws SQLException {
checkClosed();
wrappedConnection.setNetworkTimeout(executor, timeout);
}
public String getSchema() throws SQLException {
checkClosed();
return wrappedConnection.getSchema();
}
public void setSchema(String schema) throws SQLException {
checkClosed();
wrappedConnection.setSchema(schema);
}
public java.sql.Array createArrayOf(String typeName,
Object[] elements) throws SQLException {
checkClosed();
return wrappedConnection.createArrayOf(typeName, elements);
}
public Blob createBlob() throws SQLException {
checkClosed();
return wrappedConnection.createBlob();
}
public Clob createClob() throws SQLException {
checkClosed();
return wrappedConnection.createClob();
}
public NClob createNClob() throws SQLException {
checkClosed();
return wrappedConnection.createNClob();
}
public SQLXML createSQLXML() throws SQLException {
checkClosed();
return wrappedConnection.createSQLXML();
}
public Struct createStruct(String typeName,
Object[] attributes) throws SQLException {
checkClosed();
return wrappedConnection.createStruct(typeName, attributes);
}
public Properties getClientInfo() throws SQLException {
checkClosed();
return wrappedConnection.getClientInfo();
}
public String getClientInfo(String name) throws SQLException {
checkClosed();
return wrappedConnection.getClientInfo(name);
}
public void setClientInfo(Properties properties) throws SQLClientInfoException {
// No checkClosed() call since we can only throw SQLClientInfoException from here
wrappedConnection.setClientInfo(properties);
}
public void setClientInfo(String name,
String value) throws SQLClientInfoException {
// No checkClosed() call since we can only throw SQLClientInfoException from here
wrappedConnection.setClientInfo(name, value);
}
public boolean isValid(int timeout) throws SQLException {
checkClosed();
return wrappedConnection.isValid(timeout);
}
public boolean isWrapperFor(Class> iface) throws SQLException {
wrappedConnection.getConnectionLogger().entering(toString(), "isWrapperFor", iface);
boolean f = iface.isInstance(this);
wrappedConnection.getConnectionLogger().exiting(toString(), "isWrapperFor", f);
return f;
}
public T unwrap(Class iface) throws SQLException {
wrappedConnection.getConnectionLogger().entering(toString(), "unwrap", iface);
T t;
try {
t = iface.cast(this);
}
catch (ClassCastException e) {
SQLServerException newe = new SQLServerException(e.getMessage(), e);
throw newe;
}
wrappedConnection.getConnectionLogger().exiting(toString(), "unwrap", t);
return t;
}
public UUID getClientConnectionId() throws SQLServerException {
checkClosed();
return wrappedConnection.getClientConnectionId();
}
/**
* Modifies the setting of the sendTimeAsDatetime connection property. When true, java.sql.Time values will be sent to the server as SQL
* Serverdatetime values. When false, java.sql.Time values will be sent to the server as SQL Servertime values. sendTimeAsDatetime can also be
* modified programmatically with SQLServerDataSource.setSendTimeAsDatetime. The default value for this property may change in a future release.
*
* @param sendTimeAsDateTimeValue
* enables/disables setting the sendTimeAsDatetime connection property. For more information about how the Microsoft JDBC Driver for
* SQL Server configures java.sql.Time values before sending them to the server, see
* Configuring How java.sql.Time Values are Sent to the
* Server.
*/
public synchronized void setSendTimeAsDatetime(boolean sendTimeAsDateTimeValue) throws SQLServerException {
checkClosed();
wrappedConnection.setSendTimeAsDatetime(sendTimeAsDateTimeValue);
}
/**
* Returns the setting of the sendTimeAsDatetime connection property.
*
* @return if enabled, returns true. Otherwise, false.
* @throws SQLServerException
* when an error occurs.
*/
public synchronized final boolean getSendTimeAsDatetime() throws SQLServerException {
checkClosed();
return wrappedConnection.getSendTimeAsDatetime();
}
}