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

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


The following commit(s) were added to refs/heads/9.0.x by this push:
     new d2917ea453 Fix BZ 69236 - reset JDBC interceptors in declaration order
d2917ea453 is described below

commit d2917ea4537b15740f23dab7efd3838fb6465a40
Author: Arturo Bernal <[email protected]>
AuthorDate: Fri Oct 23 14:07:55 2026 +0200

    Fix BZ 69236 - reset JDBC interceptors in declaration order
    
    When a pooled connection was created, the interceptor chain was built
    from the last interceptor to the first and each interceptor was reset as
    it was added, so reset() was called in reverse order. For a connection
    taken from the pool the chain was reset from the first interceptor to
    the last. Build the chain first and then reset it in declaration order
    in both cases.
---
 .../apache/tomcat/jdbc/pool/ConnectionPool.java    |  11 ++-
 .../jdbc/test/InterceptorResetOrderTest.java       | 106 +++++++++++++++++++++
 2 files changed, 113 insertions(+), 4 deletions(-)

diff --git 
a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
 
b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
index 533b4244ee..b9ad952c1f 100644
--- 
a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
+++ 
b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
@@ -311,8 +311,6 @@ public class ConnectionPool {
                     interceptor.setProperties(proxies[i].getProperties());
                     //setup the chain
                     interceptor.setNext(handler);
-                    //call reset
-                    interceptor.reset(this, con);
                     //configure the last one to be held by the connection
                     handler = interceptor;
                 }catch(Exception x) {
@@ -323,13 +321,18 @@ public class ConnectionPool {
             }
             //cache handler for the next iteration
             con.setHandler(handler);
-        } else {
+        }
+        //reset the chain in the order the interceptors are declared, for new 
and cached handlers alike
+        try {
             JdbcInterceptor next = handler;
-            //we have a cached handler, reset it
             while (next!=null) {
                 next.reset(this, con);
                 next = next.getNext();
             }
+        }catch(Exception x) {
+            SQLException sx = new SQLException("Unable to reset interceptor 
chain.");
+            sx.initCause(x);
+            throw sx;
         }
         // setup statement proxy
         if (getPoolProperties().getUseStatementFacade()) {
diff --git 
a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/InterceptorResetOrderTest.java
 
b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/InterceptorResetOrderTest.java
new file mode 100644
index 0000000000..a4824702cf
--- /dev/null
+++ 
b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/InterceptorResetOrderTest.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.tomcat.jdbc.test;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+import org.apache.tomcat.jdbc.test.driver.Driver;
+
+/**
+ * The reset order of the interceptors must follow the order in which they are 
declared, whether the connection is new
+ * or is taken from the pool.
+ */
+public class InterceptorResetOrderTest extends DefaultTestCase {
+
+    private static final List<String> RESETS = 
Collections.synchronizedList(new ArrayList<>());
+
+    @Before
+    public void setUp() {
+        RESETS.clear();
+        datasource.setDriverClassName(Driver.class.getName());
+        datasource.setUrl("jdbc:tomcat:test");
+        datasource.setMaxActive(1);
+        datasource.setInitialSize(0);
+        datasource.setMinIdle(0);
+        datasource.setJdbcInterceptors(First.class.getName() + ";" + 
Second.class.getName());
+    }
+
+    @Test
+    public void testResetOrderOnNewConnection() throws SQLException {
+        datasource.getConnection().close();
+        Assert.assertEquals(Arrays.asList("first", "second"), RESETS);
+    }
+
+    @Test
+    public void testResetOrderOnReusedConnection() throws SQLException {
+        datasource.getConnection().close();
+        RESETS.clear();
+        datasource.getConnection().close();
+        Assert.assertEquals(Arrays.asList("first", "second"), RESETS);
+    }
+
+    @Test
+    public void testResetFailureIsReportedAsSQLException() {
+        datasource.setJdbcInterceptors(Failing.class.getName());
+
+        SQLException e = Assert.assertThrows(SQLException.class, () -> 
datasource.getConnection());
+
+        Assert.assertTrue(e.getCause() instanceof IllegalStateException);
+    }
+
+    public static class Failing extends JdbcInterceptor {
+
+        @Override
+        public void reset(ConnectionPool parent, PooledConnection con) {
+            if (parent != null) {
+                throw new IllegalStateException();
+            }
+        }
+    }
+
+    public static class First extends JdbcInterceptor {
+
+        @Override
+        public void reset(ConnectionPool parent, PooledConnection con) {
+            // the pool also resets interceptors without a parent when a 
connection is discarded
+            if (parent != null) {
+                RESETS.add("first");
+            }
+        }
+    }
+
+    public static class Second extends JdbcInterceptor {
+
+        @Override
+        public void reset(ConnectionPool parent, PooledConnection con) {
+            if (parent != null) {
+                RESETS.add("second");
+            }
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to