This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 27f81e4fe98725c85a9d0b8411a056b95dca9cd9
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Aug 26 16:15:50 2020 +0100

    Update Commons DBCP to latest
---
 MERGE.txt                                          |   2 +-
 .../apache/tomcat/dbcp/dbcp2/BasicDataSource.java  | 166 +++++++++-------
 .../tomcat/dbcp/dbcp2/BasicDataSourceFactory.java  |  11 +-
 .../tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java   |  27 +++
 .../tomcat/dbcp/dbcp2/DelegatingConnection.java    |   4 +-
 .../tomcat/dbcp/dbcp2/PoolableConnection.java      |   3 +
 .../dbcp/dbcp2/PoolableConnectionFactory.java      |  14 ++
 .../tomcat/dbcp/dbcp2/PoolingConnection.java       | 220 +++++++++++----------
 .../dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java  |  28 +--
 .../dbcp2/datasources/CPDSConnectionFactory.java   |   3 +-
 .../dbcp2/datasources/InstanceKeyDataSource.java   |   8 +-
 .../dbcp/dbcp2/datasources/package-info.java       |   2 +-
 webapps/docs/changelog.xml                         |   4 +
 13 files changed, 297 insertions(+), 195 deletions(-)

diff --git a/MERGE.txt b/MERGE.txt
index 79fc82e..b8c152d 100644
--- a/MERGE.txt
+++ b/MERGE.txt
@@ -69,4 +69,4 @@ Sub-tree
 src/main/java/org/apache/commons/dbcp2
 src/main/resources/org/apache/commons/dbcp2
 The SHA1 ID / tag for the most recent commit to be merged to Tomcat is:
-a363906bf7a039f79c07fa3c68b082a69ae035d7 (2019-12-06)
+6d232e547d5725e419832fc514fc0348aa897e7c (2020-08-11)
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java 
b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
index 0293e9a..70a052a 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
@@ -220,6 +220,8 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      */
     private boolean poolPreparedStatements = false;
 
+    private boolean clearStatementPoolOnReturn = false;
+
     /**
      * <p>
      * The maximum number of open statements that can be allocated from the 
statement pool at the same time, or negative
@@ -402,7 +404,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * </p>
      * <p>
      * Attempts to acquire connections using {@link #getConnection()} after 
this method has been invoked result in
-     * SQLExceptions.
+     * SQLExceptions.  To reopen a datasource that has been closed using this 
method, use {@link #start()}.
      * </p>
      * <p>
      * This method is idempotent - i.e., closing an already closed 
BasicDataSource has no effect and does not generate
@@ -448,7 +450,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     }
 
     /**
-     * Creates a JDBC connection factory for this datasource. The JDBC driver 
is loaded using the following algorithm:
+     * Creates a JDBC connection factory for this data source. The JDBC driver 
is loaded using the following algorithm:
      * <ol>
      * <li>If a Driver instance has been specified via {@link 
#setDriver(Driver)} use it</li>
      * <li>If no Driver instance was specified and {@link #driverClassName} is 
specified that class is loaded using the
@@ -471,6 +473,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         return ConnectionFactoryFactory.createConnectionFactory(this, 
DriverFactory.createDriver(this));
     }
 
+
     /**
      * Creates a connection pool for this datasource. This method only exists 
so subclasses can replace the
      * implementation class.
@@ -530,7 +533,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
             if (dataSource != null) {
                 return dataSource;
             }
-
             jmxRegister();
 
             // create factory which returns raw physical connections
@@ -544,10 +546,8 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
                 
poolableConnectionFactory.setPoolStatements(poolPreparedStatements);
                 
poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
                 success = true;
-            } catch (final SQLException se) {
+            } catch (final SQLException | RuntimeException se) {
                 throw se;
-            } catch (final RuntimeException rte) {
-                throw rte;
             } catch (final Exception ex) {
                 throw new SQLException("Error creating connection factory", 
ex);
             }
@@ -564,10 +564,8 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
                 newDataSource = createDataSourceInstance();
                 newDataSource.setLogWriter(logWriter);
                 success = true;
-            } catch (final SQLException se) {
+            } catch (final SQLException | RuntimeException se) {
                 throw se;
-            } catch (final RuntimeException rte) {
-                throw rte;
             } catch (final Exception ex) {
                 throw new SQLException("Error creating datasource", ex);
             } finally {
@@ -654,6 +652,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
             connectionFactory.setDefaultSchema(defaultSchema);
             connectionFactory.setCacheState(cacheState);
             connectionFactory.setPoolStatements(poolPreparedStatements);
+            
connectionFactory.setClearStatementPoolOnReturn(clearStatementPoolOnReturn);
             
connectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
             connectionFactory.setMaxConnLifetimeMillis(maxConnLifetimeMillis);
             connectionFactory.setRollbackOnReturn(getRollbackOnReturn());
@@ -687,10 +686,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * @return The print writer used by this configuration to log information 
on abandoned objects.
      */
     public PrintWriter getAbandonedLogWriter() {
-        if (abandonedConfig != null) {
-            return abandonedConfig.getLogWriter();
-        }
-        return null;
+        return abandonedConfig == null ? null : abandonedConfig.getLogWriter();
     }
 
     /**
@@ -702,10 +698,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      */
     @Override
     public boolean getAbandonedUsageTracking() {
-        if (abandonedConfig != null) {
-            return abandonedConfig.getUseUsageTracking();
-        }
-        return false;
+        return abandonedConfig == null ? false : 
abandonedConfig.getUseUsageTracking();
     }
 
     /**
@@ -738,7 +731,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     @Override
     public Connection getConnection() throws SQLException {
         if (Utils.IS_SECURITY_ENABLED) {
-            final PrivilegedExceptionAction<Connection> action = new 
PaGetConnection();
+            final PrivilegedExceptionAction<Connection> action =  new 
PaGetConnection();
             try {
                 return AccessController.doPrivileged(action);
             } catch (final PrivilegedActionException e) {
@@ -1021,10 +1014,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      */
     @Override
     public boolean getLogAbandoned() {
-        if (abandonedConfig != null) {
-            return abandonedConfig.getLogAbandoned();
-        }
-        return false;
+        return abandonedConfig == null ? false : 
abandonedConfig.getLogAbandoned();
     }
 
     /**
@@ -1055,8 +1045,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      */
     @Override
     public int getLoginTimeout() throws SQLException {
-        // This method isn't supported by the PoolingDataSource returned by the
-        // createDataSource
+        // This method isn't supported by the PoolingDataSource returned by 
the createDataSource
         throw new UnsupportedOperationException("Not supported by 
BasicDataSource");
     }
 
@@ -1170,10 +1159,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     public int getNumActive() {
         // Copy reference to avoid NPE if close happens after null check
         final GenericObjectPool<PoolableConnection> pool = connectionPool;
-        if (pool != null) {
-            return pool.getNumActive();
-        }
-        return 0;
+        return pool == null ? 0 : pool.getNumActive();
     }
 
     /**
@@ -1185,10 +1171,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     public int getNumIdle() {
         // Copy reference to avoid NPE if close happens after null check
         final GenericObjectPool<PoolableConnection> pool = connectionPool;
-        if (pool != null) {
-            return pool.getNumIdle();
-        }
-        return 0;
+        return pool == null ? 0 : pool.getNumIdle();
     }
 
     /**
@@ -1246,10 +1229,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      */
     @Override
     public boolean getRemoveAbandonedOnBorrow() {
-        if (abandonedConfig != null) {
-            return abandonedConfig.getRemoveAbandonedOnBorrow();
-        }
-        return false;
+        return abandonedConfig == null ? false : 
abandonedConfig.getRemoveAbandonedOnBorrow();
     }
 
     /**
@@ -1270,10 +1250,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      */
     @Override
     public boolean getRemoveAbandonedOnMaintenance() {
-        if (abandonedConfig != null) {
-            return abandonedConfig.getRemoveAbandonedOnMaintenance();
-        }
-        return false;
+        return abandonedConfig == null ? false : 
abandonedConfig.getRemoveAbandonedOnMaintenance();
     }
 
     /**
@@ -1298,10 +1275,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      */
     @Override
     public int getRemoveAbandonedTimeout() {
-        if (abandonedConfig != null) {
-            return abandonedConfig.getRemoveAbandonedTimeout();
-        }
-        return 300;
+        return abandonedConfig == null ? 300 : 
abandonedConfig.getRemoveAbandonedTimeout();
     }
 
     /**
@@ -1478,7 +1452,18 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     }
 
     /**
-     * If true, this data source is closed and no more connections can be 
retrieved from this datasource.
+     * Returns true if the statement pool is cleared when the connection is 
returned to its pool.
+     *
+     * @return true if the statement pool is cleared at connection return
+     * @since 2.8.0
+     */
+    @Override
+    public boolean isClearStatementPoolOnReturn() {
+        return clearStatementPoolOnReturn;
+    }
+
+    /**
+     * If true, this data source is closed and no more connections can be 
retrieved from this data source.
      *
      * @return true, if the data source is closed; false otherwise
      */
@@ -1591,6 +1576,31 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     }
 
     /**
+     * Restarts the datasource.
+     * <p>
+     * This method calls {@link #close()} and {@link #start()} in sequence 
within synchronized scope so any
+     * connection requests that come in while the datsource is shutting down 
will be served by the new pool.
+     * <p>
+     * Idle connections that are stored in the connection pool when this 
method is invoked are closed, but
+     * connections that are checked out to clients when this method is invoked 
are not affected. When client
+     * applications subsequently invoke {@link Connection#close()} to return 
these connections to the pool, the
+     * underlying JDBC connections are closed. These connections do not count 
in {@link #getMaxTotal()} or
+     * {@link #getNumActive()} after invoking this method. For example, if 
there are 3 connections checked out by
+     * clients when {@link #restart()} is invoked, after this method is 
called, {@link #getNumActive()} will
+     * return 0 and up to {@link #getMaxTotal()} + 3 connections may be open 
until the connections sourced from
+     * the original pool are returned.
+     * <p>
+     * The new connection pool created by this method is initialized with 
currently set configuration properties.
+     *
+     * @throws SQLException if an error occurs initializing the datasource
+     */
+    @Override
+    public synchronized void restart() throws SQLException {
+        close();
+        start();
+    }
+
+    /**
      * Sets the print writer to be used by this configuration to log 
information on abandoned objects.
      *
      * @param logWriter The new log writer
@@ -1655,8 +1665,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         this.autoCommitOnReturn = autoCommitOnReturn;
     }
 
-    // ----------------------------------------------------- DataSource Methods
-
     /**
      * Sets the state caching flag.
      *
@@ -1667,17 +1675,24 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     }
 
     /**
+     * Sets whether the pool of statements (which was enabled with {@link 
#setPoolPreparedStatements(boolean)}) should
+     * be cleared when the connection is returned to its pool. Default is 
false.
+     *
+     * @param clearStatementPoolOnReturn clear or not
+     * @since 2.8.0
+     */
+    public void setClearStatementPoolOnReturn(final boolean 
clearStatementPoolOnReturn) {
+        this.clearStatementPoolOnReturn = clearStatementPoolOnReturn;
+    }
+
+    /**
      * Sets the ConnectionFactory class name.
      *
      * @param connectionFactoryClassName A class name.
      * @since 2.7.0
      */
     public void setConnectionFactoryClassName(final String 
connectionFactoryClassName) {
-        if (isEmpty(connectionFactoryClassName)) {
-            this.connectionFactoryClassName = null;
-        } else {
-            this.connectionFactoryClassName = connectionFactoryClassName;
-        }
+        this.connectionFactoryClassName = isEmpty(connectionFactoryClassName) 
? null : connectionFactoryClassName;
     }
 
     /**
@@ -1768,11 +1783,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * @param defaultCatalog the default catalog
      */
     public void setDefaultCatalog(final String defaultCatalog) {
-        if (isEmpty(defaultCatalog)) {
-            this.defaultCatalog = null;
-        } else {
-            this.defaultCatalog = defaultCatalog;
-        }
+        this.defaultCatalog = isEmpty(defaultCatalog) ? null : defaultCatalog;
     }
 
     /**
@@ -1815,11 +1826,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * @since 2.5.0
      */
     public void setDefaultSchema(final String defaultSchema) {
-        if (isEmpty(defaultSchema)) {
-            this.defaultSchema = null;
-        } else {
-            this.defaultSchema = defaultSchema;
-        }
+        this.defaultSchema = isEmpty(defaultSchema) ? null : defaultSchema;
     }
 
     /**
@@ -1920,11 +1927,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * @param driverClassName the class name of the JDBC driver
      */
     public synchronized void setDriverClassName(final String driverClassName) {
-        if (isEmpty(driverClassName)) {
-            this.driverClassName = null;
-        } else {
-            this.driverClassName = driverClassName;
-        }
+        this.driverClassName = isEmpty(driverClassName) ? null : 
driverClassName;
     }
 
     /**
@@ -2409,11 +2412,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * @param validationQuery the new value for the validation query
      */
     public void setValidationQuery(final String validationQuery) {
-        if (isEmpty(validationQuery)) {
-            this.validationQuery = null;
-        } else {
-            this.validationQuery = validationQuery;
-        }
+        this.validationQuery = isEmpty(validationQuery) ? null : 
validationQuery;
     }
 
     /**
@@ -2432,6 +2431,29 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     }
 
     /**
+     * Starts the datasource.
+     * <p>
+     * It is not necessary to call this method before using a newly created 
BasicDataSource instance, but
+     * calling it in that context causes the datasource to be immediately 
initialized (instead of waiting for
+     * the first {@link #getConnection()} request). Its primary use is to 
restart and reinitialize a
+     * datasource that has been closed.
+     * <p>
+     * When this method is called after {@link #close()}, connections checked 
out by clients
+     * before the datasource was stopped do not count in {@link 
#getMaxTotal()} or {@link #getNumActive()}.
+     * For example, if there are 3 connections checked out by clients when 
{@link #close()} is invoked and they are
+     * not returned before {@link #start()} is invoked, after this method is 
called, {@link #getNumActive()} will
+     * return 0.  These connections will be physically closed when they are 
returned, but they will not count against
+     * the maximum allowed in the newly started datasource.
+     *
+     * @throws SQLException if an error occurs initializing the datasource
+     */
+    @Override
+    public synchronized void start() throws SQLException {
+        closed = false;
+        createDataSource();
+    }
+
+    /**
      * Starts the connection pool maintenance task, if configured.
      */
     protected void startPoolMaintenance() {
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
index 158b944..b8ae8f2 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
@@ -100,6 +100,7 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
     private static final String PROP_LOG_ABANDONED = "logAbandoned";
     private static final String PROP_ABANDONED_USAGE_TRACKING = 
"abandonedUsageTracking";
     private static final String PROP_POOL_PREPARED_STATEMENTS = 
"poolPreparedStatements";
+    private static final String PROP_CLEAR_STATEMENT_POOL_ON_RETURN = 
"clearStatementPoolOnReturn";
     private static final String PROP_MAX_OPEN_PREPARED_STATEMENTS = 
"maxOpenPreparedStatements";
     private static final String PROP_CONNECTION_PROPERTIES = 
"connectionProperties";
     private static final String PROP_MAX_CONN_LIFETIME_MILLIS = 
"maxConnLifetimeMillis";
@@ -140,6 +141,7 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
             PROP_URL, PROP_USER_NAME, PROP_VALIDATION_QUERY, 
PROP_VALIDATION_QUERY_TIMEOUT, PROP_CONNECTION_INIT_SQLS,
             PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED, 
PROP_REMOVE_ABANDONED_ON_BORROW, PROP_REMOVE_ABANDONED_ON_MAINTENANCE,
             PROP_REMOVE_ABANDONED_TIMEOUT, PROP_LOG_ABANDONED, 
PROP_ABANDONED_USAGE_TRACKING, PROP_POOL_PREPARED_STATEMENTS,
+            PROP_CLEAR_STATEMENT_POOL_ON_RETURN,
             PROP_MAX_OPEN_PREPARED_STATEMENTS, PROP_CONNECTION_PROPERTIES, 
PROP_MAX_CONN_LIFETIME_MILLIS,
             PROP_LOG_EXPIRED_CONNECTIONS, PROP_ROLLBACK_ON_RETURN, 
PROP_ENABLE_AUTO_COMMIT_ON_RETURN,
             PROP_DEFAULT_QUERY_TIMEOUT, PROP_FAST_FAIL_VALIDATION, 
PROP_DISCONNECTION_SQL_CODES, PROP_JMX_NAME,
@@ -255,7 +257,7 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
             final List<String> infoMessages) {
         final List<String> allPropsAsList = Arrays.asList(ALL_PROPERTIES);
         final String nameString = name != null ? "Name = " + name.toString() + 
" " : "";
-        if (NUPROP_WARNTEXT != null && !NUPROP_WARNTEXT.keySet().isEmpty()) {
+        if (NUPROP_WARNTEXT != null && !NUPROP_WARNTEXT.isEmpty()) {
             for (final String propertyName : NUPROP_WARNTEXT.keySet()) {
                 final RefAddr ra = ref.get(propertyName);
                 if (ra != null && !allPropsAsList.contains(ra.getType())) {
@@ -275,7 +277,7 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
             final String propertyName = ra.getType();
             // If property name is not in the properties list, we haven't 
warned on it
             // and it is not in the "silent" list, tell user we are ignoring 
it.
-            if (!(allPropsAsList.contains(propertyName) || 
NUPROP_WARNTEXT.keySet().contains(propertyName)
+            if (!(allPropsAsList.contains(propertyName) || 
NUPROP_WARNTEXT.containsKey(propertyName)
                     || SILENT_PROPERTIES.contains(propertyName))) {
                 final String propertyValue = ra.getContent().toString();
                 final StringBuilder stringBuilder = new 
StringBuilder(nameString);
@@ -490,6 +492,11 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
             
dataSource.setPoolPreparedStatements(Boolean.valueOf(value).booleanValue());
         }
 
+        value = properties.getProperty(PROP_CLEAR_STATEMENT_POOL_ON_RETURN);
+        if (value != null) {
+            
dataSource.setClearStatementPoolOnReturn(Boolean.valueOf(value).booleanValue());
+        }
+
         value = properties.getProperty(PROP_MAX_OPEN_PREPARED_STATEMENTS);
         if (value != null) {
             dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value));
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java 
b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
index 8e07619..564a630 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
@@ -16,6 +16,8 @@
  */
 package org.apache.tomcat.dbcp.dbcp2;
 
+import java.sql.SQLException;
+
 /**
  * Defines the methods that will be made available via JMX.
  *
@@ -130,6 +132,14 @@ public interface BasicDataSourceMXBean {
     boolean isPoolPreparedStatements();
 
     /**
+     * See {@link BasicDataSource#isClearStatementPoolOnReturn()}
+     *
+     * @return {@link BasicDataSource#isClearStatementPoolOnReturn()}
+     * @since 2.8.0
+     */
+    boolean isClearStatementPoolOnReturn();
+
+    /**
      * See {@link BasicDataSource#getMaxOpenPreparedStatements()}
      *
      * @return {@link BasicDataSource#getMaxOpenPreparedStatements()}
@@ -313,4 +323,21 @@ public interface BasicDataSourceMXBean {
      * @since 2.1
      */
     String[] getDisconnectionSqlCodesAsArray();
+
+    /**
+     * See {@link BasicDataSource#start()}
+     *
+     * @throws SQLException if an error occurs initializing the datasource
+     *
+     * @since 2.8
+     */
+    void start() throws SQLException;
+
+    /**
+     * See {@link BasicDataSource#restart()}
+     * @throws SQLException if an error occurs initializing the datasource
+     *
+     * @since 2.8
+     */
+    void restart() throws SQLException;
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
index c215d03..45e4dd6 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
@@ -532,7 +532,7 @@ public class DelegatingConnection<C extends Connection> 
extends AbandonedTrace i
         try {
             connection.setAutoCommit(autoCommit);
             if (cacheState) {
-                autoCommitCached = Boolean.valueOf(autoCommit);
+                autoCommitCached = Boolean.valueOf(connection.getAutoCommit());
             }
         } catch (final SQLException e) {
             autoCommitCached = null;
@@ -556,7 +556,7 @@ public class DelegatingConnection<C extends Connection> 
extends AbandonedTrace i
         try {
             connection.setReadOnly(readOnly);
             if (cacheState) {
-                readOnlyCached = Boolean.valueOf(readOnly);
+                readOnlyCached = Boolean.valueOf(connection.isReadOnly());
             }
         } catch (final SQLException e) {
             readOnlyCached = null;
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
index 9c15c7e..bdca159 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
@@ -124,6 +124,9 @@ public class PoolableConnection extends 
DelegatingConnection<Connection> impleme
     protected void passivate() throws SQLException {
         super.passivate();
         setClosedInternal(true);
+        if (getDelegateInternal() instanceof PoolingConnection) {
+            ((PoolingConnection) 
getDelegateInternal()).connectionReturnedToPool();
+        }
     }
 
     /**
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
index 4123d16..b25bb9a 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
@@ -84,6 +84,8 @@ public class PoolableConnectionFactory implements 
PooledObjectFactory<PoolableCo
 
     private boolean poolStatements;
 
+    private boolean clearStatementPoolOnReturn;
+
     private int maxOpenPreparedStatements = 
GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
 
     private long maxConnLifetimeMillis = -1;
@@ -392,6 +394,7 @@ public class PoolableConnectionFactory implements 
PooledObjectFactory<PoolableCo
             final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> 
stmtPool = new GenericKeyedObjectPool<>(
                     poolingConn, config);
             poolingConn.setStatementPool(stmtPool);
+            
poolingConn.setClearStatementPoolOnReturn(clearStatementPoolOnReturn);
             poolingConn.setCacheState(cacheState);
         }
 
@@ -597,6 +600,17 @@ public class PoolableConnectionFactory implements 
PooledObjectFactory<PoolableCo
         this.poolStatements = poolStatements;
     }
 
+    /**
+     * Sets whether the pool of statements (which was enabled with {@link 
#setPoolStatements(boolean)}) should
+     * be cleared when the connection is returned to its pool. Default is 
false.
+     *
+     * @param clearStatementPoolOnReturn clear or not
+     * @since 2.8.0
+     */
+    public void setClearStatementPoolOnReturn(final boolean 
clearStatementPoolOnReturn) {
+        this.clearStatementPoolOnReturn = clearStatementPoolOnReturn;
+    }
+
     public void setRollbackOnReturn(final boolean rollbackOnReturn) {
         this.rollbackOnReturn = rollbackOnReturn;
     }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
index e278722..6dd738f 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
@@ -65,6 +65,8 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
     /** Pool of {@link PreparedStatement}s. and {@link CallableStatement}s */
     private KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pstmtPool;
 
+    private boolean clearStatementPoolOnReturn = false;
+
     /**
      * Constructor.
      *
@@ -117,6 +119,23 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
     }
 
     /**
+     * Notification from {@link PoolableConnection} that we returned to the 
pool.
+     *
+     * @throws SQLException when <code>clearStatementPoolOnReturn</code> is 
true and the statement pool could not be
+     *                      cleared
+     * @since 2.8.0
+     */
+    public void connectionReturnedToPool() throws SQLException {
+        if (pstmtPool != null && clearStatementPoolOnReturn) {
+            try {
+                pstmtPool.clear();
+            } catch (Exception e) {
+                throw new SQLException("Error clearing statement pool", e);
+            }
+        }
+    }
+
+    /**
      * Creates a PStmtKey for the given arguments.
      *
      * @param sql
@@ -134,7 +153,8 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
      * @param sql
      *            the SQL string used to define the statement
      * @param columnIndexes
-     *            column indexes
+     *            An array of column indexes indicating the columns that 
should be returned from the inserted row or
+     *            rows.
      *
      * @return the PStmtKey created for the given arguments.
      */
@@ -142,6 +162,17 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
         return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), 
getSchemaOrNull(), columnIndexes);
     }
 
+    /**
+     * Creates a PStmtKey for the given arguments.
+     *
+     * @param sql
+     *            the SQL string used to define the statement
+     * @param autoGeneratedKeys
+     *            A flag indicating whether auto-generated keys should be 
returned; one of
+     *            <code>Statement.RETURN_GENERATED_KEYS</code> or 
<code>Statement.NO_GENERATED_KEYS</code>.
+     *
+     * @return the PStmtKey created for the given arguments.
+     */
     protected PStmtKey createKey(final String sql, final int 
autoGeneratedKeys) {
         return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), 
getSchemaOrNull(), autoGeneratedKeys);
     }
@@ -277,13 +308,23 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
     }
 
     private String getSchemaOrNull() {
-        String catalog = null;
+        String schema = null;
         try {
-            catalog = getSchema();
+            schema = getSchema();
         } catch (final SQLException e) {
             // Ignored
         }
-        return catalog;
+        return schema;
+    }
+
+    /**
+     * Returns the prepared statement pool we're using.
+     *
+     * @return statement pool
+     * @since 2.8.0
+     */
+    public KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> 
getStatementPool() {
+        return pstmtPool;
     }
 
     /**
@@ -342,6 +383,19 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
     /**
      * Creates or obtains a {@link CallableStatement} from the pool.
      *
+     * @param key
+     *            a {@link PStmtKey} for the given arguments
+     * @return a {@link PoolableCallableStatement}
+     * @throws SQLException
+     *             Wraps an underlying exception.
+     */
+    private CallableStatement prepareCall(final PStmtKey key) throws 
SQLException {
+        return (CallableStatement) prepareStatement(key);
+    }
+
+    /**
+     * Creates or obtains a {@link CallableStatement} from the pool.
+     *
      * @param sql
      *            the SQL string used to define the CallableStatement
      * @return a {@link PoolableCallableStatement}
@@ -350,15 +404,7 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
      */
     @Override
     public CallableStatement prepareCall(final String sql) throws SQLException 
{
-        try {
-            return (CallableStatement) pstmtPool.borrowObject(createKey(sql, 
StatementType.CALLABLE_STATEMENT));
-        } catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenCallableStatements limit reached", 
e);
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow callableStatement from pool 
failed", e);
-        }
+        return prepareCall(createKey(sql, StatementType.CALLABLE_STATEMENT));
     }
 
     /**
@@ -377,16 +423,7 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
     @Override
     public CallableStatement prepareCall(final String sql, final int 
resultSetType, final int resultSetConcurrency)
             throws SQLException {
-        try {
-            return (CallableStatement) pstmtPool.borrowObject(
-                    createKey(sql, resultSetType, resultSetConcurrency, 
StatementType.CALLABLE_STATEMENT));
-        } catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenCallableStatements limit reached", 
e);
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow callableStatement from pool 
failed", e);
-        }
+        return prepareCall(createKey(sql, resultSetType, resultSetConcurrency, 
StatementType.CALLABLE_STATEMENT));
     }
 
     /**
@@ -407,32 +444,25 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
     @Override
     public CallableStatement prepareCall(final String sql, final int 
resultSetType, final int resultSetConcurrency,
             final int resultSetHoldability) throws SQLException {
-        try {
-            return (CallableStatement) pstmtPool.borrowObject(createKey(sql, 
resultSetType, resultSetConcurrency,
-                    resultSetHoldability, StatementType.CALLABLE_STATEMENT));
-        } catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenCallableStatements limit reached", 
e);
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow callableStatement from pool 
failed", e);
-        }
+        return prepareCall(createKey(sql, resultSetType, resultSetConcurrency,
+                resultSetHoldability, StatementType.CALLABLE_STATEMENT));
     }
 
     /**
      * Creates or obtains a {@link PreparedStatement} from the pool.
      *
-     * @param sql
-     *            the SQL string used to define the PreparedStatement
+     * @param key
+     *            a {@link PStmtKey} for the given arguments
      * @return a {@link PoolablePreparedStatement}
+     * @throws SQLException
+     *             Wraps an underlying exception.
      */
