Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.sql.SQLException;
import java.sql.SQLTimeoutException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -165,7 +166,15 @@ public ExecuteBatchResult executeBatch(
}

// 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]);
}

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;
}
Comment on lines +169 to +176

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.

}
return new ExecuteBatchResult(updatedCounts);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,9 @@ public void testUpdateQueryWithBatchedParameters() throws SQLException {
stmt.setArray(2, connection.createArrayOf("INTEGER", new Integer[] {0, -1, 100000}));
stmt.addBatch();
int[] updated = stmt.executeBatch();
assertEquals(42, updated[0]);
assertEquals(2, updated.length);
assertEquals(21, updated[0]);
assertEquals(21, updated[1]);
}
}
}
Loading