private synchronized Connection getConnection3() throws SQLException {
   if (isDisposed) { // test again within synchronized lock
     throw new IllegalStateException("Connection pool has been disposed.");
   }
   PooledConnection pconn;
   if (!recycledConnections.isEmpty()) {
     pconn = recycledConnections.remove();
   } else {
     pconn = dataSource.getPooledConnection();
     pconn.addConnectionEventListener(poolConnectionEventListener);
   }
   Connection conn;
   try {
     // The JDBC driver may call ConnectionEventListener.connectionErrorOccurred()
     // from within PooledConnection.getConnection(). To detect this within
     // disposeConnection(), we temporarily set connectionInTransition.
     connectionInTransition = pconn;
     conn = pconn.getConnection();
   } finally {
     connectionInTransition = null;
   }
   activeConnections++;
   assertInnerState();
   return conn;
 }
 public boolean validateObject(Object key, Object obj) {
   boolean valid = false;
   if (obj instanceof PooledConnectionAndInfo) {
     PooledConnection pconn = ((PooledConnectionAndInfo) obj).getPooledConnection();
     String query = _validationQuery;
     if (null != query) {
       Connection conn = null;
       Statement stmt = null;
       ResultSet rset = null;
       // logical Connection from the PooledConnection must be closed
       // before another one can be requested and closing it will
       // generate an event. Keep track so we know not to return
       // the PooledConnection
       muteMap.put(pconn, null);
       try {
         conn = pconn.getConnection();
         stmt = conn.createStatement();
         rset = stmt.executeQuery(query);
         if (rset.next()) {
           valid = true;
         } else {
           valid = false;
         }
         if (_rollbackAfterValidation) {
           conn.rollback();
         }
       } catch (Exception e) {
         valid = false;
       } finally {
         if (rset != null) {
           try {
             rset.close();
           } catch (Throwable t) {
             // ignore
           }
         }
         if (stmt != null) {
           try {
             stmt.close();
           } catch (Throwable t) {
             // ignore
           }
         }
         if (conn != null) {
           try {
             conn.close();
           } catch (Throwable t) {
             // ignore
           }
         }
         muteMap.remove(pconn);
       }
     } else {
       valid = true;
     }
   } else {
     valid = false;
   }
   return valid;
 }
  /**
   * Creates a new {@link PooledConnectionAndInfo} from the given {@link UserPassKey}.
   *
   * @param upkey {@link UserPassKey} containing user credentials
   * @throws SQLException if the connection could not be created.
   * @see org.apache.tomcat.dbcp.pool2.KeyedPooledObjectFactory#makeObject(java.lang.Object)
   */
  @Override
  public synchronized PooledObject<PooledConnectionAndInfo> makeObject(UserPassKey upkey)
      throws Exception {
    PooledConnectionAndInfo pci = null;

    PooledConnection pc = null;
    String username = upkey.getUsername();
    String password = upkey.getPassword();
    if (username == null) {
      pc = _cpds.getPooledConnection();
    } else {
      pc = _cpds.getPooledConnection(username, password);
    }

    if (pc == null) {
      throw new IllegalStateException(
          "Connection pool data source returned null from getPooledConnection");
    }

    // should we add this object as a listener or the pool.
    // consider the validateObject method in decision
    pc.addConnectionEventListener(this);
    pci = new PooledConnectionAndInfo(pc, username, password);
    pcMap.put(pc, pci);

    return new DefaultPooledObject<>(pci);
  }
 /**
  * This will be called if the Connection returned by the getConnection method came from a
  * PooledConnection, and the user calls the close() method of this connection object. What we need
  * to do here is to release this PooledConnection from our pool...
  */
 @Override
 public void connectionClosed(ConnectionEvent event) {
   PooledConnection pc = (PooledConnection) event.getSource();
   // if this event occurred because we were validating, or if this
   // connection has been marked for removal, ignore it
   // otherwise return the connection to the pool.
   if (!validatingSet.contains(pc)) {
     PooledConnectionAndInfo pci = pcMap.get(pc);
     if (pci == null) {
       throw new IllegalStateException(NO_KEY_MESSAGE);
     }
     try {
       _pool.returnObject(pci.getUserPassKey(), pci);
     } catch (Exception e) {
       System.err.println("CLOSING DOWN CONNECTION AS IT COULD " + "NOT BE RETURNED TO THE POOL");
       pc.removeConnectionEventListener(this);
       try {
         _pool.invalidateObject(pci.getUserPassKey(), pci);
       } catch (Exception e3) {
         System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + pci);
         e3.printStackTrace();
       }
     }
   }
 }
  /**
   * @param key
   * @throws SQLException if the connection could not be created.
   * @see org.apache.commons.pool.KeyedPoolableObjectFactory#makeObject(java.lang.Object)
   */
  public synchronized Object makeObject(Object key) throws Exception {
    Object obj = null;
    UserPassKey upkey = (UserPassKey) key;

    PooledConnection pc = null;
    String username = upkey.getUsername();
    String password = upkey.getPassword();
    if (username == null) {
      pc = _cpds.getPooledConnection();
    } else {
      pc = _cpds.getPooledConnection(username, password);
    }

    if (pc == null) {
      throw new IllegalStateException(
          "Connection pool data source returned null from getPooledConnection");
    }

    // should we add this object as a listener or the pool.
    // consider the validateObject method in decision
    pc.addConnectionEventListener(this);
    obj = new PooledConnectionAndInfo(pc, username, password);
    pcMap.put(pc, obj);
    cleanupListeners();

    return obj;
  }
 /** Closes the PooledConnection and stops listening for events from it. */
 @Override
 public void destroyObject(UserPassKey key, PooledObject<PooledConnectionAndInfo> p)
     throws Exception {
   PooledConnection pc = p.getObject().getPooledConnection();
   pc.removeConnectionEventListener(this);
   pcMap.remove(pc);
   pc.close();
 }
 /**
  * Closes the PooledConnection and marks it for removal from the pcMap and for listener cleanup.
  * Adds it to muteMap so connectionClosed events generated by this or other actions are ignored.
  */
 public void destroyObject(Object key, Object obj) throws Exception {
   if (obj instanceof PooledConnectionAndInfo) {
     PooledConnection pc = ((PooledConnectionAndInfo) obj).getPooledConnection();
     cleanupMap.put(pc, null); // mark for cleanup
     muteMap.put(pc, null); // ignore events until listener is removed
     pc.close();
   }
 }
    private void testBug62452WithConnection(PooledConnection con) throws Exception {
        this.pstmt = con.getConnection().prepareStatement("SELECT 1");
        this.rs = this.pstmt.executeQuery();
        con.close();

        // If PooledConnection is already closed by some reason a NullPointerException was thrown on the next line
        // because the closed connection has nulled out the list that it synchronises on when the closed event is fired.
        this.pstmt.close();
    }