-    @Override
-    public PreparedStatement prepareStatement(final String sql) throws 
SQLException {
+    private PreparedStatement prepareStatement(final PStmtKey key) throws 
SQLException {
         if (null == pstmtPool) {
             throw new SQLException("Statement pool is null - closed or invalid 
PoolingConnection.");
         }
         try {
-            return pstmtPool.borrowObject(createKey(sql));
+            return pstmtPool.borrowObject(key);
         } catch (final NoSuchElementException e) {
             throw new SQLException("MaxOpenPreparedStatements limit reached", 
e);
         } catch (final RuntimeException e) {
@@ -442,20 +472,35 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
         }
     }
 
+    /**
+     * Creates or obtains a {@link PreparedStatement} from the pool.
+     *
+     * @param sql
+     *            the SQL string used to define the PreparedStatement
+     * @return a {@link PoolablePreparedStatement}
+     * @throws SQLException
+     *             Wraps an underlying exception.
+     */
+    @Override
+    public PreparedStatement prepareStatement(final String sql) throws 
SQLException {
+        return prepareStatement(createKey(sql));
+    }
+
+    /*
+     * Creates or obtains a {@link PreparedStatement} from the pool.
+     *
+     * @param sql
+     *            the SQL string used to define the PreparedStatement
+     * @param autoGeneratedKeys
+     *            A flag indicating whether auto-generated keys should be 
returned; one of
+     *            <code>Statement.RETURN_GENERATED_KEYS</code> or 
<code>Statement.NO_GENERATED_KEYS</code>.
+     * @return a {@link PoolablePreparedStatement}
+     * @throws SQLException
+     *             Wraps an underlying exception.
+     */
     @Override
     public PreparedStatement prepareStatement(final String sql, final int 
autoGeneratedKeys) throws SQLException {
-        if (null == pstmtPool) {
-            throw new SQLException("Statement pool is null - closed or invalid 
PoolingConnection.");
-        }
-        try {
-            return pstmtPool.borrowObject(createKey(sql, autoGeneratedKeys));
-        } catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenPreparedStatements limit reached", 
e);
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", 
e);
-        }
+        return prepareStatement(createKey(sql, autoGeneratedKeys));
     }
 
     /**
@@ -464,23 +509,16 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
      * @param sql
      *            the SQL string used to define the PreparedStatement
      * @param columnIndexes
-     *            column indexes
+     *            An array of column indexes indicating the columns that 
should be returned from the inserted row or
+     *            rows.
      * @return a {@link PoolablePreparedStatement}
+     * @throws SQLException
+     *             Wraps an underlying exception.
+     *
      */
     @Override
     public PreparedStatement prepareStatement(final String sql, final int 
columnIndexes[]) throws SQLException {
-        if (null == pstmtPool) {
-            throw new SQLException("Statement pool is null - closed or invalid 
PoolingConnection.");
-        }
-        try {
-            return pstmtPool.borrowObject(createKey(sql, columnIndexes));
-        } catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenPreparedStatements limit reached", 
e);
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", 
e);
-        }
+        return prepareStatement(createKey(sql, columnIndexes));
     }
 
     /**
@@ -493,22 +531,13 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
      * @param resultSetConcurrency
      *            result set concurrency
      * @return a {@link PoolablePreparedStatement}
+     * @throws SQLException
+     *             Wraps an underlying exception.
      */
     @Override
     public PreparedStatement prepareStatement(final String sql, final int 
resultSetType, final int resultSetConcurrency)
             throws SQLException {
-        if (null == pstmtPool) {
-            throw new SQLException("Statement pool is null - closed or invalid 
PoolingConnection.");
-        }
-        try {
-            return pstmtPool.borrowObject(createKey(sql, resultSetType, 
resultSetConcurrency));
-        } catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenPreparedStatements limit reached", 
e);
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", 
e);
-        }
+        return prepareStatement(createKey(sql, resultSetType, 
resultSetConcurrency));
     }
 
     /**
@@ -523,22 +552,13 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
      * @param resultSetHoldability
      *            result set holdability
      * @return a {@link PoolablePreparedStatement}
+     * @throws SQLException
+     *             Wraps an underlying exception.
      */
     @Override
     public PreparedStatement prepareStatement(final String sql, final int 
resultSetType, final int resultSetConcurrency,
             final int resultSetHoldability) throws SQLException {
-        if (null == pstmtPool) {
-            throw new SQLException("Statement pool is null - closed or invalid 
PoolingConnection.");
-        }
-        try {
-            return pstmtPool.borrowObject(createKey(sql, resultSetType, 
resultSetConcurrency, resultSetHoldability));
-        } catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenPreparedStatements limit reached", 
e);
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", 
e);
-        }
+        return prepareStatement(createKey(sql, resultSetType, 
resultSetConcurrency, resultSetHoldability));
     }
 
     /**
@@ -549,21 +569,23 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
      * @param columnNames
      *            column names
      * @return a {@link PoolablePreparedStatement}
+     * @throws SQLException
+     *             Wraps an underlying exception.
      */
     @Override
     public PreparedStatement prepareStatement(final String sql, final String 
columnNames[]) throws SQLException {
-        if (null == pstmtPool) {
-            throw new SQLException("Statement pool is null - closed or invalid 
PoolingConnection.");
-        }
-        try {
-            return pstmtPool.borrowObject(createKey(sql, columnNames));
-        } catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenPreparedStatements limit reached", 
e);
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", 
e);
-        }
+        return prepareStatement(createKey(sql, columnNames));
+    }
+
+    /**
+     * Sets whether the pool of statements should be cleared when the 
connection is returned to its pool.
+     * Default is false.
+     *
+     * @param clearStatementPoolOnReturn clear or not
+     * @since 2.8.0
+     */
+    public void setClearStatementPoolOnReturn(final boolean 
clearStatementPoolOnReturn) {
+        this.clearStatementPoolOnReturn = clearStatementPoolOnReturn;
     }
 
     /**
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java 
b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
index 34bad40..772682f 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
@@ -37,6 +37,7 @@ import javax.naming.spi.ObjectFactory;
 import javax.sql.ConnectionPoolDataSource;
 import javax.sql.PooledConnection;
 
+import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
 import org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement;
 import org.apache.tomcat.dbcp.dbcp2.PStmtKey;
 import org.apache.tomcat.dbcp.dbcp2.Utils;
@@ -621,17 +622,15 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
     /**
      * Sets the number of statements to examine during each run of the idle 
object evictor thread (if any).
      * <p>
-     * When a negative value is supplied, <code>ceil({*link 
#numIdle})/abs({*link #getNumTestsPerEvictionRun})</code>
-     * tests will be run. I.e., when the value is <i>-n</i>, roughly one 
<i>n</i>th of the idle objects will be tested
-     * per run.
+     * When a negative value is supplied,
+     * <code>ceil({@link BasicDataSource#getNumIdle})/abs({@link 
#getNumTestsPerEvictionRun})</code> tests will be run.
+     * I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the idle 
objects will be tested per run.
      * </p>
      *
-     * @param numTestsPerEvictionRun
-     *            number of statements to examine per run
+     * @param numTestsPerEvictionRun number of statements to examine per run
      * @see #getNumTestsPerEvictionRun()
      * @see #setTimeBetweenEvictionRunsMillis(long)
-     * @throws IllegalStateException
-     *             if {@link #getPooledConnection()} has been called
+     * @throws IllegalStateException if {@link #getPooledConnection()} has 
been called
      */
     public void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
         assertInitializationAllowed();
@@ -755,11 +754,8 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
         builder.append(getConnectionCalled);
         builder.append(", connectionProperties=");
         Properties tmpProps = connectionProperties;
-        final String pwdKey = "password";
-        if (connectionProperties != null && 
connectionProperties.contains(pwdKey)) {
-            tmpProps = (Properties) connectionProperties.clone();
-            tmpProps.remove(pwdKey);
-        }
+        tmpProps = mask(tmpProps, "user");
+        tmpProps = mask(tmpProps, "password");
         builder.append(tmpProps);
         builder.append(", accessToUnderlyingConnectionAllowed=");
         builder.append(accessToUnderlyingConnectionAllowed);
@@ -767,6 +763,14 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
         return builder.toString();
     }
 
+    private Properties mask(Properties properties, final String 
maskValueAtKey) {
+        if (connectionProperties != null && 
connectionProperties.contains(maskValueAtKey)) {
+            properties = (Properties) connectionProperties.clone();
+            properties.put(maskValueAtKey, "[" + maskValueAtKey + "]");
+        }
+        return properties;
+    }
+
     private void update(final Properties properties, final String key, final 
String value) {
         if (properties != null && key != null) {
             if (value == null) {
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
index 915e4cd..93363a4 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
@@ -37,8 +37,7 @@ import org.apache.tomcat.dbcp.pool2.PooledObjectFactory;
 import org.apache.tomcat.dbcp.pool2.impl.DefaultPooledObject;
 
 /**
- * A {@link PooledObjectFactory} that creates
- * {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnection PoolableConnection}s.
+ * A {@link PooledObjectFactory} that creates {@link 
org.apache.tomcat.dbcp.dbcp2.PoolableConnection PoolableConnection}s.
  *
  * @since 2.0
  */
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
index 69d6eff..8168bcc 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
@@ -532,7 +532,7 @@ public abstract class InstanceKeyDataSource implements 
DataSource, Referenceable
     }
 
     /**
-     * Sets the backend ConnectionPoolDataSource. This property should not be 
set if using JNDI to access the
+     * Sets the back end ConnectionPoolDataSource. This property should not be 
set if using JNDI to access the
      * data source.
      *
      * @param v
@@ -689,7 +689,7 @@ public abstract class InstanceKeyDataSource implements 
DataSource, Referenceable
 
     /**
      * Gets the value of jndiEnvironment which is used when instantiating a 
JNDI InitialContext. This InitialContext is
-     * used to locate the backend ConnectionPoolDataSource.
+     * used to locate the back end ConnectionPoolDataSource.
      *
      * @param key
      *            JNDI environment key.
@@ -705,7 +705,7 @@ public abstract class InstanceKeyDataSource implements 
DataSource, Referenceable
 
     /**
      * Sets the value of the given JNDI environment property to be used when 
instantiating a JNDI InitialContext. This
-     * InitialContext is used to locate the backend ConnectionPoolDataSource.
+     * InitialContext is used to locate the back end ConnectionPoolDataSource.
      *
      * @param key
      *            the JNDI environment property to set.
@@ -721,7 +721,7 @@ public abstract class InstanceKeyDataSource implements 
DataSource, Referenceable
 
     /**
      * Sets the JNDI environment to be used when instantiating a JNDI 
InitialContext. This InitialContext is used to
-     * locate the backend ConnectionPoolDataSource.
+     * locate the back end ConnectionPoolDataSource.
      *
      * @param properties
      *            the JNDI environment property to set which will overwrite 
any current settings
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/package-info.java 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/package-info.java
index 6395e29..531db68 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/package-info.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/package-info.java
@@ -127,7 +127,7 @@
  * Connection pooling is useful in applications regardless of whether they run
  * in a J2EE environment and a <code>DataSource</code> can be used within a
  * simpler environment.  The example below shows SharedPoolDataSource using
- * DriverAdapterCPDS as the backend source, though any CPDS is applicable.
+ * DriverAdapterCPDS as the back end source, though any CPDS is applicable.
  * </p>
  *
  * <code>
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 74f20b0..bba5959 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -188,6 +188,10 @@
         Update the internal fork of Apache Commons Pool to 2.8.1. Code clean-up
         and improved abandoned pool handling. (markt)
       </add>
+      <add>
+        Update the internal fork of Apache Commons DBCP to 6d232e5 (2020-08-11,
+        2.8.0-SNAPSHOT). Code clean-up various bug fixes. (markt)
+      </add>
     </changelog>
   </subsection>
 </section>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to