Skip to content

Detect an unbatched statement executed after a JDBC batch - #290

Merged
jeanbisutti merged 1 commit into
quick-perf:masterfrom
jeanbisutti:fix-unbatched-statement-after-jdbc-batch
Oct 19, 2026
Merged

jeanbisutti merged 1 commit into
quick-perf:masterfrom
jeanbisutti:fix-unbatched-statement-after-jdbc-batch

Conversation

@jeanbisutti

Copy link
Copy Markdown
Collaborator

Problem

@ExpectJdbcBatching(batchSize = N) did not report an INSERT, UPDATE or DELETE executed without JDBC batching after a batch. The same statements executed in the opposite order were reported.

For example, with @ExpectJdbcBatching(batchSize = 30), a batch of 30 inserts followed by an executeUpdate() insert passed. The unbatched insert executed first failed with Expected batch size <30> but is <0>.

SqlStatementBatchRecorder records the different batch sizes and stops after the first unbatched execution, whose batch size is 0. With a batch executed first, the recorded sizes are [30, 0]. SqlStatementBatchVerifier never checked the last recorded size, to allow a last batch containing fewer statements, so the 0 was ignored.

Changes

1. Check a last batch size of 0 (SqlStatementBatchVerifier)

The verifier now also checks the last recorded batch size when it is 0, so [30, 0] fails with Expected batch size <30> but is <0>. A smaller last batch is still allowed: [30, 10] passes.

2. Ignore empty batches (SqlStatementBatchRecorder)

Change 1 alone would have failed tests in which every statement is batched.

datasource-proxy gives a batch size of 0 in two cases:

JDBC call isBatch() getBatchSize()
An unbatched execution: executeUpdate(), execute()... false 0
An empty batch: executeBatch() on a PreparedStatement or a CallableStatement with no addBatch() since the last execution true 0

The recorder stored both as a 0 batch size. On a plain Statement, an empty executeBatch() was already not recorded.

Before this PR, an empty batch at the end was harmless, because the last size was not checked. With change 1, a common JDBC pattern would fail:

for (int i = 1; i <= 60; i++) {
    insertStatement.setLong(1, i);
    insertStatement.addBatch();
    if (i % 30 == 0) {
        insertStatement.executeBatch();   // batches of 30
    }
}
insertStatement.executeBatch();           // the remaining statements: none here, so an empty batch

@jeanbisutti
jeanbisutti merged commit b377517 into quick-perf:master Oct 19, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant