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

com.landawn.abacus.dataSource.PoolableConnection Maven / Gradle / Ivy

/*
 * Copyright (c) 2015, Haiyang Li. All rights reserved.
 */

package com.landawn.abacus.dataSource;

import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

import com.landawn.abacus.exception.AbacusException;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.pool.AbstractPoolable;
import com.landawn.abacus.pool.KeyedObjectPool;
import com.landawn.abacus.pool.PoolFactory;
import com.landawn.abacus.util.N;

/**
 * 
 * @since 0.8
 * 
 * @author Haiyang Li
 */
class PoolableConnection extends AbstractPoolable implements Connection {
    private static final Logger logger = LoggerFactory.getLogger(PoolableConnection.class);

    private static final int CACHED_SQL_LENGTH = 4096;
    private static final int EVICTY_DELAY_FOR_STATEMENT_POOL = 60 * 1000;

    private final KeyedObjectPool cachedStatementPool;

    private final ConnectionManager connManager;
    private final Connection internalConn;

    private volatile long lastSQLExecutionTime;
    private boolean isClosed = false;

    public PoolableConnection(ConnectionManager dataSource, java.sql.Connection conn) {
        this(dataSource, conn, DataSourceConfiguration.DEFAULT_LIVE_TIME, DataSourceConfiguration.DEFAULT_MAX_IDLE_TIME,
                DataSourceConfiguration.DEFAULT_MAX_OPEN_PREPARED_STATEMENTS_PER_CONNECTION);
    }

    public PoolableConnection(ConnectionManager connManager, java.sql.Connection conn, long liveTime, long maxIdleTime, int cachedStatementSize) {
        super(liveTime, maxIdleTime);

        cachedStatementPool = PoolFactory.createKeyedObjectPool(cachedStatementSize, EVICTY_DELAY_FOR_STATEMENT_POOL);

        this.connManager = connManager;

        this.internalConn = conn;
    }

    ConnectionManager getConnectionManager() {
        return connManager;
    }

    void cachePreparedStatement(PoolablePreparedStatement stmt) {
        if (stmt == null) {
            return;
        } else if (stmt.getId() == null) {
            stmt.destroy();
        } else {
            CachedStatmentKey id = stmt.getId();

            try {
                stmt.clearParameters();

                synchronized (cachedStatementPool) {
                    if (cachedStatementPool.containsKey(id)) {
                        stmt.destroy();
                    } else if (!cachedStatementPool.put(id, stmt)) {
                        stmt.destroy();
                    }
                }
            } catch (SQLException e) {
                stmt.destroy();

                if (logger.isWarnEnabled()) {
                    logger.warn(AbacusException.getErrorMsg(e));
                }
            }
        }
    }

    void removePreparedStatementFromCache(PoolablePreparedStatement stmt) throws SQLException {
        if ((stmt != null) && (stmt.getId() != null)) {
            // DO NOT synchronized(cachedStatementPool) because it may cause dead lock.

            /*
            JNI global references: 294
            
            
            Found one Java-level deadlock:
            =============================
            "Thread-37":
            waiting to lock monitor 0x000000006374ffe8 (object 0x000000078a8ebc70, a com.landawn.abacus.pool.GenericKeyedObjectPool),
            which is held by "pool-165-thread-25"
            "pool-165-thread-25":
            waiting for ownable synchronizer 0x000000078a8ebd38, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
            which is held by "Thread-37"
            
            Java stack information for the threads listed above:
            ===================================================
            "Thread-37":
            at com.landawn.abacus.core.sql.dataSource.PoolableConnection.removePreparedStatementFromCache(PoolableConnection.java:106)
            - waiting to lock <0x000000078a8ebc70> (a com.landawn.abacus.pool.GenericKeyedObjectPool)
            at com.landawn.abacus.core.sql.dataSource.PoolablePreparedStatement.destroy(PoolablePreparedStatement.java:89)
            at com.landawn.abacus.pool.AbstractPool.destroyObject(AbstractPool.java:327)
            at com.landawn.abacus.pool.GenericKeyedObjectPool.destroyObject(GenericKeyedObjectPool.java:248)
            at com.landawn.abacus.pool.AbstractPool.destroyObject(AbstractPool.java:340)
            at com.landawn.abacus.pool.AbstractPool.clear(AbstractPool.java:238)
            at com.landawn.abacus.pool.AbstractPool.close(AbstractPool.java:257)
            at com.landawn.abacus.core.sql.dataSource.PoolableConnection.destroy(PoolableConnection.java:150)
            at com.landawn.abacus.core.sql.dataSource.SQLConnectionManager.clear(SQLConnectionManager.java:302)
            - locked <0x00000007840e1158> (a java.util.IdentityHashMap)
            at com.landawn.abacus.core.sql.dataSource.SQLConnectionManager$2.run(SQLConnectionManager.java:119)
            "pool-165-thread-25":
            at sun.misc.Unsafe.park(Native Method)
            - parking to wait for  <0x000000078a8ebd38> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
            at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:867)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1197)
            at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:214)
            at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:290)
            at com.landawn.abacus.pool.GenericKeyedObjectPool.containsKey(GenericKeyedObjectPool.java:194)
            at com.landawn.abacus.core.sql.dataSource.PoolableConnection.cachePreparedStatement(PoolableConnection.java:85)
            - locked <0x000000078a8ebc70> (a com.landawn.abacus.pool.GenericKeyedObjectPool)
            at com.landawn.abacus.core.sql.dataSource.PoolablePreparedStatement.close(PoolablePreparedStatement.java:74)
            at com.landawn.abacus.util.JdbcUtil.closeQuietly(JdbcUtil.java:636)
            at com.landawn.abacus.util.SQLExecutor.closeQuietly(SQLExecutor.java:3295)
            at com.landawn.abacus.util.SQLExecutor.query(SQLExecutor.java:1841)
            at com.landawn.abacus.util.SQLExecutor.query(SQLExecutor.java:1806)
            at com.landawn.abacus.util.SQLExecutor.query(SQLExecutor.java:1757)
            at com.landawn.abacus.util.SQLExecutor.query(SQLExecutor.java:1722)
            at com.landawn.abacus.util.PropertiesUtil$2.run(PropertiesUtil.java:195)
            - locked <0x00000007849489a0> (a java.util.concurrent.ConcurrentHashMap)
            at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
            at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
            at java.lang.Thread.run(Thread.java:745)
            
            Found 1 deadlock.            
             */
            final PoolablePreparedStatement tmp = cachedStatementPool.remove(stmt.getId());

            if (tmp == stmt || tmp == null) {
                // do nothing.
            } else {
                tmp.close();
            }
        }
    }

    synchronized void updateLastSQLExecutionTime(boolean isOk) {
        lastSQLExecutionTime = System.currentTimeMillis();

        if (!isOk) {
            connManager.updateLastSQLExecutionFailureTime();
        }
    }

    long getLastSQLExecutionTime() {
        return lastSQLExecutionTime;
    }

    /**
     * Method close.
     * 
     * @throws SQLException
     * @see java.sql.Connection#close()
     */
    @Override
    public void close() throws SQLException {
        if (connManager == null) {
            destroy();
        } else {
            connManager.closeConnection(this);
        }
    }

    /**
     * To release resourse of the AbstractPoolable.
     * 
     * @see com.landawn.abacus.pool.Poolable#destroy()
     */
    @Override
    public void destroy() {
        if (!isClosed) {
            isClosed = true;

            cachedStatementPool.close();

            try {
                internalConn.close();
            } catch (SQLException e) {
                // ignore;

                if (logger.isWarnEnabled()) {
                    logger.warn(AbacusException.getErrorMsg(e));
                }
            } finally {
                if (connManager != null) {
                    connManager.detroyConnection(this);
                }
            }
        }
    }

    /**
     * Method commit.
     * 
     * @throws SQLException
     * @see java.sql.Connection#commit()
     */
    @Override
    public void commit() throws SQLException {
        internalConn.commit();
    }

    /**
     * Method clearWarnings.
     * 
     * @throws SQLException
     * @see java.sql.Connection#clearWarnings()
     */
    @Override
    public void clearWarnings() throws SQLException {
        internalConn.clearWarnings();
    }

    /**
     * Method createStatement.
     * 
     * @return Statement
     * @throws SQLException
     * @see java.sql.Connection#createStatement()
     */
    @Override
    public Statement createStatement() throws SQLException {
        // return new NativeStatement(internalConn.createStatement(), this);
        return internalConn.createStatement();
    }

