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

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

commit f4130dedc6d210d9e0489f0fb043187a4670b068
Author: opencode <[email protected]>
AuthorDate: Tue Oct 27 22:30:40 2026 +0100

    Document the borrow-scoped connection binding of the decorator
    
    The statement proxy built by the StatementDecoratorInterceptor answers
    getConnection() from a binding made when the proxy's borrow was created.
    That binding is a snapshot: once the borrow is returned, the handle it
    holds is inert, and a component that lets a statement proxy outlive the
    borrow it was created in - StatementCache parking and later reissuing a
    statement, for instance - has to rebind it before the proxy is handed
    out again. The rebind itself landed with the cache-hit fix, and the
    behavior is covered by existing tests; what was missing was the contract
    itself, which a careless extension would violate silently.
    
    The connection field, its accessor pair and the getConnection handler
    arm now state the contract: what the binding is, when it stops working,
    who seeds it, and the rule that reuse across borrows requires a rebind,
    with StatementCache's cache-hit rebinding as the example. Documentation
    only; no behavior, API or binary change, hence no changelog entry.
---
 .../interceptor/StatementDecoratorInterceptor.java | 35 ++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git 
a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java
 
b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java
index 10f0f249e3..027d8dd6a7 100644
--- 
a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java
+++ 
b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java
@@ -207,6 +207,16 @@ public class StatementDecoratorInterceptor extends 
AbstractCreateStatementInterc
          */
         protected T delegate;
         private Object actualProxy;
+        /**
+         * The connection handle of the borrow during which this proxy was
+         * created, bound through {@link #setConnection(Object)}. It is a
+         * creation-time snapshot, not a live view: once that borrow is
+         * returned the handle answers nothing. A component that lets a
+         * statement proxy outlive its borrow - {@link StatementCache}
+         * recycling a parked statement, for instance - must therefore
+         * re-bind the handle to the new borrower before handing the proxy
+         * out; see {@link StatementCache#invoke(Object, Method, Object[])}.
+         */
         private Object connection;
         private String sql;
         private Constructor<?> constructor;
@@ -237,14 +247,31 @@ public class StatementDecoratorInterceptor extends 
AbstractCreateStatementInterc
         }
 
         /**
-         * Sets the connection proxy.
+         * Binds the connection handle that {@link #getConnection()} will
+         * report for this statement. {@code createDecorator} binds the
+         * handle of the borrow that creates the statement, and
+         * {@link StatementCache} seeds the closing borrow's handle when it
+         * parks a statement; the binding is kept as a snapshot and is
+         * never refreshed on its own. A handle kept past its borrow is
+         * inert by design, so anything reusing a statement proxy across
+         * borrows must call this method with the new borrower's handle
+         * before the proxy is handed out, as {@link StatementCache} does
+         * on a cache hit.
+         *
          * @param proxy the connection proxy
          */
         public void setConnection(Object proxy) {
             this.connection = proxy;
         }
         /**
-         * Returns the connection proxy.
+         * Returns the connection proxy most recently bound through
+         * {@link #setConnection(Object)}. While that binding's borrow is
+         * current it is a live handle; a statement kept past its borrow
+         * answers with the disposed facade it came from. Once the
+         * statement is closed the handler refuses the call before it
+         * reaches the snapshot, so a stale binding is only visible
+         * through diagnostics such as {@link #toString()}.
+         *
          * @return the connection proxy
          */
         public Object getConnection() {
@@ -328,6 +355,10 @@ public class StatementDecoratorInterceptor extends 
AbstractCreateStatementInterc
                 throw new SQLException("Statement closed.");
             }
             if (compare(GETCONNECTION_VAL,method)){
+                // the handle of the current borrow, as bound by
+                // setConnection; a proxy kept past its borrow gets the
+                // inert handle it came from, and a closed one has already
+                // thrown above
                 return connection;
             }
             boolean process = false;


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

Reply via email to