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

java.org.attribyte.sql.pool.ConnectionPoolConnection Maven / Gradle / Ivy

Go to download

A JDBC connection pool designed to support the high throughput, concurrency, tuning, monitoring and reporting typically required to support production application servers.

The newest version!
/*
 * Copyright 2010 Attribyte, LLC 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and limitations under the License.  
 * 
 */

package org.attribyte.sql.pool;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.SimpleTimeLimiter;
import com.google.common.util.concurrent.UncheckedTimeoutException;

import java.sql.*;
import java.util.Collections;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Wraps a SQL connection.
 */
public class ConnectionPoolConnection implements Connection {

   /**
    * How are incomplete transactions handled on connection close?
    */
   public enum IncompleteTransactionPolicy {

      /**
       * Exception is raised.
       */
      REPORT,

      /**
       * Transaction is committed.
       */
      COMMIT,

      /**
       * Transaction is rolled-back (default).
       */
      ROLLBACK;

      /**
       * Gets the policy from a string.
       * 

* Expect 'report', 'commit' or 'rollback'. *

* @param str The string. * @param defaultPolicy The default policy. * @return The policy, or default if string is invalid or undefined. */ static IncompleteTransactionPolicy fromString(final String str, final IncompleteTransactionPolicy defaultPolicy) { if(str == null) { return defaultPolicy; } if(str.equalsIgnoreCase("report")) { return REPORT; } else if(str.equalsIgnoreCase("commit")) { return COMMIT; } else if(str.equalsIgnoreCase("rollback")) { return ROLLBACK; } else { return defaultPolicy; } } } /** * How are open statements after close handled? */ public enum ForceRealClosePolicy { /** * Closes the connection on force real close. */ CONNECTION, /** * Closes the connection on force real close with a time limit. *

* If the connection close fails to complete, the connection is left * in an undefined state. *

*/ CONNECTION_WITH_LIMIT, /** * Attempts to close all open statements before connection on force real close. */ STATEMENTS_AND_CONNECTION, /** * Do nothing. Don't even call real close. */ NONE; /** * Gets the policy from a string. *

* Expect 'connection' or 'statements_and_connection'. *

* @param str The string. * @param defaultPolicy The default policy. * @return The policy, or default if string is invalid or undefined. */ static ForceRealClosePolicy fromString(final String str, final ForceRealClosePolicy defaultPolicy) { if(str == null) { return defaultPolicy; } if(str.equalsIgnoreCase("connection")) { return CONNECTION; } else if(str.equalsIgnoreCase("statements_and_connection") || str.equalsIgnoreCase("statementsAndConnection")) { return STATEMENTS_AND_CONNECTION; } else if(str.equalsIgnoreCase("none")) { return NONE; } else if(str.equalsIgnoreCase("connection_with_limit") || str.equalsIgnoreCase("connectionWithLimit")) { return CONNECTION_WITH_LIMIT; } else { return defaultPolicy; } } } /** * How are open statements after close handled? */ public enum OpenStatementPolicy { /** * Don't track open statements. */ NONE, /** * Closes statements silently, only reporting exceptions if they happen during statement close. */ SILENT, /** * Closes statements and raises an application exception. */ REPORT; /** * Gets the policy from a string. *

* Expect 'silent' or 'report' *

* @param str The string. * @param defaultPolicy The default policy. * @return The policy, or default if string is invalid or undefined. */ static OpenStatementPolicy fromString(final String str, final OpenStatementPolicy defaultPolicy) { if(str == null) { return defaultPolicy; } if(str.equalsIgnoreCase("none")) { return NONE; } else if(str.equalsIgnoreCase("silent")) { return SILENT; } else if(str.equalsIgnoreCase("report")) { return REPORT; } else { return defaultPolicy; } } } /** * How are connections that have exceeded the activity timeout handled? */ public enum ActivityTimeoutPolicy { /** * Causes the connection to be closed, even though operations may be pending in another thread. * In general, this is probably not thread-safe and deadlock is possible * if connection operations are pending in the application thread. */ FORCE_CLOSE, /** * Timeout is logged, but the connection remains active * and unavailable until it is returned to the pool. */ LOG; /** * Gets the policy from a string. *

* Expect 'force_close' or 'log'. *

* @param str The string. * @param defaultPolicy The default policy. * @return The policy, or default if string is invalid or undefined. */ static ActivityTimeoutPolicy fromString(final String str, final ActivityTimeoutPolicy defaultPolicy) { if(str == null) { return defaultPolicy; } if(str.equalsIgnoreCase("force_close") || str.equalsIgnoreCase("forceClose")) { return FORCE_CLOSE; } else if(str.equalsIgnoreCase("log")) { return LOG; } else { return defaultPolicy; } } } /** * Defines transaction states for this connection. */ enum TransactionState { /** * Connection is (logically) closed. */ CLOSED, /** * No transaction. */ NONE, /** * Transaction started. */ STARTED, /** * Transaction completed with commit or rollback. */ COMPLETED } /** * Connection is available. */ static final int STATE_AVAILABLE = 0; /** * Connection is open. */ static final int STATE_OPEN = 1; /** * Connection is being closed. */ static final int STATE_CLOSING = 2; /** * Connection is being reopened. */ static final int STATE_REOPENING = 3; /** * Connection is closed and disconnected from the DB. */ static final int STATE_DISCONNECTED = 4; /** * Creates a connection. * @param segment The segment this connection is part of. * @param id The connection id. * @param testSQL SQL used to test the connection. * @param debug Should debug data be recorded? */ protected ConnectionPoolConnection(final ConnectionPoolSegment segment, final String id, final String testSQL, final boolean debug) { this(segment, id, testSQL, debug, IncompleteTransactionPolicy.REPORT, OpenStatementPolicy.SILENT, ForceRealClosePolicy.CONNECTION, 5000L); } /** * Creates a connection. * @param segment The segment this connection is part of. * @param id The connection id. * @param testSQL SQL used to test the connection. * @param debug Should debug data be recorded? * @param incompleteTransactionPolicy The incomplete transaction policy. * @param openStatementPolicy The open statements policy. * @param forceRealClosePolicy The force-real-close policy. * @param closeTimeLimitMillis The close time limit in milliseconds. */ protected ConnectionPoolConnection(final ConnectionPoolSegment segment, final String id, final String testSQL, final boolean debug, final IncompleteTransactionPolicy incompleteTransactionPolicy, final OpenStatementPolicy openStatementPolicy, final ForceRealClosePolicy forceRealClosePolicy, final long closeTimeLimitMillis) { this.segment = segment; this.id = id; this.testSQL = testSQL; this.incompleteTransactionPolicy = incompleteTransactionPolicy; this.openStatementPolicy = openStatementPolicy; this.forceRealClosePolicy = forceRealClosePolicy; this.openStatements = forceRealClosePolicy == ForceRealClosePolicy.STATEMENTS_AND_CONNECTION ? Collections.newSetFromMap(Maps.newConcurrentMap()) : Sets.newHashSet(); this.debug = debug; this.closeTimeLimitMillis = closeTimeLimitMillis; } /** * Segment this connection belongs to. */ private final ConnectionPoolSegment segment; /** * Id assigned to this connection. */ final String id; /** * SQL used to test the real connection. */ private final String testSQL; /** * The incomplete transaction policy. */ private final IncompleteTransactionPolicy incompleteTransactionPolicy; /** * How open statements after connection close are dealt with. */ private final OpenStatementPolicy openStatementPolicy; /** * The policy on "force real close" */ private final ForceRealClosePolicy forceRealClosePolicy; /** * Should debug (including trace) be preserved? */ private final boolean debug; /** * The last stack trace. */ private volatile String lastTrace; /** * Real connection. */ private Connection conn; /** * A set containing all created statements to ensure they are * closed when connection is returned to pool. */ private final Set openStatements; /** * Random number generator. */ private static final Random rnd = new Random(System.currentTimeMillis()); /** * Time this connection was opened for use. */ volatile long openTime; /** * Exception raised during logical close. */ Throwable logicalCloseException; /** * Time the real connection was created. */ volatile long realOpenTime; /** * Time the real connection was last tested. */ volatile long lastTestTime; /** * State of this connection. */ final AtomicInteger state = new AtomicInteger(STATE_AVAILABLE); /** * The current transaction state. */ private volatile TransactionState transactionState = TransactionState.CLOSED; //Note volatile for forceRealClose() <-> close() /** * The current number of reopen attempts. */ int reopenAttempts; /** * The close time limit if policy is configured. */ private final long closeTimeLimitMillis; /** * Gets the current state of this connection as a string. * @return The state as a string. */ final String getStateAsString() { switch(state.get()) { case STATE_AVAILABLE: return "AVAILABLE"; case STATE_OPEN: return "OPEN"; case STATE_CLOSING: return "CLOSING"; case STATE_REOPENING: return "REOPENING"; case STATE_DISCONNECTED: return "DISCONNECTED"; default: return "UNKNOWN"; } } @Override /** * Returns this connection to the segment without change to the real connection. *

* Ignores close after the first. *

*/ public void close() throws SQLException { switch(transactionState) { case CLOSED: //Segment close will ignore multiple close on same connection, but need to skip the other stuff. return; case NONE: //Autocommit never changed transactionState = TransactionState.CLOSED; break; default: try { resolveIncompleteTransactions(); transactionState = TransactionState.CLOSED; } catch(Throwable t) { setLogicalCloseException(t); } finally { try { if(!conn.getAutoCommit()) { //Set auto-commit conn.setAutoCommit(true); } } catch(Throwable t) { setLogicalCloseException(t); } } } boolean openStatements = closeStatements(); Throwable logicalCloseException = this.logicalCloseException; //Preserve the exception - segment will set to null. segment.close(this); if(logicalCloseException != null) { //Now throw to the caller Util.throwException(logicalCloseException); } if(openStatements && openStatementPolicy == OpenStatementPolicy.REPORT) { throw new SQLException("Connection has open statements", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } } /** * Sets the connection state to open and records the * open time. No tests are performed. */ final void logicalOpen() { openTime = Clock.currTimeMillis; transactionState = TransactionState.NONE; if(debug) { lastTrace = Util.getFilteredStack(); } } /** * Sets the connection state to open and records the * open time after performing connection tests. * @throws java.sql.SQLException on test error. */ final void logicalOpenWithTest() throws SQLException { openTime = Clock.currTimeMillis; transactionState = TransactionState.NONE; if(debug) { lastTrace = Util.getFilteredStack(); } if(testSQL != null && testSQL.length() > 0) { ResultSet rs = null; Statement stmt = null; try { stmt = conn.createStatement(); rs = stmt.executeQuery(testSQL); } finally { try { if(rs != null) { rs.close(); } } finally { if(stmt != null) { stmt.close(); } } } } } /** * Opens a new (real) database connection if * this connection has been realCloseed. * @throws SQLException on open error. */ final void realOpen() throws SQLException { if(conn == null) { conn = segment.createRealConnection(); //Don't care about the exact value - randomize with some seconds to make //sure connections (if configured) don't expire at the same time even if they //are all created at once. realOpenTime = Clock.currTimeMillis + rnd.nextInt(120000); openStatements.clear(); //If reopen is a result of forceRealClose. reopenAttempts = 0; } } /** * Prepares the connection for return to the active pool. * @param withTest Should the connection be tested? * @throws SQLException on test error or exception raised (and thrown) during application close. */ final void logicalClose(final boolean withTest) throws SQLException { openTime = 0L; if(debug) { lastTrace = null; } if(logicalCloseException != null) { //Set during close() & thrown here to cause segment to reopen. Util.throwException(logicalCloseException); } if(withTest) { conn.setAutoCommit(true); if(testSQL != null && testSQL.length() > 0) { ResultSet rs = null; Statement stmt = null; try { stmt = conn.createStatement(); rs = stmt.executeQuery(testSQL); } finally { try { if(rs != null) { rs.close(); } } finally { if(stmt != null) { stmt.close(); } } } } } } /** * Check for unclosed statements. * @return Were any statements unclosed? */ private boolean closeStatements() { // JDBC API says... // Calling the method close on a Statement object that is already closed has no effect. // Note: When a Statement object is closed, its current ResultSet object, if one exists, is also closed. boolean hasUnclosed = false; if(openStatements.size() > 0) { for(Statement stmt : openStatements) { try { if(!stmt.isClosed()) { stmt.close(); hasUnclosed = true; } } catch(SQLException e) { hasUnclosed = true; setLogicalCloseException(e); } catch(Throwable t) { hasUnclosed = true; if(logicalCloseException == null) { if(Util.isRuntimeError(t)) { setLogicalCloseException(t); } else { setLogicalCloseException(new SQLException(t)); } } } } openStatements.clear(); } return hasUnclosed; } /** * Sets logicalCloseException if null or replaces logicalCloseException * if not null && input is a runtime error. * @param t The throwable */ private void setLogicalCloseException(final Throwable t) { if(logicalCloseException == null) { logicalCloseException = t; } else if(!Util.isRuntimeError(logicalCloseException) && Util.isRuntimeError(t)) { logicalCloseException = t; } } /** * Closes the underlying DB connection, ignoring any exception raised. *

* Use the default policy. *

*/ final void forceRealClose() { forceRealClose(forceRealClosePolicy); } /** * A time-limiter - used for obtaining database connections. */ private static final SimpleTimeLimiter closeTimeLimiter = new SimpleTimeLimiter(); /** * Closes the underlying DB connection, ignoring any exception raised. *

* Use the specified policy. *

* @param policy The policy. */ final void forceRealClose(ForceRealClosePolicy policy) { if(conn != null) { //Set transaction state to closed so app's close (in finally, hopefully) will do nothing when called. transactionState = TransactionState.CLOSED; if(policy == ForceRealClosePolicy.STATEMENTS_AND_CONNECTION) { for(Statement stmt : openStatements) { try { stmt.close(); } catch(SQLException se) { //Ignore } } } if(policy != ForceRealClosePolicy.NONE) { if(policy == ForceRealClosePolicy.CONNECTION_WITH_LIMIT) { try { closeTimeLimiter.callWithTimeout(new Callable() { public Boolean call() throws Exception { conn.close(); return Boolean.TRUE; } }, closeTimeLimitMillis, TimeUnit.MILLISECONDS, true); } catch(UncheckedTimeoutException ute) { segment.logError("Unable to close connection after waiting " + closeTimeLimitMillis + " ms"); } catch(Exception e) { segment.logError("Connection close error", e); } } else { try { conn.close(); } catch(Exception e) { segment.logError("Connection close error", e); } } } conn = null; realOpenTime = Long.MAX_VALUE; reopenAttempts = 0; lastTrace = null; } } /** * Attempt to deal with any transaction problems. * @throws SQLException on invalid state. */ private void resolveIncompleteTransactions() throws SQLException { switch(transactionState) { case COMPLETED: //All we know for certain is that at least one commit/rollback was called. Do nothing. break; case STARTED: //At least one statement was created with auto-commit false & no commit/rollback. //Follow the default policy. if(conn != null && openStatements.size() > 0) { switch(incompleteTransactionPolicy) { case REPORT: throw new SQLException("Statement closed with incomplete transaction", JDBConnection.SQLSTATE_INVALID_TRANSACTION_STATE); case COMMIT: if(!conn.isClosed()) { conn.commit(); } break; case ROLLBACK: if(!conn.isClosed()) { conn.rollback(); } } } break; } } /** * Gets the (on-open) stack trace, if available. * @return The stack trace. */ String getTrace() { return lastTrace; } /** * Adds statement to open statements set. * @param stmt The statement. */ private void openStatement(final Statement stmt) { switch(openStatementPolicy) { case NONE: break; default: openStatements.add(stmt); } } /* JDBC */ public Statement createStatement() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } if(debug) { lastTrace = Util.getFilteredStack(); } Statement stmt = conn.createStatement(); openStatement(stmt); return stmt; } public PreparedStatement prepareStatement(String sql) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } if(debug) { lastTrace = Util.getFilteredStack(); } PreparedStatement stmt = conn.prepareStatement(sql); openStatement(stmt); return stmt; } public CallableStatement prepareCall(String sql) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } if(debug) { lastTrace = Util.getFilteredStack(); } CallableStatement stmt = conn.prepareCall(sql); openStatement(stmt); return stmt; } public String nativeSQL(String sql) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.nativeSQL(sql); } public void setAutoCommit(boolean autoCommit) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } conn.setAutoCommit(autoCommit); if(!autoCommit) { switch(transactionState) { case NONE: transactionState = TransactionState.STARTED; break; default: transactionState = TransactionState.COMPLETED; break; } } else if(transactionState != TransactionState.NONE) { transactionState = TransactionState.COMPLETED; } } public boolean getAutoCommit() throws SQLException { return conn.getAutoCommit(); } public void commit() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } conn.commit(); transactionState = TransactionState.COMPLETED; } public void rollback() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } conn.rollback(); transactionState = TransactionState.COMPLETED; } public boolean isClosed() throws SQLException { return transactionState == TransactionState.CLOSED; } public DatabaseMetaData getMetaData() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.getMetaData(); } public void setReadOnly(boolean readOnly) throws SQLException { //Ignore - this must be set on real connection open. TODO } public boolean isReadOnly() throws SQLException { return conn.isReadOnly(); } public void setCatalog(String catalog) throws SQLException { //Ignore - this must be set on real connection open. TODO } public String getCatalog() throws SQLException { return conn.getCatalog(); } public void setTransactionIsolation(int level) throws SQLException { //Ignore - this must be set on real connection open. TODO } public int getTransactionIsolation() throws SQLException { return conn.getTransactionIsolation(); } public SQLWarning getWarnings() throws SQLException { return conn.getWarnings(); } public void clearWarnings() throws SQLException { //Ignore } public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } if(debug) { lastTrace = Util.getFilteredStack(); } Statement stmt = conn.createStatement(resultSetType, resultSetConcurrency); openStatement(stmt); return stmt; } public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } if(debug) { lastTrace = Util.getFilteredStack(); } PreparedStatement stmt = conn.prepareStatement(sql, resultSetType, resultSetConcurrency); openStatement(stmt); return stmt; } public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } if(debug) { lastTrace = Util.getFilteredStack(); } CallableStatement stmt = conn.prepareCall(sql, resultSetType, resultSetConcurrency); openStatement(stmt); return stmt; } public java.util.Map> getTypeMap() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.getTypeMap(); } public void setTypeMap(java.util.Map> map) throws SQLException { //Ignore - this must be done on real connection construction. TODO. } public void setHoldability(int holdability) throws SQLException { //Ignore - this must be done on real connection construction. TODO. } public int getHoldability() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.getHoldability(); } public Savepoint setSavepoint() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.setSavepoint(); } public Savepoint setSavepoint(String name) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.setSavepoint(name); } public void rollback(Savepoint savepoint) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } transactionState = TransactionState.COMPLETED; conn.rollback(savepoint); } public void releaseSavepoint(Savepoint savepoint) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } conn.releaseSavepoint(savepoint); } public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } if(debug) { lastTrace = Util.getFilteredStack(); } Statement stmt = conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); openStatement(stmt); return stmt; } public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } PreparedStatement stmt = conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); openStatement(stmt); return stmt; } public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } if(debug) { lastTrace = Util.getFilteredStack(); } CallableStatement stmt = conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); openStatement(stmt); return stmt; } public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } if(debug) { lastTrace = Util.getFilteredStack(); } PreparedStatement stmt = conn.prepareStatement(sql, autoGeneratedKeys); openStatement(stmt); return stmt; } public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } if(debug) { lastTrace = Util.getFilteredStack(); } PreparedStatement stmt = conn.prepareStatement(sql, columnIndexes); openStatement(stmt); return stmt; } public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } if(debug) { lastTrace = Util.getFilteredStack(); } PreparedStatement stmt = conn.prepareStatement(sql, columnNames); openStatement(stmt); return stmt; } public Clob createClob() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.createClob(); } public Blob createBlob() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.createBlob(); } public NClob createNClob() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.createNClob(); } public SQLXML createSQLXML() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Statements may not be created after connection close", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.createSQLXML(); } public boolean isValid(int timeout) throws SQLException { return transactionState != TransactionState.CLOSED; } public void setClientInfo(String name, String value) throws SQLClientInfoException { //Ignore - this must be done on real connection construction. TODO. } public void setClientInfo(Properties properties) throws SQLClientInfoException { //Ignore - this must be done on real connection construction. TODO. } public String getClientInfo(String name) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.getClientInfo(name); } public Properties getClientInfo() throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.getClientInfo(); } public Array createArrayOf(String typeName, Object[] elements) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.createArrayOf(typeName, elements); } public Struct createStruct(String typeName, Object[] attributes) throws SQLException { if(transactionState == TransactionState.CLOSED) { throw new SQLException("Operation not permitted on closed connection", JDBConnection.SQLSTATE_CONNECTION_EXCEPTION); } return conn.createStruct(typeName, attributes); } public T unwrap(Class iface) throws SQLException { return conn.unwrap(iface); } public boolean isWrapperFor(Class iface) throws SQLException { return conn.isWrapperFor(iface); } /* Java 7 - JDBC 4 */ public void setSchema(String schema) throws SQLException { throw new SQLFeatureNotSupportedException(); } public String getSchema() throws SQLException { throw new SQLFeatureNotSupportedException(); } public void abort(Executor executor) throws SQLException { throw new SQLFeatureNotSupportedException(); } public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { throw new SQLFeatureNotSupportedException(); } public int getNetworkTimeout() throws SQLException { throw new SQLFeatureNotSupportedException(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy