/**
   * Asserts that closing the logical statement and caching the physical one does close the logical
   * one but not the physical one.
   *
   * @throws SQLException if a JDBC operation fails
   */
  public void testCloseWhenStatementShallBeCached() throws SQLException {
    // Initial setup.
    final String sql = "values 9";
    java.sql.PreparedStatement ps = prepareStatement(sql);
    JDBCStatementCache cache = new JDBCStatementCache(10);
    StatementKey stmtKey = insertStatementIntoCache(cache, ps, sql);
    LogicalStatementEntity logic = createLogicalStatementEntity(sql, false, cache);
    assertSame(ps, logic.getPhysPs());
    assertFalse(logic.isLogicalEntityClosed());

    // Close the statement, it should go into the cache.
    logic.close();
    assertTrue(logic.isLogicalEntityClosed());
    // Use the physical statement.
    java.sql.ResultSet rs = ps.executeQuery();
    JDBC.assertSingleValueResultSet(rs, "9");
    // Get the statement from the cache.
    assertSame(ps, cache.getCached(stmtKey));
  }
 /**
  * Tries to execute a method on a logical statement when the underlying physical statement has
  * been closed without the logical connection knowing.
  *
  * @throws SQLException if something goes wrong...
  */
 public void testClosedUnderlyingStatement() throws SQLException {
   // Initial setup.
   final String sql = "values 19";
   java.sql.PreparedStatement ps = prepareStatement(sql);
   JDBCStatementCache cache = new JDBCStatementCache(10);
   insertStatementIntoCache(cache, ps, sql);
   LogicalStatementEntity logic = createLogicalStatementEntity(sql, false, cache);
   assertSame(ps, logic.getPhysPs());
   assertFalse(logic.isLogicalEntityClosed());
   java.sql.PreparedStatement logicalPs = (java.sql.PreparedStatement) logic;
   assertNotNull(logicalPs.getMetaData());
   ps.close();
   try {
     logicalPs.getMetaData();
     fail("Getting meta data on a closed connection should fail");
   } catch (SQLException sqle) {
     assertSQLState("XJ012", sqle);
   }
   logicalPs.close();
 }
  /**
   * Tests that the cache throws out the least frequently used statement when it reaches its maximum
   * capacity, and that the thrown out statement is closed in the process.
   *
   * <p>Note: This test assumes things about the replacement policy.
   *
   * @throws SQLException if a JDBC operation fails
   */
  public void testEvictionFromCache() throws SQLException {
    // Initial setup.
    JDBCStatementCache cache = new JDBCStatementCache(2);
    final String sql1 = "values 1";
    final String sql2 = "values 2";
    final String sql3 = "values 3";
    // Create three physical prepares statements.
    java.sql.PreparedStatement ps1 = prepareStatement(sql1);
    java.sql.PreparedStatement ps2 = prepareStatement(sql2);
    java.sql.PreparedStatement ps3 = prepareStatement(sql3);
    // Insert the two first physical statements, the get logical wrappers.
    StatementKey stmtKey1 = insertStatementIntoCache(cache, ps1, sql1);
    StatementKey stmtKey2 = insertStatementIntoCache(cache, ps2, sql2);
    LogicalStatementEntity logic1 = createLogicalStatementEntity(sql1, false, cache);
    LogicalStatementEntity logic2 = createLogicalStatementEntity(sql2, false, cache);
    // Insert the last physical statement and get the logical wrapper.
    StatementKey stmtKey3 = insertStatementIntoCache(cache, ps3, sql3);
    LogicalStatementEntity logic3 = createLogicalStatementEntity(sql3, false, cache);
    assertSame(ps1, logic1.getPhysPs());
    assertSame(ps2, logic2.getPhysPs());
    assertSame(ps3, logic3.getPhysPs());

    // Close two first logical statements, putting them back into the cache.
    logic1.close();
    logic2.close();
    // Assert both of the statements are open.
    JDBC.assertSingleValueResultSet(ps1.executeQuery(), "1");
    JDBC.assertSingleValueResultSet(ps2.executeQuery(), "2");
    // Close the third statement. It should be cached, but since the cache
    // will exceed its maximum capacity, the first statement will be thrown
    // out and it should be closed in the process.
    logic3.close();
    JDBC.assertSingleValueResultSet(ps3.executeQuery(), "3");
    assertNull("ps1 still in the cache", cache.getCached(stmtKey1));
    try {
      ps1.executeQuery();
      fail("ps1 should have been closed by the cache");
    } catch (SQLException sqle) {
      assertSQLState("XJ012", sqle);
    }
    // Make sure the right statements are returned from the cache.
    assertSame(ps2, cache.getCached(stmtKey2));
    assertSame(ps3, cache.getCached(stmtKey3));
  }
 /**
  * Verifies that the logical statement representing a callable statement behaves correctly when it
  * has been closed.
  *
  * @throws SQLException if a JDBC operation fails
  */
 public void testCloseBehaviorExternalCs() throws SQLException {
   final String sql = "values 3";
   java.sql.CallableStatement cs = prepareCall(sql);
   JDBCStatementCache cache = new JDBCStatementCache(10);
   insertStatementIntoCache(cache, cs, sql);
   LogicalStatementEntity logic = createLogicalStatementEntity(sql, true, cache);
   assertSame(cs, logic.getPhysCs());
   assertFalse(logic.isLogicalEntityClosed());
   logic.close();
   assertTrue(logic.isLogicalEntityClosed());
   logic.close();
   logic.close();
   assertTrue(logic.isLogicalEntityClosed());
   try {
     logic.getPhysCs();
     fail("Should have thrown exception");
   } catch (SQLException sqle) {
     assertSQLState("XJ012", sqle);
   }
 }
  /**
   * Tests that a statement equal to one in the cache is not cached when closing the logical
   * statement, and that the physical statement is closed.
   *
   * @throws SQLException if a JDBC operation fails
   */
  public void testCloseOnDuplicateStatement() throws SQLException {
    // Initial setup.
    final String sql = "values 7";
    java.sql.PreparedStatement ps = prepareStatement(sql);
    JDBCStatementCache cache = new JDBCStatementCache(10);
    StatementKey stmtKey = insertStatementIntoCache(cache, ps, sql);
    LogicalStatementEntity logic = createLogicalStatementEntity(sql, false, cache);
    assertSame(ps, logic.getPhysPs());
    assertFalse(logic.isLogicalEntityClosed());

    // Put a statement into the cache.
    // assertTrue(cache.cacheStatement(stmtKey, ps));
    // Create a second statement, equal to the first.
    java.sql.PreparedStatement psDupe = prepareStatement(sql);
    insertStatementIntoCache(cache, psDupe, sql);
    LogicalStatementEntity logicDupe = createLogicalStatementEntity(sql, false, cache);
    // Close the first logical entry, to put the physical statement back
    // into the cache.
    logic.close();
    // When we ask the logical entity to close the statement now, the
    // underlying physical prepared statement should actually be closed.
    logicDupe.close();
    assertTrue(logicDupe.isLogicalEntityClosed());
    // Since we are possibly running in a pre-JDBC 4 environment, try do do
    // something to provoke an exception.
    try {
      psDupe.execute();
      fail("Statement should have been closed and throw an exception");
    } catch (SQLException sqle) {
      assertSQLState("XJ012", sqle);
    }

    // The cached statement should still be open.
    java.sql.PreparedStatement psCached = cache.getCached(stmtKey);
    assertSame(ps, psCached);
    java.sql.ResultSet rs = psCached.executeQuery();
    JDBC.assertSingleValueResultSet(rs, "7");
  }