From 930cdb068451491aeb90af24c0f108752bf88eeb Mon Sep 17 00:00:00 2001 From: lukaseder Date: Thu, 22 Mar 2018 15:47:53 +0100 Subject: [PATCH] [#4277] INSERT .. RETURNING acquires two different Connections for MySQL --- .../org/jooq/impl/DefaultExecuteContext.java | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java index d5829c7e3d..029cc5c749 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java @@ -103,6 +103,7 @@ class DefaultExecuteContext implements ExecuteContext { // Transient attributes (created afresh per execution) private transient ConnectionProvider connectionProvider; private transient Connection connection; + private transient SettingsEnabledConnection wrappedConnection; private transient PreparedStatement statement; private transient int statementExecutionCount; private transient ResultSet resultSet; @@ -399,7 +400,11 @@ class DefaultExecuteContext implements ExecuteContext { } private DefaultExecuteContext(Configuration configuration, Query query, Query[] batchQueries, Routine routine) { - this.configuration = configuration; + + // [#4277] The ExecuteContext's Configuration will always return the same Connection, + // e.g. when running statements from sub-ExecuteContexts + this.connectionProvider = configuration.connectionProvider(); + this.configuration = configuration.derive(new ExecuteContextConnectionProvider()); this.data = new DataMap(); this.query = query; this.routine = routine; @@ -591,7 +596,7 @@ class DefaultExecuteContext implements ExecuteContext { @Override public final DSLContext dsl() { - return configuration.dsl(); + return configuration().dsl(); } @Override @@ -620,13 +625,10 @@ class DefaultExecuteContext implements ExecuteContext { // single method. It can thus be guaranteed, that every connection is // wrapped by a ConnectionProxy, transparently, in order to implement // Settings.getStatementType() correctly. + if (wrappedConnection == null && connectionProvider != null) + connection(connectionProvider, connectionProvider.acquire()); - ConnectionProvider provider = connectionProvider != null ? connectionProvider : configuration.connectionProvider(); - if (connection == null && provider != null) { - connection(provider, provider.acquire()); - } - - return connection; + return wrappedConnection; } /** @@ -639,10 +641,15 @@ class DefaultExecuteContext implements ExecuteContext { final void connection(ConnectionProvider provider, Connection c) { if (c != null) { LOCAL_CONNECTION.set(c); - connection = new SettingsEnabledConnection(new ProviderEnabledConnection(provider, c), configuration.settings()); + connection = c; + wrappedConnection = wrapConnection(provider, c); } } + private final SettingsEnabledConnection wrapConnection(ConnectionProvider provider, Connection c) { + return new SettingsEnabledConnection(new ProviderEnabledConnection(provider, c), configuration.settings()); + } + final void incrementStatementExecutionCount() { statementExecutionCount++; } @@ -749,4 +756,22 @@ class DefaultExecuteContext implements ExecuteContext { public final void serverOutput(String[] output) { this.serverOutput = output; } + + private final class ExecuteContextConnectionProvider implements ConnectionProvider { + + @Override + public final Connection acquire() { + + // [#4277] Connections are acquired lazily in parent ExecuteContext. A child ExecuteContext + // may well need a Connection earlier than the parent, in case of which acquisition is + // forced in the parent as well. + if (connection == null) + DefaultExecuteContext.this.connection(); + + return wrapConnection(this, connection); + } + + @Override + public final void release(Connection c) {} + } }