From 5d1a98b49dcb754d1fd5fe0606a135304195eea7 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Tue, 5 Feb 2013 14:53:48 +0100 Subject: [PATCH] [#1886] Query.bind() has no effect when Query.keepStatement(true) and StatementType.STATIC_STATEMENT are combined --- .../jooq/test/_/testcases/StatementTests.java | 36 ++++++++++++++--- jOOQ/src/main/java/org/jooq/Query.java | 16 ++++++++ .../java/org/jooq/impl/AbstractQuery.java | 39 +++++++++++++++++-- 3 files changed, 82 insertions(+), 9 deletions(-) diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/StatementTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/StatementTests.java index 3d3f30d7e8..0f71dfdf19 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/StatementTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/StatementTests.java @@ -40,6 +40,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; import static org.jooq.SQLDialect.H2; +import static org.jooq.impl.Factory.inline; import static org.jooq.impl.Factory.val; import java.lang.reflect.InvocationHandler; @@ -60,6 +61,7 @@ import org.jooq.ResultQuery; import org.jooq.Select; import org.jooq.TableRecord; import org.jooq.UpdatableRecord; +import org.jooq.conf.StatementType; import org.jooq.exception.DataAccessException; import org.jooq.impl.DefaultExecuteListener; import org.jooq.impl.Executor; @@ -102,7 +104,7 @@ extends BaseTest> query = create.select(val(1)); + ResultQuery> query = create.select(val(1), inline(2)); assertEquals(1, query.fetchOne(0)); assertEquals(2, query.bind(1, 2).fetchOne(0)); @@ -116,21 +118,43 @@ extends BaseTest> cursor = query.fetchLazy(); + Cursor> cursor = query.fetchLazy(); assertEquals(3, cursor.fetchOne().getValue(0)); assertEquals(3, query.fetchOne(0)); + // [#1886] The first underlying statement should've been closed when + // using StatementType.STATIC_STATEMENT assertEquals(4, KeepStatementListener.statements.size()); assertEquals(0, KeepStatementListener.closed); - assertTrue( + assertEquals( + create().getSettings().getStatementType() == StatementType.PREPARED_STATEMENT, KeepStatementListener.statements.get(0) == KeepStatementListener.statements.get(1)); + + // Statements #2, #3, #4 should be identical assertTrue( - KeepStatementListener.statements.get(0) == + KeepStatementListener.statements.get(1) == + KeepStatementListener.statements.get(2)); + assertTrue( + KeepStatementListener.statements.get(2) == + KeepStatementListener.statements.get(3)); + + // [#1886] Check if inline bind values are correctly changed + KeepStatementListener.reset(); + assertEquals(3, query.fetchOne(0)); + assertEquals(3, query.bind(2, 4).fetchOne(0)); + assertEquals(4, query.bind(2, 4).fetchOne(1)); + + // All statements should be closed, as the inline bind value was changed + assertEquals(3, KeepStatementListener.statements.size()); + assertEquals(0, KeepStatementListener.closed); + assertTrue( + KeepStatementListener.statements.get(0) != + KeepStatementListener.statements.get(1)); + assertTrue( + KeepStatementListener.statements.get(1) != KeepStatementListener.statements.get(2)); cursor.close(); diff --git a/jOOQ/src/main/java/org/jooq/Query.java b/jOOQ/src/main/java/org/jooq/Query.java index 52cd922ccb..aebf1e280b 100644 --- a/jOOQ/src/main/java/org/jooq/Query.java +++ b/jOOQ/src/main/java/org/jooq/Query.java @@ -172,6 +172,14 @@ public interface Query extends QueryPart, Attachable { /** * Bind a new value to a named parameter + *

+ * [#1886] If the bind value with name param is inlined ( + * {@link Param#isInline()}) or if this query was created with + * {@link StatementType#STATIC_STATEMENT} and there is an underlying + * PreparedStatement kept open because of + * {@link #keepStatement(boolean)}, the underlying + * PreparedStatement will be closed automatically in order for + * new bind values to have an effect. * * @param param The named parameter name. If this is a number, then this is * the same as calling {@link #bind(int, Object)} @@ -185,6 +193,14 @@ public interface Query extends QueryPart, Attachable { /** * Bind a new value to an indexed parameter + *

+ * [#1886] If the bind value at index is inlined ( + * {@link Param#isInline()}) or if this query was created with + * {@link StatementType#STATIC_STATEMENT} and there is an underlying + * PreparedStatement kept open because of + * {@link #keepStatement(boolean)}, the underlying + * PreparedStatement will be closed automatically in order for + * new bind values to have an effect. * * @param index The parameter index, starting with 1 * @param value The new bind value. diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java index 627fe9675a..b8bbe4d202 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java @@ -50,6 +50,8 @@ import org.jooq.ExecuteContext; import org.jooq.ExecuteListener; import org.jooq.Param; import org.jooq.Query; +import org.jooq.conf.SettingsTools; +import org.jooq.conf.StatementType; import org.jooq.exception.DetachedException; import org.jooq.tools.JooqLogger; @@ -123,6 +125,7 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query, Attacha } p.setConverted(value); + closeIfNecessary(p); return this; } } @@ -134,16 +137,46 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query, Attacha */ @Override public Query bind(int index, Object value) { - Param[] array = getParams().values().toArray(new Param[0]); + Param[] params = getParams().values().toArray(new Param[0]); - if (index < 1 || index > array.length) { + if (index < 1 || index > params.length) { throw new IllegalArgumentException("Index out of range for Query parameters : " + index); } - array[index - 1].setConverted(value); + Param param = params[index - 1]; + param.setConverted(value); + closeIfNecessary(param); return this; } + /** + * Close the statement if necessary. + *

+ * [#1886] If there is an open (cached) statement and its bind values are + * inlined due to a {@link StatementType#STATIC_STATEMENT} setting, the + * statement should be closed. + * + * @param param The param that was changed + */ + private final void closeIfNecessary(Param param) { + + // This is relevant when there is an open statement, only + if (keepStatement() && statement != null) { + + // When an inlined param is being changed, the previous statement + // has to be closed, regardless if variable binding is performed + if (param.isInline()) { + close(); + } + + // If all params are inlined, the previous statement always has to + // be closed + else if (SettingsTools.executeStaticStatements(getConfiguration().getSettings())) { + close(); + } + } + } + /** * Subclasses may override this for covariant result types *