-
-
Notifications
You must be signed in to change notification settings - Fork 336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot use bindList
with prepareBatch
when lists have varied size.
#2335
Comments
So I put together this test: class Issue2335Test {
static final Something ONE = new Something(3, "foo");
static final Something TWO = new Something(4, "bar");
static final Something THREE = new Something(5, "baz");
@RegisterExtension
public static EmbeddedPgExtension pg = MultiDatabaseBuilder.instanceWithDefaults().build();
@RegisterExtension
PgDatabaseExtension h2Extension = PgDatabaseExtension.instance(pg);
Handle handle;
Jdbi jdbi;
@BeforeEach
void setUp() {
jdbi = h2Extension.getJdbi();
handle = h2Extension.getSharedHandle();
handle.execute("CREATE TABLE arr_table (id INT PRIMARY KEY, data varchar array)");
handle.execute("INSERT INTO arr_table (id, data) values (1, ARRAY[1, 2, 3])");
handle.execute("INSERT INTO arr_table (id, data) values (2, ARRAY[4, 5, 6])");
}
@Test
void testBatchQuery() {
try (PreparedBatch batch = handle.prepareBatch("INSERT INTO arr_table (id, data) VALUES (:id, ARRAY[<data>])")) {
batch.bind("id", 3).bindList("data", Arrays.asList(3, 4, 5)).add();
batch.bind("id", 4).bindList("data", Arrays.asList(6, 7, 8)).add();
batch.bind("id", 5).bindList("data", Arrays.asList(10, 11, 12)).add();
int [] result = batch.execute();
assertThat(result).hasSize(3)
.containsExactly(1, 1, 1);
}
}
} and that works fine. I would need to see more of your specific use case. Are you binding more parameters? |
ok, I figured out how to reproduce it. It depends on the numbers of list elements begin different from row to row. |
bindList
with prepareBatch
bindList
with prepareBatch
when arrays are of varied size.
bindList
with prepareBatch
when arrays are of varied size.bindList
with prepareBatch
when lists have varied size.
The batch pieces work by creating a prepared statement and then executing those repeatedly with different values. This is where the performance of batch comes from. The bindList is an odd duck, because it it actually changes the statement by using templating. Depending on the database that you use, you can do this (this is for postgres): @Test
void testUpdateOperation() {
try (PreparedBatch batch = handle.prepareBatch(
"UPDATE something SET name = :name WHERE id = ANY(:ids)")) {
batch.bind("name", "foo").bindArray("ids", Integer.class, Arrays.asList(1, 2)).add();
batch.bind("name", "bar").bindArray("ids", Integer.class, Arrays.asList(3)).add();
batch.bind("name", "baz").bindArray("ids", Integer.class, Arrays.asList(1, 2, 4)).add();
int[] result = batch.execute();
assertThat(result).hasSize(3)
.containsExactly(2, 1, 3);
}
} => Bind the list as a typed SQL array (integer array) and use the This is more a documentation issue (you are correct: bindList() is incompatible with the way the batches work) than a real but, but it nevertheless causes customer issues. |
Thanks for investigating and providing the workaround. A nice-to-have would be if this case was detected and a more specific error was thrown. Having one might've prevented me from spending time questioning what I might be doing wrong. |
document that bindList is not working well with batches. addresses jdbi#2335
Understood. Detecting this problem is not simple (Jdbi is not a fully fledged ORM; it is a convenience library); we do not actually track the number of placeholders in batch statements. Maybe we should. I added documentation for this issue. |
document that bindList is not working well with batches. addresses jdbi#2335
Closing, still tracked in #2390. |
I think we can close this one - as you say, batching works by re-using the same sql, so you can't change the template. |
JDBI version: 3.37.1
Database: Postgresql
I have a kotlin project where I'm trying to use
prepareBatch
in combination withbindList
, but it is failing.Expected
I should be able to execute the above code with an error being thrown.
Note: Above is a minimal repro. Actual use case is an
UPDATE
with many moreadd()
calls in a loop, but the result is the same.Actual
Instead I see the following exception.
It looks like the prepared statement with
IN (:__array_0,:__array_1)
is generated for the larger list1, 2
so the smaller list of just1
fails to match on:__array_1
.Follow up
Is this a bug? Or is
bindList
incompatible withprepareBatch
by design? If the latter, should this be clarified in the docs?The text was updated successfully, but these errors were encountered: