You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by kr...@apache.org on 2008/02/21 11:26:35 UTC

svn commit: r629734 [2/2] - in /db/derby/code/trunk/java: client/org/apache/derby/client/am/ client/org/apache/derby/client/net/ testing/org/apache/derby/client/ testing/org/apache/derby/client/am/

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/ClientJDBCObjectFactoryImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/net/ClientJDBCObjectFactoryImpl.java?rev=629734&r1=629733&r2=629734&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/ClientJDBCObjectFactoryImpl.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/ClientJDBCObjectFactoryImpl.java Thu Feb 21 02:26:31 2008
@@ -26,18 +26,23 @@
 import java.sql.SQLException;
 import org.apache.derby.client.ClientPooledConnection;
 import org.apache.derby.client.ClientXAConnection;
+import org.apache.derby.client.am.CachingLogicalConnection;
 import org.apache.derby.client.am.CallableStatement;
 import org.apache.derby.client.am.ClientJDBCObjectFactory;
 import org.apache.derby.client.am.LogicalConnection;
 import org.apache.derby.client.am.ParameterMetaData;
 import org.apache.derby.client.am.PreparedStatement;
 import org.apache.derby.client.am.Configuration;
+import org.apache.derby.client.am.LogicalCallableStatement;
+import org.apache.derby.client.am.LogicalPreparedStatement;
 import org.apache.derby.client.am.LogWriter;
 import org.apache.derby.client.am.Agent;
 import org.apache.derby.client.am.Section;
 import org.apache.derby.client.am.Statement;
 import org.apache.derby.client.am.SqlException;
 import org.apache.derby.client.am.Cursor;
+import org.apache.derby.client.am.stmtcache.JDBCStatementCache;
+import org.apache.derby.client.am.stmtcache.StatementKey;
 import org.apache.derby.client.net.NetLogWriter;
 import org.apache.derby.jdbc.ClientBaseDataSource;
 import org.apache.derby.jdbc.ClientXADataSource;
@@ -112,6 +117,26 @@
         return new LogicalConnection(physicalConnection, pooledConnection);
     }
     
+   /**
+    * Returns an instance of a {@code CachingLogicalConnection}, which
+    * provides caching of prepared statements.
+    *
+    * @param physicalConnection the underlying physical connection
+    * @param pooledConnection the pooled connection
+    * @param stmtCache statement cache
+    * @return A logical connection with statement caching capabilities.
+    *
+    * @throws SqlException if creation of the logical connection fails
+    */
+    public LogicalConnection newCachingLogicalConnection(
+            org.apache.derby.client.am.Connection physicalConnection,
+            ClientPooledConnection pooledConnection,
+            JDBCStatementCache stmtCache) throws SqlException {
+        return new CachingLogicalConnection(physicalConnection,
+                                            pooledConnection,
+                                            stmtCache);
+    }
+
     /**
      * This method returns an instance of PreparedStatement
      * which implements java.sql.PreparedStatement. It has the
@@ -180,6 +205,36 @@
             throws SqlException {
         return new PreparedStatement(agent,connection,sql,type,concurrency,
                 holdability,autoGeneratedKeys,columnNames, columnIndexes, cpc);
+    }
+
+    /**
+     * Returns a new logcial prepared statement object.
+     *
+     * @param ps underlying physical prepared statement
+     * @param stmtKey key for the underlying physical prepared statement
+     * @param stmtCache the statement cache
+     * @return A logical prepared statement.
+     */
+    public java.sql.PreparedStatement newLogicalPreparedStatement(
+            java.sql.PreparedStatement ps,
+            StatementKey stmtKey,
+            JDBCStatementCache stmtCache) {
+        return new LogicalPreparedStatement(ps, stmtKey, stmtCache);
+    }
+
+    /**
+     * Returns a new logical callable statement object.
+     *
+     * @param cs underlying physical callable statement
+     * @param stmtKey key for the underlying physical callable statement
+     * @param stmtCache the statement cache
+     * @return A logical callable statement.
+     */
+    public java.sql.CallableStatement newLogicalCallableStatement(
+            java.sql.CallableStatement cs,
+            StatementKey stmtKey,
+            JDBCStatementCache stmtCache) {
+        return new LogicalCallableStatement(cs, stmtKey, stmtCache);
     }
 
     /**

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/ClientJDBCObjectFactoryImpl40.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/net/ClientJDBCObjectFactoryImpl40.java?rev=629734&r1=629733&r2=629734&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/ClientJDBCObjectFactoryImpl40.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/ClientJDBCObjectFactoryImpl40.java Thu Feb 21 02:26:31 2008
@@ -25,6 +25,7 @@
 import org.apache.derby.client.ClientPooledConnection40;
 import org.apache.derby.client.ClientXAConnection;
 import org.apache.derby.client.ClientXAConnection40;
+import org.apache.derby.client.am.CachingLogicalConnection40;
 import org.apache.derby.client.am.CallableStatement;
 import org.apache.derby.client.am.CallableStatement40;
 import org.apache.derby.client.am.ColumnMetaData;
@@ -36,6 +37,8 @@
 import org.apache.derby.client.am.PreparedStatement40;
 import org.apache.derby.client.am.ParameterMetaData;
 import org.apache.derby.client.am.ParameterMetaData40;
+import org.apache.derby.client.am.LogicalCallableStatement40;
+import org.apache.derby.client.am.LogicalPreparedStatement40;
 import org.apache.derby.client.am.LogWriter;
 import org.apache.derby.client.am.Agent;
 import org.apache.derby.client.am.SQLExceptionFactory40;
@@ -44,6 +47,8 @@
 import org.apache.derby.client.am.Statement40;
 import org.apache.derby.client.am.SqlException;
 import org.apache.derby.client.am.Cursor;
+import org.apache.derby.client.am.stmtcache.JDBCStatementCache;
+import org.apache.derby.client.am.stmtcache.StatementKey;
 import org.apache.derby.client.net.NetLogWriter;
 import org.apache.derby.jdbc.ClientDataSource;
 import org.apache.derby.jdbc.ClientBaseDataSource;
@@ -127,6 +132,26 @@
         return new LogicalConnection40(physicalConnection, pooledConnection);
     }
     
+   /**
+    * Returns an instance of a {@code CachingLogicalConnection}, which
+    * provides caching of prepared statements.
+    *
+    * @param physicalConnection the underlying physical connection
+    * @param pooledConnection the pooled connection
+    * @param stmtCache statement cache
+    * @return A logical connection with statement caching capabilities.
+    *
+    * @throws SqlException if creation of the logical connection fails
+    */
+    public LogicalConnection newCachingLogicalConnection(
+            org.apache.derby.client.am.Connection physicalConnection,
+            ClientPooledConnection pooledConnection,
+            JDBCStatementCache stmtCache) throws SqlException {
+        return new CachingLogicalConnection40(physicalConnection,
+                                              pooledConnection,
+                                              stmtCache);
+    }
+
     /**
      * Returns an instance of org.apache.derby.client.am.CallableStatement40
      */
