This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 11.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 48740bca87e73498176616f0ce85b9ce73ec13fb 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 364b98dcd9..b10e2a2b5c 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 @@ -204,6 +204,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; @@ -234,14 +244,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() { @@ -325,6 +352,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]
