[#1886] Query.bind() has no effect when Query.keepStatement(true)

and StatementType.STATIC_STATEMENT are combined
This commit is contained in:
Lukas Eder 2013-02-05 14:53:48 +01:00
parent 1b0d7c08b9
commit 5d1a98b49d
3 changed files with 82 additions and 9 deletions

View File

@ -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<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
// [#385] By default, new statements are created for every execution
KeepStatementListener.reset();
ResultQuery<Record1<Integer>> query = create.select(val(1));
ResultQuery<Record2<Integer, Integer>> 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<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
KeepStatementListener.reset();
query.keepStatement(true);
assertEquals(2, query.fetchOne(0));
// [#1886] TODO: Fix this for StatementType.STATIC_STATEMENT
assertEquals(3, query.bind(1, 3).fetchOne(0));
Cursor<Record1<Integer>> cursor = query.fetchLazy();
Cursor<Record2<Integer, Integer>> 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();

View File

@ -172,6 +172,14 @@ public interface Query extends QueryPart, Attachable {
/**
* Bind a new value to a named parameter
* <p>
* [#1886] If the bind value with name <code>param</code> is inlined (
* {@link Param#isInline()}) or if this query was created with
* {@link StatementType#STATIC_STATEMENT} and there is an underlying
* <code>PreparedStatement</code> kept open because of
* {@link #keepStatement(boolean)}, the underlying
* <code>PreparedStatement</code> 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
* <p>
* [#1886] If the bind value at <code>index</code> is inlined (
* {@link Param#isInline()}) or if this query was created with
* {@link StatementType#STATIC_STATEMENT} and there is an underlying
* <code>PreparedStatement</code> kept open because of
* {@link #keepStatement(boolean)}, the underlying
* <code>PreparedStatement</code> 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.

View File

@ -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.
* <p>
* [#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
* <p>