@@ -180,7 +205,36 @@
                 holdability,autoGeneratedKeys,columnNames,columnIndexes, cpc);
     }
 
-    
+    /**
+     * Returns a new logcial prepared statement object.
+     *
+     * @param ps underlying physical prepared statement
+     * @param stmtKey key for the underlying physical prepared statement
+     * @param stmtCache the statement cache
+     * @return A logical prepared statement.
+     */
+    public java.sql.PreparedStatement newLogicalPreparedStatement(
+            java.sql.PreparedStatement ps,
+            StatementKey stmtKey,
+            JDBCStatementCache stmtCache) {
+        return new LogicalPreparedStatement40(ps, stmtKey, stmtCache);
+    }
+
+    /**
+     * Returns a new logical callable statement object.
+     *
+     * @param cs underlying physical callable statement
+     * @param stmtKey key for the underlying physical callable statement
+     * @param stmtCache the statement cache
+     * @return A logical callable statement.
+     */
+    public java.sql.CallableStatement newLogicalCallableStatement(
+            java.sql.CallableStatement cs,
+            StatementKey stmtKey,
+            JDBCStatementCache stmtCache) {
+        return new LogicalCallableStatement40(cs, stmtKey, stmtCache);
+    }
+
     /**
      * returns an instance of org.apache.derby.client.net.NetConnection40
      */

Added: db/derby/code/trunk/java/testing/org/apache/derby/client/am/LogicalStatementEntityTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derby/client/am/LogicalStatementEntityTest.java?rev=629734&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derby/client/am/LogicalStatementEntityTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derby/client/am/LogicalStatementEntityTest.java Thu Feb 21 02:26:31 2008
@@ -0,0 +1,298 @@
+/*
+
+   Derby - Class org.apache.derby.client.am.LogicalStatementEntityTest
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.apache.derby.client.am;
+
+import java.sql.SQLException;
+
+import junit.framework.Test;
+
+import org.apache.derby.client.am.stmtcache.JDBCStatementCache;
+import org.apache.derby.client.am.stmtcache.StatementKey;
+import org.apache.derby.client.am.stmtcache.StatementKeyFactory;
+
+import org.apache.derby.jdbc.ClientDriver;
+import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.JDBC;
+import org.apache.derbyTesting.junit.TestConfiguration;
+
+/**
+ * Tests for the handling of logical prepared statements.
+ */
+public class LogicalStatementEntityTest
+    extends BaseJDBCTestCase {
+
+    public LogicalStatementEntityTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Verifies that the logical statement representing a prepared statement
+     * behaves correctly when it has been closed.
+     *
+     * @throws SQLException if a JDBC operation fails
+     */
+    public void testCloseBehaviorExternalPs()
+            throws SQLException {
+        final String sql = "values 7";
+        final String schema = "APP";
+        java.sql.PreparedStatement ps = prepareStatement(sql);
+        StatementKey stmtKey = StatementKeyFactory.newPrepared(
+                sql, schema, getConnection().getHoldability());
+        JDBCStatementCache cache = new JDBCStatementCache(10);
+        LogicalStatementEntity logic =
+                new LogicalStatementEntityClass(ps, stmtKey, cache);
+        assertSame(ps, logic.getPhysPs());
+        assertFalse(logic.isLogicalEntityClosed());
+        logic.close();
+        assertTrue(logic.isLogicalEntityClosed());
+        logic.close();
+        logic.close();
+        assertTrue(logic.isLogicalEntityClosed());
+        try {
+            logic.getPhysPs();
+            fail("Should have thrown exception");
+        } catch (SQLException sqle) {
+            assertSQLState("XJ012", sqle);
+        }
+    }
+
+    /**
+     * 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";
+        final String schema = "APP";
+        java.sql.CallableStatement cs = prepareCall(sql);
+        StatementKey stmtKey = StatementKeyFactory.newCallable(
+                sql, schema, getConnection().getHoldability());
+        JDBCStatementCache cache = new JDBCStatementCache(10);
+        LogicalStatementEntity logic =
+                new LogicalStatementEntityClass(cs, stmtKey, 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";
+        final String schema = "APP";
+        java.sql.PreparedStatement ps = prepareStatement(sql);
+        StatementKey stmtKey = StatementKeyFactory.newPrepared(
+                sql, schema, getConnection().getHoldability());
+        JDBCStatementCache cache = new JDBCStatementCache(10);
+        LogicalStatementEntity logic =
+                new LogicalStatementEntityClass(ps, stmtKey, 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);
+        LogicalStatementEntity logicDupe =
+                new LogicalStatementEntityClass(psDupe, stmtKey, cache);
+        // 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 pre-JDBC 4, try do do something to
+        // provoke 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");
+    }
+
+    /**
+     * 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";
+        final String schema = "APP";
+        java.sql.PreparedStatement ps = prepareStatement(sql);
+        StatementKey stmtKey = StatementKeyFactory.newPrepared(
+                sql, schema, getConnection().getHoldability());
+        JDBCStatementCache cache = new JDBCStatementCache(10);
+        LogicalStatementEntity logic =
+                new LogicalStatementEntityClass(ps, stmtKey, 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";
+        final String schema = "APP";
+        java.sql.PreparedStatement ps = prepareStatement(sql);
+        StatementKey stmtKey = StatementKeyFactory.newPrepared(
+                sql, schema, getConnection().getHoldability());
+        JDBCStatementCache cache = new JDBCStatementCache(10);
+        LogicalStatementEntity logic =
+                new LogicalStatementEntityClass(ps, stmtKey, cache);
+        assertSame(ps, logic.getPhysPs());
+        assertFalse(logic.isLogicalEntityClosed());
+        java.sql.PreparedStatement logicalPs = ClientDriver.getFactory().
+                newLogicalPreparedStatement(ps, stmtKey, cache);
+        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 schema = "APP";
+        java.sql.PreparedStatement ps1 = prepareStatement("values 1");
+        java.sql.PreparedStatement ps2 = prepareStatement("values 2");
+        java.sql.PreparedStatement ps3 = prepareStatement("values 3");
+        StatementKey stmtKey1 = StatementKeyFactory.newPrepared(
+                "values 1", schema, getConnection().getHoldability());
+        StatementKey stmtKey2 = StatementKeyFactory.newPrepared(
+                "values 2", schema, getConnection().getHoldability());
+        StatementKey stmtKey3 = StatementKeyFactory.newPrepared(
+                "values 3", schema, getConnection().getHoldability());
+        LogicalStatementEntity logic1 =
+                new LogicalStatementEntityClass(ps1, stmtKey1, cache);
+        LogicalStatementEntity logic2 =
+                new LogicalStatementEntityClass(ps2, stmtKey2, cache);
+        LogicalStatementEntity logic3 =
+                new LogicalStatementEntityClass(ps3, stmtKey3, cache);
+
+        // Close the two first logical statements, putting them 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));
+    }
+
+    /**
+     * Returns a suite of tests running in a client-server environment.
+     *
+     * @return A test suite.
+     */
+    public static Test suite() {
+        return TestConfiguration.clientServerSuite(
+                LogicalStatementEntityTest.class);
+    }
+
+    /**
+     * Class used to represent a logical statement.
+     */
+    private static class LogicalStatementEntityClass
+            extends LogicalStatementEntity {
+
+        /**
+         * Constructor creating an object handling closing of a logical
+         * prepared / callable statement.
+         *
+         * @param ps underlying physical prepared / callable statement
+         */
+        public LogicalStatementEntityClass(java.sql.PreparedStatement ps,
+                                           StatementKey key,
+                                           JDBCStatementCache cache) {
+            super(ps, key, cache);
+        }
+    }
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derby/client/am/LogicalStatementEntityTest.java
------------------------------------------------------------------------------
    svn:eol-style = native