    /**
     * Method createStatement.
     * 
     * @param resultSetType
     * @param resultSetConcurrency
     * @return Statement
     * @throws SQLException
     * @see java.sql.Connection#createStatement(int, int)
     */
    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
        // return new
        // NativeStatement(internalConn.createStatement(resultSetType,
        // resultSetConcurrency), this);
        return internalConn.createStatement(resultSetType, resultSetConcurrency);
    }

    /**
     * Method createStatement.
     * 
     * @param resultSetType
     * @param resultSetConcurrency
     * @param resultSetHoldability
     * @return Statement
     * @throws SQLException
     * @see java.sql.Connection#createStatement(int, int, int)
     */
    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        // return new
        // NativeStatement(internalConn.createStatement(resultSetType,
        // resultSetConcurrency,
        // resultSetHoldability), this);
        return internalConn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
    }

    /**
     * Method getAutoCommit.
     * 
     * @return boolean
     * @throws SQLException
     * @see java.sql.Connection#getAutoCommit()
     */
    @Override
    public boolean getAutoCommit() throws SQLException {
        return internalConn.getAutoCommit();
    }

    /**
     * Method getCatalog.
     * 
     * @return String
     * @throws SQLException
     * @see java.sql.Connection#getCatalog()
     */
    @Override
    public String getCatalog() throws SQLException {
        return internalConn.getCatalog();
    }

    /**
     * Method getHoldability.
     * 
     * @return int
     * @throws SQLException
     * @see java.sql.Connection#getHoldability()
     */
    @Override
    public int getHoldability() throws SQLException {
        return internalConn.getHoldability();
    }

    /**
     * Method getMetaData.
     * 
     * @return DatabaseMetaData
     * @throws SQLException
     * @see java.sql.Connection#getMetaData()
     */
    @Override
    public DatabaseMetaData getMetaData() throws SQLException {
        return internalConn.getMetaData();
    }

    /**
     * Method getTransactionIsolation.
     * 
     * @return int
     * @throws SQLException
     * @see java.sql.Connection#getTransactionIsolation()
     */
    @Override
    public int getTransactionIsolation() throws SQLException {
        return internalConn.getTransactionIsolation();
    }

    /**
     * Method getTypeMap.
     * 
     * @return Map>
     * @throws SQLException
     * @see java.sql.Connection#getTypeMap()
     */
    @Override
    public Map> getTypeMap() throws SQLException {
        return internalConn.getTypeMap();
    }

    /**
     * Method getWarnings.
     * 
     * @return SQLWarning
     * @throws SQLException
     * @see java.sql.Connection#getWarnings()
     */
    @Override
    public SQLWarning getWarnings() throws SQLException {
        return internalConn.getWarnings();
    }

    /**
     * Method isClosed.
     * 
     * @return boolean
     * @throws SQLException
     * @see java.sql.Connection#isClosed()
     */
    @Override
    public boolean isClosed() throws SQLException {
        if (!isClosed) {
            try {
                if (internalConn.isClosed()) {
                    destroy();
                }
            } catch (SQLException e) {
                // ignore
                destroy();

                if (logger.isWarnEnabled()) {
                    logger.warn(AbacusException.getErrorMsg(e));
                }
            }
        }

        return isClosed;
    }

    /**
     * Method isReadOnly.
     * 
     * @return boolean
     * @throws SQLException
     * @see java.sql.Connection#isReadOnly()
     */
    @Override
    public boolean isReadOnly() throws SQLException {
        return internalConn.isReadOnly();
    }

    /**
     * Method nativeSQL.
     * 
     * @param sql
     * @return String
     * @throws SQLException
     * @see java.sql.Connection#nativeSQL(String)
     */
    @Override
    public String nativeSQL(String sql) throws SQLException {
        return internalConn.nativeSQL(sql);
    }

    /**
     * Method prepareCall.
     * 
     * @param sql
     * @return CallableStatement
     * @throws SQLException
     * @see java.sql.Connection#prepareCall(String)
     */
    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        // return new NativeCallableStatement(internalConn.prepareCall(sql),
        // this);
        return internalConn.prepareCall(sql);
    }

    /**
     * Method prepareCall.
     * 
     * @param sql
     * @param resultSetType
     * @param resultSetConcurrency
     * @return CallableStatement
     * @throws SQLException
     * @see java.sql.Connection#prepareCall(String, int, int)
     */
    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        // return new NativeCallableStatement(internalConn.prepareCall(sql,
        // resultSetType, resultSetConcurrency), this);
        return internalConn.prepareCall(sql, resultSetType, resultSetConcurrency);
    }

    /**
     * Method prepareCall.
     * 
     * @param sql
     * @param resultSetType
     * @param resultSetConcurrency
     * @param resultSetHoldability
     * @return CallableStatement
     * @throws SQLException
     * @see java.sql.Connection#prepareCall(String, int, int, int)
     */
    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        // return new NativeCallableStatement(internalConn.prepareCall(sql,
        // resultSetType, resultSetConcurrency,
        // resultSetHoldability), this);
        return internalConn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
    }

    /**
     * Method prepareStatement.
     * 
     * @param sql
     * @return PreparedStatement
     * @throws SQLException
     * @see java.sql.Connection#prepareStatement(String)
     */
    @Override
    public PoolablePreparedStatement prepareStatement(String sql) throws SQLException {
        return prepareStatement(sql, -1, -1, -1, -1);
    }

    /**
     * Method prepareStatement.
     * 
     * @param sql
     * @param autoGeneratedKeys
     * @return PreparedStatement
     * @throws SQLException
     * @see java.sql.Connection#prepareStatement(String, int)
     */
    @Override
    public PoolablePreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
        return prepareStatement(sql, autoGeneratedKeys, -1, -1, -1);
    }

    /**
     * Method prepareStatement.
     * 
     * @param sql
     * @param columnIndexes
     * @return PreparedStatement
     * @throws SQLException
     * @see java.sql.Connection#prepareStatement(String, int[])
     */
    @Override
    public PoolablePreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
        return new PoolablePreparedStatement(internalConn.prepareStatement(sql, columnIndexes), this, null);
    }

    /**
     * Method prepareStatement.
     * 
     * @param sql
     * @param columnNames
     * @return PreparedStatement
     * @throws SQLException
     * @see java.sql.Connection#prepareStatement(String, String[])
     */
    @Override
    public PoolablePreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
        return new PoolablePreparedStatement(internalConn.prepareStatement(sql, columnNames), this, null);
    }

    /**
     * Method prepareStatement.
     * 
     * @param sql
     * @param resultSetType
     * @param resultSetConcurrency
     * @return PreparedStatement
     * @throws SQLException
     * @see java.sql.Connection#prepareStatement(String, int, int)
     */
    @Override
    public PoolablePreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return prepareStatement(sql, -1, resultSetType, resultSetConcurrency, -1);
    }

    @Override
    public PoolablePreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return prepareStatement(sql, -1, resultSetType, resultSetConcurrency, resultSetHoldability);
    }

    protected PoolablePreparedStatement prepareStatement(String sql, int autoGeneratedKeys, int resultSetType, int resultSetConcurrency,
            int resultSetHoldability) throws SQLException {
        PoolablePreparedStatement stmt = null;
        CachedStatmentKey id = null;

        if (sql.length() < CACHED_SQL_LENGTH) {
            id = new CachedStatmentKey(sql, autoGeneratedKeys, resultSetType, resultSetConcurrency, resultSetHoldability);

            synchronized (cachedStatementPool) {
                stmt = cachedStatementPool.remove(id);
            }
        }

        if (stmt == null) {
            if ((resultSetType != -1) && (resultSetConcurrency != -1) && (resultSetHoldability != -1)) {
                stmt = new PoolablePreparedStatement(internalConn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability), this, id);
            } else if ((resultSetType != -1) && (resultSetConcurrency != -1)) {
                stmt = new PoolablePreparedStatement(internalConn.prepareStatement(sql, resultSetType, resultSetConcurrency), this, id);
            } else {
                if (autoGeneratedKeys != -1) {
                    stmt = new PoolablePreparedStatement(internalConn.prepareStatement(sql, autoGeneratedKeys), this, id);
                } else {
                    stmt = new PoolablePreparedStatement(internalConn.prepareStatement(sql), this, id);
                }
            }
        }

        return stmt;
    }

    /**
     * Method releaseSavepoint.
     * 
     * @param savepoint
     * @throws SQLException
     * @see java.sql.Connection#releaseSavepoint(Savepoint)
     */
    @Override
    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
        internalConn.releaseSavepoint(savepoint);
    }

    /**
     * Method rollback.
     * 
     * @throws SQLException
     * @see java.sql.Connection#rollback()
     */
    @Override
    public void rollback() throws SQLException {
        internalConn.rollback();
    }

    /**
     * Method rollback.
     * 
     * @param savepoint
     * @throws SQLException
     * @see java.sql.Connection#rollback(Savepoint)
     */
    @Override
    public void rollback(Savepoint savepoint) throws SQLException {
        internalConn.rollback(savepoint);
    }

    /**
     * Method setAutoCommit.
     * 
     * @param autoCommit
     * @throws SQLException
     * @see java.sql.Connection#setAutoCommit(boolean)
     */
    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {
        internalConn.setAutoCommit(autoCommit);
    }

    /**
     * Method setCatalog.
     * 
     * @param catalog
     * @throws SQLException
     * @see java.sql.Connection#setCatalog(String)
     */
    @Override
    public void setCatalog(String catalog) throws SQLException {
        internalConn.setCatalog(catalog);
    }

    /**
     * Method setHoldability.
     * 
     * @param holdability
     * @throws SQLException
     * @see java.sql.Connection#setHoldability(int)
     */
    @Override
    public void setHoldability(int holdability) throws SQLException {
        internalConn.setHoldability(holdability);
    }

    /**
     * Method setReadOnly.
     * 
     * @param readOnly
     * @throws SQLException
     * @see java.sql.Connection#setReadOnly(boolean)
     */
    @Override
    public void setReadOnly(boolean readOnly) throws SQLException {
        internalConn.setReadOnly(readOnly);
    }

    /**
     * Method setSavepoint.
     * 
     * @return Savepoint
     * @throws SQLException
     * @see java.sql.Connection#setSavepoint()
     */
    @Override
    public Savepoint setSavepoint() throws SQLException {
        return internalConn.setSavepoint();
    }

    /**
     * Method setSavepoint.
     * 
     * @param name
     * @return Savepoint
     * @throws SQLException
     * @see java.sql.Connection#setSavepoint(String)
     */
    @Override
    public Savepoint setSavepoint(String name) throws SQLException {
        return internalConn.setSavepoint(name);
    }

    /**
     * Method setTransactionIsolation.
     * 
     * @param level
     * @throws SQLException
     * @see java.sql.Connection#setTransactionIsolation(int)
     */
    @Override
    public void setTransactionIsolation(int level) throws SQLException {
        internalConn.setTransactionIsolation(level);
    }

    /**
     * Method setTypeMap.
     * 
     * @param arg0
     * @throws SQLException
     * @see java.sql.Connection#setTypeMap(Map>)
     */
    @Override
    public void setTypeMap(Map> arg0) throws SQLException {
        internalConn.setTypeMap(arg0);
    }

    /**
     * Method createArrayOf.
     * 
     * @param typeName
     * @param elements
     * @return Array
     * @throws SQLException
     * @see java.sql.Connection#createArrayOf(String, Object[])
     */
    @Override
    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
        return internalConn.createArrayOf(typeName, elements);
    }

    /**
     * Method createBlob.
     * 
     * @return Blob
     * @throws SQLException
     * @see java.sql.Connection#createBlob()
     */
    @Override
    public Blob createBlob() throws SQLException {
        return internalConn.createBlob();
    }

    /**
     * Method createClob.
     * 
     * @return Clob
     * @throws SQLException
     * @see java.sql.Connection#createClob()
     */
    @Override
    public Clob createClob() throws SQLException {
        return internalConn.createClob();
    }

    /**
     * Method createNClob.
     * 
     * @return NClob
     * @throws SQLException
     * @see java.sql.Conn#createNClob()
     */
    @Override
    public NClob createNClob() throws SQLException {
        return internalConn.createNClob();
    }

    /**
     * Method createSQLXML.
     * 
     * @return SQLXML
     * @throws SQLException
     * @see java.sql.Conn#createSQLXML()
     */
    @Override
    public SQLXML createSQLXML() throws SQLException {
        return internalConn.createSQLXML();
    }

    /**
     * Method createStruct.
     * 
     * @param typeName
     * @param attributes
     * @return Struct
     * @throws SQLException
     * @see java.sql.Connection#createStruct(String, Object[])
     */
    @Override
    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
        return internalConn.createStruct(typeName, attributes);
    }

    /**
     * Method getClientInfo.
     * 
     * @return Properties
     * @throws SQLException
     * @see java.sql.Connection#getClientInfo()
     */
    @Override
    public Properties getClientInfo() throws SQLException {
        return internalConn.getClientInfo();
    }

    /**
     * Method getClientInfo.
     * 
     * @param name
     * @return String
     * @throws SQLException
     * @see java.sql.Connection#getClientInfo(String)
     */
    @Override
    public String getClientInfo(String name) throws SQLException {
        return internalConn.getClientInfo(name);
    }

    /**
     * Method isValid.
     * 
     * @param timeout
     * @return boolean
     * @throws SQLException
     * @see java.sql.Connection#isValid(int)
     */
    @Override
    public boolean isValid(int timeout) throws SQLException {
        return internalConn.isValid(timeout);
    }

    /**
     * Method setClientInfo.
     * 
     * @param properties
     * @throws SQLClientInfoException
     * @see java.sql.Connection#setClientInfo(Properties)
     */
    @Override
    public void setClientInfo(Properties properties) throws SQLClientInfoException {
        internalConn.setClientInfo(properties);
    }

    /**
     * Method setClientInfo.
     * 
     * @param name
     * @param value
     * @throws SQLClientInfoException
     * @see java.sql.Connection#setClientInfo(String, String)
     */
    @Override
    public void setClientInfo(String name, String value) throws SQLClientInfoException {
        internalConn.setClientInfo(name, value);
    }

    /**
     * Method isWrapperFor.
     * 
     * @param iface
     * @return boolean
     * @throws SQLException
     * @see java.sql.Wrapper#isWrapperFor(Class)
     */
    @Override
    public boolean isWrapperFor(Class iface) throws SQLException {
        return internalConn.isWrapperFor(iface);
    }

    /**
     * Method unwrap.
     * 
     * @param iface
     * @return T
     * @throws SQLException
     * @see java.sql.Wrapper#unwrap(Class)
     */
    @Override
    public  T unwrap(Class iface) throws SQLException {
        return internalConn.unwrap(iface);
    }

    /**
     * Method toString.
     * 
     * @return String
     */
    @Override
    public String toString() {
        return internalConn.toString();
    }

    /**
     * Method hashCode.
     * 
     * @return int
     */
    @Override
    public int hashCode() {
        return internalConn.hashCode();
    }

    /**
     * Method equals.
     * 
     * @param obj
     * @return boolean
     */
    @Override
    public boolean equals(Object obj) {
        return this == obj || (obj instanceof PoolableConnection && ((PoolableConnection) obj).internalConn.equals(internalConn));
    }

    @Override
    public void abort(Executor executor) throws SQLException {
        internalConn.abort(executor);
    }

    @Override
    public int getNetworkTimeout() throws SQLException {
        return internalConn.getNetworkTimeout();
    }

    @Override
    public String getSchema() throws SQLException {
        return internalConn.getSchema();
    }

    @Override
    public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
        internalConn.setNetworkTimeout(executor, milliseconds);
    }

    @Override
    public void setSchema(String schema) throws SQLException {
        internalConn.setSchema(schema);
    }

    /**
     * @author Haiyang Li
     * @version $Revision: 0.8 $
     */
    protected static class CachedStatmentKey {
        private final String sql;
        private final int autoGeneratedKeys;
        private final int resultSetType;
        private final int resultSetConcurrency;
        private final int resultSetHoldability;
        private int h;

        public CachedStatmentKey(String sql, int autoGeneratedKeys, int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
            this.sql = sql;
            this.autoGeneratedKeys = autoGeneratedKeys;
            this.resultSetType = resultSetType;
            this.resultSetConcurrency = resultSetConcurrency;
            this.resultSetHoldability = resultSetHoldability;
        }

        @Override
        public int hashCode() {
            if (h == 0) {
                h = 17;
                h = (h * 31) + sql.hashCode();
                h = (h * 31) + autoGeneratedKeys;
                h = (h * 31) + resultSetType;
                h = (h * 31) + resultSetConcurrency;
                h = (h * 31) + resultSetHoldability;
            }

            return h;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }

            if (obj instanceof CachedStatmentKey) {
                CachedStatmentKey other = (CachedStatmentKey) obj;

                return N.equals(sql, other.sql) && (autoGeneratedKeys == other.autoGeneratedKeys) && (resultSetType == other.resultSetType)
                        && (resultSetConcurrency == other.resultSetConcurrency) && (resultSetHoldability == other.resultSetHoldability);
            }

            return false;
        }

        @Override
        public String toString() {
            return sql;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy