Repository: commons-dbcp
Updated Branches:
  refs/heads/master 8a1c11185 -> e6543480a


Fix DBCP-462

Refactoring to prepare for a future patch to enable pooling of all
prepared and callable statements in PoolingConnection.

Project: http://git-wip-us.apache.org/repos/asf/commons-dbcp/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-dbcp/commit/e6543480
Tree: http://git-wip-us.apache.org/repos/asf/commons-dbcp/tree/e6543480
Diff: http://git-wip-us.apache.org/repos/asf/commons-dbcp/diff/e6543480

Branch: refs/heads/master
Commit: e6543480ad73e45c7f02710b0ee15352664e118a
Parents: 8a1c111
Author: Mark Thomas <[email protected]>
Authored: Thu Nov 3 08:53:42 2016 +0000
Committer: Mark Thomas <[email protected]>
Committed: Thu Nov 3 08:53:42 2016 +0000

----------------------------------------------------------------------
 src/changes/changes.xml                         |   4 +
 .../java/org/apache/commons/dbcp2/PStmtKey.java | 108 ++++++++++++++++++-
 .../apache/commons/dbcp2/PoolingConnection.java |  32 ++----
 .../commons/dbcp2/TestPoolingConnection.java    | 106 ++++++++++++++++++
 .../apache/commons/dbcp2/TesterConnection.java  |   7 +-
 .../commons/dbcp2/TesterPreparedStatement.java  |  20 ++++
 6 files changed, 247 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/e6543480/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index a3e5daa..da71653 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -109,6 +109,10 @@ The <action> type attribute can be add,update,fix,remove.
         remains but is deprecated so not to break clients currently using the
         incorrect name.
       </action>
+     <action dev="markt" type="add" issue="DBCP-462" due-to=" Keiichi Fujino">
+       Refactoring to prepare for a future patch to enable pooling of all
+       prepared and callable statements in PoolingConnection.
+     </action>
     </release>
     <release version="2.1.1" date="6 Aug 2015" description=
 "This is a patch release, including bug fixes only.">

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/e6543480/src/main/java/org/apache/commons/dbcp2/PStmtKey.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/PStmtKey.java 
b/src/main/java/org/apache/commons/dbcp2/PStmtKey.java
index 95a1d89..4d5dc90 100644
--- a/src/main/java/org/apache/commons/dbcp2/PStmtKey.java
+++ b/src/main/java/org/apache/commons/dbcp2/PStmtKey.java
@@ -16,6 +16,11 @@
  */
 package org.apache.commons.dbcp2;
 
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
+
 import org.apache.commons.dbcp2.PoolingConnection.StatementType;
 
 /**
@@ -43,13 +48,30 @@ public class PStmtKey {
     /** Statement type */
     private final StatementType _stmtType;
 
