@@ -3455,6 +3455,129 @@ public void testPreparedStatementInsertMultipleValuesWithTrigger() throws SQLExc
34553455 }
34563456 }
34573457
3458+ /**
3459+ * Tests execute a mixed SQL batch (INSERT → INSERT error → INSERT → SELECT) using
3460+ * {@link Statement#execute(String)} and verifies correct result traversal after
3461+ * a primary key violation.
3462+ *
3463+ * After catching the expected error, the test calls {@link Statement#getMoreResults()}
3464+ * to continue processing the batch and validates that the update count of the
3465+ * subsequent successful INSERT is not swallowed before reaching the SELECT.
3466+ *
3467+ * Validates that update counts are reported correctly even after an error occurs in the batch.
3468+ * Github issue #2850 : Statement.execute() skips valid update count after catching SQLException in mixed batch execution
3469+ *
3470+ * @throws SQLException
3471+ */
3472+ @ Test
3473+ public void testBatchUpdateCount () throws SQLException {
3474+ // Create separate test tables to avoid conflicts with existing setup
3475+ String testTable = AbstractSQLGenerator .escapeIdentifier (RandomUtil .getIdentifier ("UpdateCountTestTable" ));
3476+
3477+ try (Connection conn = getConnection ();
3478+ Statement stmt = conn .createStatement ()) {
3479+
3480+ TestUtils .dropTableIfExists (testTable , stmt );
3481+
3482+ // Create table
3483+ String createTableSql = String .format ("""
3484+ CREATE TABLE %s (
3485+ id int primary key, column_name varchar(100))
3486+ """ , testTable );
3487+
3488+ stmt .execute (createTableSql );
3489+
3490+ // SQL Batch breakdown:
3491+ // 1. INSERT (Success)
3492+ // 2. INSERT (Failure - Primary Key Conflict Error 2627)
3493+ // 3. INSERT (Success - BUT this update count gets swallowed by the driver bug)
3494+ // 4. SELECT (Result Set)
3495+
3496+ String sqlBatch =
3497+ "insert into " + testTable + " values (1, 'test'); " +
3498+ "insert into " + testTable + " values (1, 'test'); " +
3499+ "insert into " + testTable + " values (2, 'test'); " +
3500+ "select * from " + testTable + ";" ;
3501+
3502+ boolean hasResult = stmt .execute (sqlBatch );
3503+ int resultCount = 0 ;
3504+ List <Integer > updateCounts = new ArrayList <>();
3505+ int resultSetCount = 0 ;
3506+ boolean exceptionCaught = false ;
3507+
3508+ while (true ) {
3509+ resultCount ++;
3510+ try {
3511+ // Standard JDBC processing logic
3512+ if (hasResult ) {
3513+ try (ResultSet rs = stmt .getResultSet ()) {
3514+ resultSetCount ++;;
3515+ int rowCount = 0 ;
3516+ while (rs .next ()) {
3517+ rowCount ++;
3518+ }
3519+ // Verify we get the expected 2 rows in the final SELECT
3520+ if (resultSetCount == 1 ) {
3521+ assertEquals (2 , rowCount , "Final SELECT should return 2 rows" );
3522+ }
3523+ }
3524+ } else {
3525+ int updateCount = stmt .getUpdateCount ();
3526+ if (updateCount == -1 ) {
3527+ break ; // Exit loop - no more results
3528+ }
3529+ updateCounts .add (updateCount );
3530+ }
3531+
3532+ // Attempt to get the next result
3533+ hasResult = stmt .getMoreResults ();
3534+
3535+ } catch (SQLException e ) {
3536+ exceptionCaught = true ;
3537+ assertEquals (2627 , e .getErrorCode (), "Expected primary key violation error" );
3538+ assertTrue (e .getMessage ().contains ("PRIMARY KEY constraint" ),
3539+ "Expected primary key constraint violation message" );
3540+
3541+ // ================= Core Recovery Logic =================
3542+ // The driver throws an exception for the 2nd SQL (Duplicate Key).
3543+ // We catch it and try to move to the next result (3rd SQL).
3544+ try {
3545+ // Force move pointer to continue processing the batch
3546+ hasResult = stmt .getMoreResults ();
3547+ } catch (Exception ex ) {
3548+ fail ("Failed to recover from batch exception: " + ex .getMessage ());
3549+ }
3550+ // =======================================================
3551+ }
3552+ }
3553+
3554+ // Verify test results
3555+ assertTrue (exceptionCaught , "Expected exception for duplicate key was not caught" );
3556+ assertEquals (1 , resultSetCount , "Should have processed exactly 1 ResultSet" );
3557+
3558+ // This is the key assertion that will fail with the current bug:
3559+ // We should get 2 update counts (first INSERT and third INSERT)
3560+ // But due to the bug, we only get 1 update count (the first INSERT)
3561+ // The third INSERT's update count gets swallowed by the driver
3562+ assertEquals (2 , updateCounts .size (),
3563+ "Should have 2 update counts (1st INSERT success + 3rd INSERT success), " +
3564+ "but driver bug causes 3rd INSERT update count to be swallowed" );
3565+
3566+ // Verify the update counts are correct
3567+ assertEquals (Integer .valueOf (1 ), updateCounts .get (0 ), "First INSERT should affect 1 row" );
3568+ assertEquals (Integer .valueOf (1 ), updateCounts .get (1 ), "Third INSERT should affect 1 row" );
3569+
3570+ // Verify final table state
3571+ try (ResultSet rs = stmt .executeQuery ("SELECT COUNT(*) FROM " + testTable )) {
3572+ assertTrue (rs .next ());
3573+ assertEquals (2 , rs .getInt (1 ), "Table should contain exactly 2 rows" );
3574+ }
3575+
3576+ TestUtils .dropTableIfExists (testTable , stmt );
3577+
3578+ }
3579+ }
3580+
34583581 @ AfterEach
34593582 public void terminate () {
34603583 try (Connection con = getConnection (); Statement stmt = con .createStatement ()) {
0 commit comments