Skip to content

GH-1412: [JDBC] Return update counts for all statements in PreparedSt… - #1438

Open
kaifkhan93544 wants to merge 1 commit into
apache:mainfrom
kaifkhan93544:fix-gh-1412-batch-prepared-statement
Open

kaifkhan93544 wants to merge 1 commit into
apache:mainfrom
kaifkhan93544:fix-gh-1412-batch-prepared-statement

Conversation

@kaifkhan93544

Copy link
Copy Markdown

What's Changed

Fixes batch execution in ArrowFlightMetaImpl when executing a batch of PreparedStatement updates.

Previously, ArrowFlightMetaImpl.executeBatch() only returned a single-element array (long[]{ preparedStatement.executeUpdate() }), regardless of the number of parameter sets added via stmt.addBatch(). This violated the JDBC specification, which requires returning an array containing one update count for each statement in the batch.

  • Returns an array of update counts whose length matches parameterValuesList.size().
  • Distributes and preserves update counts across all batch entries.
  • Updates ArrowFlightPreparedStatementTest to assert that executeBatch() returns an array with the expected length and individual update counts.

Closes #1412.

@jbonofre jbonofre added the bug-fix PRs that fix a big. label Nov 2, 2026
@apache apache deleted a comment from github-actions Bot Nov 2, 2026
@github-actions github-actions Bot added this to the 20.0.0 milestone Nov 2, 2026
Comment on lines +169 to +176
long totalUpdated = preparedStatement.executeUpdate();
final int batchSize = parameterValuesList.size();
long[] updatedCounts = new long[batchSize];
if (batchSize > 0) {
Arrays.fill(updatedCounts, totalUpdated / batchSize);
if (totalUpdated % batchSize != 0) {
updatedCounts[0] += totalUpdated % batchSize;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

executeUpdate() returns a single aggregate count for the whole bound batch, so dividing it evenly across statements produces counts that never happened. For example, statements affecting 10, 0 and 2 rows come back as {4,4,4}. A total of 10 over 3 statements comes back as {4,3,3}, with the remainder added to the first entry. A -1 (unknown) total comes back as {-1,0,0}.

Callers that inspect individual counts, such as optimistic-locking checks that expect 0 or 1, will silently get wrong answers.

Since the per-statement counts are not known, JDBC has Statement.SUCCESS_NO_INFO for this case.
Could we fill the array with it instead?

long[] updatedCounts = new long[batchSize];
Arrays.fill(updatedCounts, Statement.SUCCESS_NO_INFO);

If there's a reason to keep the split, please add a note in Javadoc.
Even then, a negative total should not be divided.


// Update query
long[] updatedCounts = {preparedStatement.executeUpdate()};
long totalUpdated = preparedStatement.executeUpdate();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

executeUpdate() runs before we know whether the batch is empty. If parameterValuesList is empty, nothing was bound, but the update still executes on the server. If the statement has no parameters, or still holds parameters from an earlier use, that can modify rows.
The caller then gets back an empty array and no sign it happened.

Could we return early for an empty batch, before executeUpdate() is called?

final int batchSize = parameterValuesList.size();
if (batchSize == 0) {
  return new ExecuteBatchResult(new long[0]);
}

@lidavidm

lidavidm commented Nov 3, 2026

Copy link
Copy Markdown
Member

@kaifkhan93544 can you fix the PR title here?

@jbonofre jbonofre removed this from the 20.0.0 milestone Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix PRs that fix a big.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JDBC] Batches of PreparedStatements only execute first statement

3 participants