+    /** Statement builder */
+    private StatementeBuilder builder;
 
     public PStmtKey(final String sql) {
-        this(sql, null, StatementType.PREPARED_STATEMENT, null);
+        this(sql, null, StatementType.PREPARED_STATEMENT);
     }
 
     public PStmtKey(final String sql, final String catalog) {
-        this(sql, catalog, StatementType.PREPARED_STATEMENT, null);
+        this(sql, catalog, StatementType.PREPARED_STATEMENT);
+    }
+
+    public PStmtKey(final String sql, final String catalog, final 
StatementType stmtType) {
+        _sql = sql;
+        _catalog = catalog;
+        _stmtType = stmtType;
+        _autoGeneratedKeys = null;
+        _resultSetType = null;
+        _resultSetConcurrency = null;
+        // create builder
+        if (stmtType == StatementType.PREPARED_STATEMENT) {
+            builder = new PreparedStatementSQL();
+        } else if (stmtType == StatementType.CALLABLE_STATEMENT) {
+            builder = new PreparedCallSQL();
+        }
     }
 
     public PStmtKey(final String sql, final String catalog, final int 
autoGeneratedKeys) {
@@ -63,6 +85,12 @@ public class PStmtKey {
         _autoGeneratedKeys = autoGeneratedKeys;
         _resultSetType = null;
         _resultSetConcurrency = null;
+        // create builder
+        if (stmtType == StatementType.PREPARED_STATEMENT) {
+            builder = new PreparedStatementWithAutoGeneratedKeys();
+        } else if (stmtType == StatementType.CALLABLE_STATEMENT) {
+            builder = new PreparedCallSQL();
+        }
     }
 
     public  PStmtKey(final String sql, final int resultSetType, final int 
resultSetConcurrency) {
@@ -80,6 +108,12 @@ public class PStmtKey {
         _resultSetConcurrency = Integer.valueOf(resultSetConcurrency);
         _stmtType = stmtType;
         _autoGeneratedKeys = null;
+        // create builder
+        if (stmtType == StatementType.PREPARED_STATEMENT) {
+            builder = new PreparedStatementWithResultSetConcurrency();
+        } else if (stmtType == StatementType.CALLABLE_STATEMENT) {
+            builder = new PreparedCallWithResultSetConcurrency();
+        }
     }
 
 
@@ -190,4 +224,74 @@ public class PStmtKey {
         buf.append(_stmtType);
         return buf.toString();
     }
+
+    public Statement createStatement(Connection connection) throws 
SQLException {
+        if (builder == null) throw new IllegalStateException("Prepared 
statement key is invalid.");
+        return builder.createStatement(connection);
+    }
+
+    /**
+     * Interface for Prepared or Callable Statement
+     */
+    private interface StatementeBuilder {
+        public Statement createStatement(Connection connection) throws 
SQLException;
+    }
+
+    /**
+     * Builder for prepareStatement(String sql)
+     */
+    private class PreparedStatementSQL implements StatementeBuilder {
+        @Override
+        public Statement createStatement(Connection connection) throws 
SQLException {
+            PreparedStatement statement = connection.prepareStatement(_sql);
+            return statement;
+        }
+    }
+
+    /**
+     * Builder for prepareStatement(String sql, int autoGeneratedKeys)
+     */
+    private class PreparedStatementWithAutoGeneratedKeys implements 
StatementeBuilder {
+        @Override
+        public Statement createStatement(Connection connection) throws 
SQLException {
+            PreparedStatement statement = connection.prepareStatement(
+                    _sql, _autoGeneratedKeys.intValue());
+            return statement;
+        }
+    }
+
+    /**
+     * Builder for prepareStatement(String sql, int resultSetType, int 
resultSetConcurrency)
+     */
+    private class PreparedStatementWithResultSetConcurrency implements 
StatementeBuilder {
+        @Override
+        public Statement createStatement(Connection connection) throws 
SQLException {
+            PreparedStatement statement = connection.prepareStatement(
+                    _sql, _resultSetType.intValue(), 
_resultSetConcurrency.intValue());
+            return statement;
+        }
+    }
+
+    /**
+     * Builder for prepareCall(String sql)
+     */
+    private class PreparedCallSQL implements StatementeBuilder {
+        @Override
+        public Statement createStatement(Connection connection) throws 
SQLException {
+            PreparedStatement statement = connection.prepareCall(_sql);
+            return statement;
+        }
+    }
+
+    /**
+     * Builder for prepareCall(String sql, int resultSetType, int 
resultSetConcurrency)
+     */
+    private class PreparedCallWithResultSetConcurrency implements 
StatementeBuilder {
+        @Override
+        public Statement createStatement(Connection connection) throws 
SQLException {
+            PreparedStatement statement = connection.prepareCall(
+                    _sql, _resultSetType.intValue(), 
_resultSetConcurrency.intValue());
+            return statement;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/e6543480/src/main/java/org/apache/commons/dbcp2/PoolingConnection.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/PoolingConnection.java 
b/src/main/java/org/apache/commons/dbcp2/PoolingConnection.java
index 2f1eab4..1fd9bbe 100644
--- a/src/main/java/org/apache/commons/dbcp2/PoolingConnection.java
+++ b/src/main/java/org/apache/commons/dbcp2/PoolingConnection.java
@@ -317,33 +317,15 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
         if(null == key) {
             throw new IllegalArgumentException("Prepared statement key is null 
or invalid.");
         }
-        if (null == key.getResultSetType() && null == 
key.getResultSetConcurrency() && null == key.getAutoGeneratedKeys()) {
-            if (key.getStmtType() == StatementType.PREPARED_STATEMENT ) {
-                @SuppressWarnings({"rawtypes", "unchecked"}) // Unable to find 
way to avoid this
-                final
-                PoolablePreparedStatement pps = new PoolablePreparedStatement(
-                        getDelegate().prepareStatement(key.getSql()), key, 
_pstmtPool, this);
-                return new 
DefaultPooledObject<DelegatingPreparedStatement>(pps);
-            }
-            return new DefaultPooledObject<DelegatingPreparedStatement>(
-                    new PoolableCallableStatement(getDelegate().prepareCall( 
key.getSql()), key, _pstmtPool, this));
-        } else if (null == key.getResultSetType() && null == 
key.getResultSetConcurrency()){
+        if (key.getStmtType() == StatementType.PREPARED_STATEMENT ) {
+            PreparedStatement statement = (PreparedStatement) 
key.createStatement(getDelegate());
             @SuppressWarnings({"rawtypes", "unchecked"}) // Unable to find way 
to avoid this
-            final
-            PoolablePreparedStatement pps = new PoolablePreparedStatement(
-                    getDelegate().prepareStatement(key.getSql(), 
key.getAutoGeneratedKeys().intValue()), key, _pstmtPool, this);
+            PoolablePreparedStatement pps = new 
PoolablePreparedStatement(statement, key, _pstmtPool, this);
             return new DefaultPooledObject<DelegatingPreparedStatement>(pps);
-        } else { // Both _resultSetType and _resultSetConcurrency are non-null 
here (both or neither are set by constructors)
-            if(key.getStmtType() == StatementType.PREPARED_STATEMENT) {
-                @SuppressWarnings({"rawtypes", "unchecked"}) // Unable to find 
way to avoid this
-                final
-                PoolablePreparedStatement pps = new 
PoolablePreparedStatement(getDelegate().prepareStatement(
-                        key.getSql(), 
key.getResultSetType().intValue(),key.getResultSetConcurrency().intValue()), 
key, _pstmtPool, this);
-                return new 
DefaultPooledObject<DelegatingPreparedStatement>(pps);
-            }
-            return new DefaultPooledObject<DelegatingPreparedStatement>(
-                    new PoolableCallableStatement( getDelegate().prepareCall(
-                            key.getSql(),key.getResultSetType().intValue(), 
key.getResultSetConcurrency().intValue()), key, _pstmtPool, this));
+        } else {
+            CallableStatement statement = (CallableStatement) 
key.createStatement(getDelegate());
+            PoolableCallableStatement pcs = new 
PoolableCallableStatement(statement, key, _pstmtPool, this);
+            return new DefaultPooledObject<DelegatingPreparedStatement>(pcs);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/e6543480/src/test/java/org/apache/commons/dbcp2/TestPoolingConnection.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/dbcp2/TestPoolingConnection.java 
b/src/test/java/org/apache/commons/dbcp2/TestPoolingConnection.java
new file mode 100644
index 0000000..101fa6f
--- /dev/null
+++ b/src/test/java/org/apache/commons/dbcp2/TestPoolingConnection.java
@@ -0,0 +1,106 @@
+/*
+ * 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.commons.dbcp2;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.commons.pool2.KeyedObjectPool;
+import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
+import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestPoolingConnection {
+
+    private PoolingConnection con = null;
+
+    @Before
+    public void setUp() throws Exception {
+        con = new PoolingConnection(new TesterConnection("test", "test"));
+        final GenericKeyedObjectPoolConfig config = new 
GenericKeyedObjectPoolConfig();
+        config.setMaxTotalPerKey(-1);
+        config.setBlockWhenExhausted(false);
+        config.setMaxWaitMillis(0);
+        config.setMaxIdlePerKey(1);
+        config.setMaxTotal(1);
+        final KeyedObjectPool<PStmtKey,DelegatingPreparedStatement> stmtPool =
+                new GenericKeyedObjectPool<>(con, config);
+        con.setStatementPool(stmtPool);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        con.close();
+        con = null;
+    }
+
+    @Test
+    public void testPrepareStatement() throws Exception {
+        String sql = "select 'a' from dual";
+        DelegatingPreparedStatement statement = 
(DelegatingPreparedStatement)con.prepareStatement(sql);
+        TesterPreparedStatement testStatement = (TesterPreparedStatement) 
statement.getInnermostDelegate();
+        // assert
+        assertEquals(sql, testStatement.getSql());
+    }
+
+    @Test
+    public void testPrepareStatementWithAutoGeneratedKeys() throws Exception {
+        String sql = "select 'a' from dual";
+        int autoGeneratedKeys = 0;
+        DelegatingPreparedStatement statement = 
(DelegatingPreparedStatement)con.prepareStatement(sql, autoGeneratedKeys);
+        TesterPreparedStatement testStatement = (TesterPreparedStatement) 
statement.getInnermostDelegate();
+        // assert
+        assertEquals(sql, testStatement.getSql());
+        assertEquals(autoGeneratedKeys, testStatement.getAutoGeneratedKeys());
+    }
+
+    @Test
+    public void testPrepareStatementWithResultSetConcurrency() throws 
Exception {
+        String sql = "select 'a' from dual";
+        int resultSetType = 0;
+        int resultSetConcurrency = 0;
+        DelegatingPreparedStatement statement = 
(DelegatingPreparedStatement)con.prepareStatement(sql, resultSetType, 
resultSetConcurrency);
+        TesterPreparedStatement testStatement = (TesterPreparedStatement) 
statement.getInnermostDelegate();
+        // assert
+        assertEquals(sql, testStatement.getSql());
+        assertEquals(resultSetType, testStatement.getResultSetType());
+        assertEquals(resultSetConcurrency, 
testStatement.getResultSetConcurrency());
+    }
+
+    @Test
+    public void testPrepareCall() throws Exception {
+        String sql = "select 'a' from dual";
+        DelegatingCallableStatement statement = 
(DelegatingCallableStatement)con.prepareCall(sql);
+        TesterCallableStatement testStatement = (TesterCallableStatement) 
statement.getInnermostDelegate();
+        // assert
+        assertEquals(sql, testStatement.getSql());
+    }
+
+    @Test
+    public void testPrepareCallWithResultSetConcurrency() throws Exception {
+        String sql = "select 'a' from dual";
+        int resultSetType = 0;
+        int resultSetConcurrency = 0;
+        DelegatingCallableStatement statement = 
(DelegatingCallableStatement)con.prepareCall(sql, resultSetType, 
resultSetConcurrency);
+        TesterCallableStatement testStatement = (TesterCallableStatement) 
statement.getInnermostDelegate();
+        // assert
+        assertEquals(sql, testStatement.getSql());
+        assertEquals(resultSetType, testStatement.getResultSetType());
+        assertEquals(resultSetConcurrency, 
testStatement.getResultSetConcurrency());
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/e6543480/src/test/java/org/apache/commons/dbcp2/TesterConnection.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/dbcp2/TesterConnection.java 
b/src/test/java/org/apache/commons/dbcp2/TesterConnection.java
index ab0f665..3be2a45 100644
--- a/src/test/java/org/apache/commons/dbcp2/TesterConnection.java
+++ b/src/test/java/org/apache/commons/dbcp2/TesterConnection.java
@@ -159,13 +159,13 @@ public class TesterConnection implements Connection {
         if ("warning".equals(sql)) {
             setWarnings(new SQLWarning("warning in prepareCall"));
         }
-        return new TesterCallableStatement(this);
+        return new TesterCallableStatement(this, sql);
     }
 
     @Override
     public CallableStatement prepareCall(final String sql, final int 
resultSetType, final int resultSetConcurrency) throws SQLException {
         checkOpen();
-        return new TesterCallableStatement(this);
+        return new TesterCallableStatement(this, sql, resultSetType, 
resultSetConcurrency);
     }
 
     @Override
@@ -302,7 +302,8 @@ public class TesterConnection implements Connection {
     @Override
     public PreparedStatement prepareStatement(final String sql, final int 
autoGeneratedKeys)
         throws SQLException {
-        return prepareStatement(sql);
+        checkOpen();
+        return new TesterPreparedStatement(this, sql, autoGeneratedKeys);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/e6543480/src/test/java/org/apache/commons/dbcp2/TesterPreparedStatement.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/commons/dbcp2/TesterPreparedStatement.java 
b/src/test/java/org/apache/commons/dbcp2/TesterPreparedStatement.java
index 292f9c1..147a9dc 100644
--- a/src/test/java/org/apache/commons/dbcp2/TesterPreparedStatement.java
+++ b/src/test/java/org/apache/commons/dbcp2/TesterPreparedStatement.java
@@ -45,6 +45,7 @@ public class TesterPreparedStatement extends TesterStatement 
implements Prepared
     private final ResultSetMetaData _resultSetMetaData = null;
     private String _sql = null;
     private String _catalog = null;
+    private int _autoGeneratedKeys = 1;
 
     public TesterPreparedStatement(final Connection conn) {
         super(conn);
@@ -65,6 +66,17 @@ public class TesterPreparedStatement extends TesterStatement 
implements Prepared
         }
     }
 
+    public TesterPreparedStatement(final Connection conn, final String sql, 
final int autoGeneratedKeys) {
+        super(conn);
+        _sql = sql;
+        _autoGeneratedKeys = autoGeneratedKeys;
+        try {
+            _catalog = conn.getCatalog();
+        } catch (final SQLException e) {
+            // Ignored
+        }
+    }
+
     public TesterPreparedStatement(final Connection conn, final String sql, 
final int resultSetType, final int resultSetConcurrency) {
         super(conn, resultSetType, resultSetConcurrency);
         _sql = sql;
@@ -76,10 +88,18 @@ public class TesterPreparedStatement extends 
TesterStatement implements Prepared
     }
 
     /** for junit test only */
+    public String getSql() {
+        return _sql;
+    }
+
     public String getCatalog() {
         return _catalog;
     }
 
+    public int getAutoGeneratedKeys() {
+        return _autoGeneratedKeys;
+    }
+
     @Override
     public ResultSet executeQuery(final String sql) throws SQLException {
         checkOpen();

Reply via email to