Ejemplo n.º 9
0
  /**
   * Tests whether Connection.changeUser() (and thus pooled connections) restore character set
   * information correctly.
   *
   * @throws Exception if the test fails.
   */
  public void testChangeUserAndCharsets() throws Exception {
    if (versionMeetsMinimum(4, 1)) {
      MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
      ds.setURL(BaseTestCase.dbUrl);
      ds.setCharacterEncoding("utf-8");
      PooledConnection pooledConnection = ds.getPooledConnection();

      Connection connToMySQL = pooledConnection.getConnection();
      this.rs = connToMySQL.createStatement().executeQuery("SELECT @@character_set_results");
      assertTrue(this.rs.next());

      String toCheck = null;

      if (versionMeetsMinimum(4, 1, 15)) {
        if (versionMeetsMinimum(5, 0)) {
          if (versionMeetsMinimum(5, 0, 13)) {
            toCheck = null;
          } else {
            toCheck = "NULL";
          }
        } else {
          toCheck = null;
        }
      } else {
        toCheck = "NULL";
      }

      assertEquals(toCheck, this.rs.getString(1));

      this.rs =
          connToMySQL
              .createStatement()
              .executeQuery("SHOW SESSION VARIABLES LIKE 'character_set_client'");
      assertTrue(this.rs.next());

      // Cause of utf8mb4
      assertEquals(0, this.rs.getString(2).indexOf("utf8"));

      connToMySQL.close();

      connToMySQL = pooledConnection.getConnection();
      this.rs = connToMySQL.createStatement().executeQuery("SELECT @@character_set_results");
      assertTrue(this.rs.next());
      assertEquals(toCheck, this.rs.getString(1));

      this.rs =
          connToMySQL
              .createStatement()
              .executeQuery("SHOW SESSION VARIABLES LIKE 'character_set_client'");
      assertTrue(this.rs.next());

      // Cause of utf8mb4
      assertEquals(0, this.rs.getString(2).indexOf("utf8"));

      pooledConnection.getConnection().close();
    }
  }
Ejemplo n.º 10
0
 private void getPooledConnection() throws Exception {
   Context ctx = new InitialContext();
   ConnectionPoolDataSource ds = (ConnectionPoolDataSource) ctx.lookup(DATA_SOURCE);
   PooledConnection pooledConnection = ds.getPooledConnection();
   connection = pooledConnection.getConnection(); // Obtain connection from pool
   if (connection == null) {
     throw new Exception("Failed to get database connection.");
   } else {
     return;
   }
 }
Ejemplo n.º 11
0
  //
  // Find all the objects inside the ConnectionPooledDataSource and vet them.
  //
  private void vetConnectionPooledDataSource(
      HashSet<String> unsupportedList, HashSet<String> notUnderstoodList) throws Exception {
    ConnectionPoolDataSource ds = J2EEDataSource.getConnectionPoolDataSource();
    PooledConnection pc =
        ds.getPooledConnection(
            getTestConfiguration().getUserName(), getTestConfiguration().getUserPassword());
    Connection conn = pc.getConnection();

    vetObject(ds, unsupportedList, notUnderstoodList);
    vetObject(pc, unsupportedList, notUnderstoodList);

    connectionWorkhorse(conn, unsupportedList, notUnderstoodList);
  }
 /**
  * Validates a pooled connection.
  *
  * @param key ignored
  * @param p wrapped {@link PooledConnectionAndInfo} containing the connection to validate
  * @return true if validation succeeds
  */
 @Override
 public boolean validateObject(UserPassKey key, PooledObject<PooledConnectionAndInfo> p) {
   try {
     validateLifetime(p);
   } catch (Exception e) {
     return false;
   }
   boolean valid = false;
   PooledConnection pconn = p.getObject().getPooledConnection();
   if (null == _validationQuery) {
     int timeout = _validationQueryTimeout;
     if (timeout < 0) {
       timeout = 0;
     }
     try {
       valid = pconn.getConnection().isValid(timeout);
     } catch (SQLException e) {
       valid = false;
     }
   } else {
     Connection conn = null;
     Statement stmt = null;
     ResultSet rset = null;
     // logical Connection from the PooledConnection must be closed
     // before another one can be requested and closing it will
     // generate an event. Keep track so we know not to return
     // the PooledConnection
     validatingSet.add(pconn);
     try {
       conn = pconn.getConnection();
       stmt = conn.createStatement();
       rset = stmt.executeQuery(_validationQuery);
       if (rset.next()) {
         valid = true;
       } else {
         valid = false;
       }
       if (_rollbackAfterValidation) {
         conn.rollback();
       }
     } catch (Exception e) {
       valid = false;
     } finally {
       Utils.closeQuietly(rset);
       Utils.closeQuietly(stmt);
       Utils.closeQuietly(conn);
       validatingSet.remove(pconn);
     }
   }
   return valid;
 }
  protected ConnectionPoolDataSource testCPDS(String username, String password)
      throws javax.naming.NamingException, SQLException {
    // The source of physical db connections
    ConnectionPoolDataSource cpds = this.dataSource;
    if (cpds == null) {
      Context ctx = null;
      if (jndiEnvironment == null) {
        ctx = new InitialContext();
      } else {
        ctx = new InitialContext(jndiEnvironment);
      }
      Object ds = ctx.lookup(dataSourceName);
      if (ds instanceof ConnectionPoolDataSource) {
        cpds = (ConnectionPoolDataSource) ds;
      } else {
        throw new SQLException(
            "Illegal configuration: "
                + "DataSource "
                + dataSourceName
                + " ("
                + ds.getClass().getName()
                + ")"
                + " doesn't implement javax.sql.ConnectionPoolDataSource");
      }
    }

    // try to get a connection with the supplied username/password
    PooledConnection conn = null;
    try {
      if (username != null) {
        conn = cpds.getPooledConnection(username, password);
      } else {
        conn = cpds.getPooledConnection();
      }
      if (conn == null) {
        throw new SQLException("Cannot connect using the supplied username/password");
      }
    } finally {
      if (conn != null) {
        try {
          conn.close();
        } catch (SQLException e) {
          // at least we could connect
        }
      }
    }
    return cpds;
  }
 private void closeConnectionAndIgnoreException(PooledConnection pconn) {
   try {
     pconn.close();
   } catch (SQLException e) {
     log("Error while closing database connection: " + e.toString());
   }
 }
 /** Closes all unused pooled connections. */
 public synchronized void dispose() throws SQLException {
   if (isDisposed) {
     return;
   }
   isDisposed = true;
   SQLException e = null;
   while (!recycledConnections.isEmpty()) {
     PooledConnection pconn = recycledConnections.remove();
     try {
       pconn.close();
     } catch (SQLException e2) {
       if (e == null) {
         e = e2;
       }
     }
   }
   if (e != null) {
     throw e;
   }
 }
  /**
   * If a fatal error occurs, close the underlying physical connection so as not to be returned in
   * the future
   */
  @Override
  public void connectionErrorOccurred(ConnectionEvent event) {
    PooledConnection pc = (PooledConnection) event.getSource();
    if (null != event.getSQLException()) {
      System.err.println(
          "CLOSING DOWN CONNECTION DUE TO INTERNAL ERROR (" + event.getSQLException() + ")");
    }
    pc.removeConnectionEventListener(this);

    PooledConnectionAndInfo info = pcMap.get(pc);
    if (info == null) {
      throw new IllegalStateException(NO_KEY_MESSAGE);
    }
    try {
      _pool.invalidateObject(info.getUserPassKey(), info);
    } catch (Exception e) {
      System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + info);
      e.printStackTrace();
    }
  }
 /**
  * Cleans up pooled connections from cleanupMap. 1) remove PoolableConnectionAndInfo wrapper from
  * pcMap 2) remove from MuteMap
  */
 private void cleanupListeners() {
   try {
     Iterator iter = cleanupMap.keySet().iterator();
     while (iter.hasNext()) {
       PooledConnection pc = (PooledConnection) iter.next();
       pcMap.remove(pc);
       muteMap.remove(pc);
       try {
         pc.removeConnectionEventListener(this);
       } catch (Exception ex) {
         System.err.println("EXCEPTION REMOVING CONNECTION LISTENER ");
         ex.printStackTrace();
       }
     }
   } catch (Exception e) {
     System.err.println("EXCEPTION CLEANING UP CONNECTION LISTENERS ");
     e.printStackTrace();
   } finally {
     cleanupMap.clear();
   }
 }
 /**
  * Test pooled connetion for chinese database name, user and password.
  *
  * @throws SQLException
  */
 public void testCPDSConnect() throws SQLException {
   // Test chinese database name.
   ConnectionPoolDataSource ds = J2EEDataSource.getConnectionPoolDataSource();
   J2EEDataSource.setBeanProperty(ds, "databaseName", "\u4e10");
   J2EEDataSource.setBeanProperty(ds, "createDatabase", "create");
   try {
     PooledConnection poolConn = ds.getPooledConnection();
     Connection conn = poolConn.getConnection();
     conn.close();
   } catch (SQLException se) {
     if (usingEmbedded()) throw se;
     else assertSQLState("22005", se);
   }
   // Chinese user
   try {
     J2EEDataSource.setBeanProperty(ds, "user", "\u4e10");
     PooledConnection poolConn = ds.getPooledConnection();
     Connection conn = poolConn.getConnection();
     conn.close();
   } catch (SQLException se) {
     if (usingEmbedded()) throw se;
     else assertSQLState("22005", se);
   }
   // Chinese password
   try {
     J2EEDataSource.setBeanProperty(ds, "password", "\u4e10");
     PooledConnection poolConn = ds.getPooledConnection();
     Connection conn = poolConn.getConnection();
     conn.close();
   } catch (SQLException se) {
     if (usingEmbedded()) throw se;
     else assertSQLState("22005", se);
   }
 }
  /** Creates a Pooled connection and adds it to the connection pool. */
  private void installConnection() throws EmanagerDatabaseException {
    logger.debug("enter");

    PooledConnection connection;

    try {
      connection = poolDataSource.getPooledConnection();
      connection.addConnectionEventListener(this);
      connection.getConnection().setAutoCommit(false);
      synchronized (connectionPool) {
        connectionPool.add(connection);
        logger.debug("Database connection added.");
      }
    } catch (SQLException ex) {
      logger.fatal("exception caught while obtaining database " + "connection: ex = " + ex);
      SQLException ex1 = ex.getNextException();
      while (ex1 != null) {
        logger.fatal("chained sql exception ex1 = " + ex1);
        SQLException nextEx = ex1.getNextException();
        ex1 = nextEx;
      }
      String logString;
      EmanagerDatabaseException ede;

      logString =
          EmanagerDatabaseStatusCode.DatabaseConnectionFailure.getStatusCodeDescription()
              + ex.getMessage();

      logger.fatal(logString);
      ede =
          new EmanagerDatabaseException(
              EmanagerDatabaseStatusCode.DatabaseConnectionFailure, logString);
      throw ede;
    }
  }
 private synchronized void disposeConnection(PooledConnection pconn) {
   pconn.removeConnectionEventListener(poolConnectionEventListener);
   if (!recycledConnections.remove(pconn) && pconn != connectionInTransition) {
     // If the PooledConnection is not in the recycledConnections list
     // and is not currently within a PooledConnection.getConnection() call,
     // we assume that the connection was active.
     if (activeConnections <= 0) {
       throw new AssertionError();
     }
     activeConnections--;
     semaphore.release();
   }
   closeConnectionAndIgnoreException(pconn);
   assertInnerState();
 }
  /** @roseuid 3F3A89D40175 */
  public void shutdown() {
    logger.debug("Enter");

    Iterator iter;
    PooledConnection pooledConnection;

    SHUTTING_DOWN = true;
    iter = connectionPool.iterator();
    while (iter.hasNext()) {
      pooledConnection = (PooledConnection) iter.next();

      try {
        if (!pooledConnection.getConnection().isClosed()) {
          pooledConnection.getConnection().close();
        }
      } catch (Exception ex) {
        // We don't care what happens here, we're on the way out!
      }
    }

    connectionPool.clear();
  }
Ejemplo n.º 22
0
 @Override
 public void addConnectionEventListener(ConnectionEventListener eventTarget) {
   passthru.addConnectionEventListener(eventTarget);
 }
Ejemplo n.º 23
0
 @Override
 public void removeConnectionEventListener(ConnectionEventListener eventTarget) {
   passthru.removeConnectionEventListener(eventTarget);
 }
Ejemplo n.º 24
0
 @Override
 public void addStatementEventListener(StatementEventListener listener) {
   passthru.addStatementEventListener(listener);
 }
Ejemplo n.º 25
0
 @Override
 public void removeStatementEventListener(StatementEventListener listener) {
   passthru.removeStatementEventListener(listener);
 }
 public Connection getConnection(String username, String password) throws SQLException {
   PooledConnection pc = getPoolManager().getPool(username, password).checkoutPooledConnection();
   return pc.getConnection();
 }
 // implementation of javax.sql.DataSource
 public Connection getConnection() throws SQLException {
   PooledConnection pc = getPoolManager().getPool().checkoutPooledConnection();
   return pc.getConnection();
 }
  /**
   * @return Connection
   * @roseuid 3F3A5FFD0338
   */
  public Connection getConnection() throws EmanagerDatabaseException {
    long connectionId;
    Connection connection;
    PooledConnection pooledConnection;

    connection = null;
    pooledConnection = null;
    connectionId = InvalidConnectionId;

    try {
      synchronized (connectionPool) {
        if (!connectionPool.isEmpty()) {
          try {
            boolean connectionClosed;

            connectionClosed = false;

            pooledConnection = (PooledConnection) connectionPool.remove(0);
            connection = pooledConnection.getConnection();
            connection.clearWarnings();
            connectionId = getConnectionID(connection);
            connectionClosed = connection.isClosed();
            if (connectionId == InvalidConnectionId || connectionClosed == true) {
              logger.debug("Pooled connection closed.");
              connection = null;
            }
          } catch (SQLException sqe) {
            logger.debug("Pooled connection closed.");
            connection = null;
          }
        }
      }

      if (connection == null) {
        logger.debug("Getting a new connection.");
        pooledConnection = poolDataSource.getPooledConnection();
        pooledConnection.addConnectionEventListener(this);
        connection = pooledConnection.getConnection();
        connection.clearWarnings();
        connectionId = getConnectionID(connection);
      }
    } catch (SQLException sqe) {
      String logString;
      EmanagerDatabaseException ede;

      logString =
          EmanagerDatabaseStatusCode.UnableToGetPooledConnection.getStatusCodeDescription()
              + sqe.getMessage();

      logger.error(logString);
      ede =
          new EmanagerDatabaseException(
              EmanagerDatabaseStatusCode.UnableToGetPooledConnection, logString);
      throw ede;
    }

    if (connectionId == InvalidConnectionId) {
      EmanagerDatabaseException ede;
      ede =
          new EmanagerDatabaseException(
              EmanagerDatabaseStatusCode.UnableToGetPooledConnection,
              EmanagerDatabaseStatusCode.UnableToGetPooledConnection.getStatusCodeDescription());
      throw ede;
    }

    logger.debug(
        "\n*****************************"
            + "\nPooled Connection Init"
            + "\nCon ID:"
            + connectionId
            + "\nCon Object:"
            + pooledConnection
            + "\nPool Object:"
            + connection
            + "\n*****************************");

    return connection;
  }
  /** Attempt to establish a database connection. */
  public synchronized Connection getConnection(String username, String password)
      throws SQLException {
    if (isNew) {
      throw new SQLException(
          "Must set the ConnectionPoolDataSource "
              + "through setDataSourceName or setConnectionPoolDataSource"
              + " before calling getConnection.");
    }

    getConnectionCalled = true;
    Map pools = (Map) dsInstanceMap.get(instanceKey);
    PoolKey key = getPoolKey(username);
    Object pool = pools.get(key);
    if (pool == null) {
      try {
        registerPool(username, password);
        pool = pools.get(key);
      } catch (Exception e) {
        e.printStackTrace();
        throw new SQLException(e.getMessage());
      }
    }

    PooledConnectionAndInfo info = null;
    if (pool instanceof ObjectPool) {
      try {
        info = (PooledConnectionAndInfo) ((ObjectPool) pool).borrowObject();
      } catch (NoSuchElementException e) {
        closeDueToException(info);
        throw new SQLException(e.getMessage());
      } catch (RuntimeException e) {
        closeDueToException(info);
        throw e;
      } catch (SQLException e) {
        closeDueToException(info);
        throw e;
      } catch (Exception e) {
        closeDueToException(info);
        throw new SQLException(e.getMessage());
      }
    } else {
      // assume KeyedObjectPool
      try {
        UserPassKey upkey = getUserPassKey(username, password);
        info = (PooledConnectionAndInfo) ((KeyedObjectPool) pool).borrowObject(upkey);
      } catch (NoSuchElementException e) {
        closeDueToException(info);
        throw new SQLException(e.getMessage());
      } catch (RuntimeException e) {
        closeDueToException(info);
        throw e;
      } catch (SQLException e) {
        closeDueToException(info);
        throw e;
      } catch (Exception e) {
        closeDueToException(info);
        throw new SQLException(e.getMessage());
      }
    }
    if (!(null == password ? null == info.getPassword() : password.equals(info.getPassword()))) {
      closeDueToException(info);
      throw new SQLException(
          "Given password did not match password used " + "to create the PooledConnection.");
    }
    PooledConnection pc = info.getPooledConnection();

    boolean defaultAutoCommit = isDefaultAutoCommit();
    if (username != null) {
      Boolean userMax = getPerUserDefaultAutoCommit(username);
      if (userMax != null) {
        defaultAutoCommit = userMax.booleanValue();
      }
    }

    boolean defaultReadOnly = isDefaultReadOnly();
    if (username != null) {
      Boolean userMax = getPerUserDefaultReadOnly(username);
      if (userMax != null) {
        defaultReadOnly = userMax.booleanValue();
      }
    }

    Connection con = pc.getConnection();
    con.setAutoCommit(defaultAutoCommit);
    con.setReadOnly(defaultReadOnly);
    return con;
  }
Ejemplo n.º 30
0
 @Override
 public void close() throws SQLException {
   passthru.close();
 }