Skip to content

Commit ed649c4

Browse files
authored
Add test case for PreparedStatement INSERT multiple values update count issue. (#2817)
1 parent 70e07cf commit ed649c4

File tree

3 files changed

+51
-28
lines changed

3 files changed

+51
-28
lines changed

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -788,20 +788,6 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException {
788788
return false;
789789
}
790790

791-
/**
792-
* Override TDS token processing behavior for PreparedStatement.
793-
* For regular Statement, the execute API for INSERT requires reading an additional explicit
794-
* TDS_DONE token that contains the actual update count returned by the server.
795-
* PreparedStatement does not require this additional token processing, unless
796-
* generated keys were requested (which requires processing additional TDS tokens).
797-
*/
798-
@Override
799-
protected boolean hasUpdateCountTDSTokenForInsertCmd() {
800-
// When generated keys are requested, we need to process additional TDS tokens
801-
// to properly locate the ResultSet containing the generated keys
802-
return bRequestedGeneratedKeys;
803-
}
804-
805791
/**
806792
* Sends the statement parameters by RPC.
807793
*/

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,7 +1602,7 @@ boolean onDone(TDSReader tdsReader) throws SQLServerException {
16021602
return false;
16031603

16041604
// For Insert operations, check if additional TDS_DONE token processing is required.
1605-
if (hasUpdateCountTDSTokenForInsertCmd() && (StreamDone.CMD_INSERT == doneToken.getCurCmd()) && (-1 != doneToken.getUpdateCount())
1605+
if ((StreamDone.CMD_INSERT == doneToken.getCurCmd()) && (-1 != doneToken.getUpdateCount())
16061606
&& EXECUTE == executeMethod) {
16071607
return true;
16081608
}
@@ -1845,19 +1845,6 @@ boolean consumeExecOutParam(TDSReader tdsReader) throws SQLServerException {
18451845
return false;
18461846
}
18471847

1848-
/**
1849-
* Determines whether to continue processing additional TDS_DONE tokens for INSERT statements.
1850-
* For INSERT operations, regular Statement requires reading an additional TDS_DONE token that contains
1851-
* the actual update count. This method can be overridden by subclasses to customize
1852-
* TDS token processing behavior.
1853-
*
1854-
* @return true to continue processing more tokens to get the actual update count for INSERT operations
1855-
*/
1856-
protected boolean hasUpdateCountTDSTokenForInsertCmd() {
1857-
// For Insert, we must fetch additional TDS_DONE token that comes with the actual update count
1858-
return true;
1859-
}
1860-
18611848
// --------------------------JDBC 2.0-----------------------------
18621849

18631850
@Override

src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3405,6 +3405,56 @@ public void testPreparedStatementWithTriggersAndGeneratedKeys() throws SQLExcept
34053405
}
34063406
}
34073407

3408+
/**
3409+
* Tests PreparedStatement INSERT with multiple values and trigger to validate update count.
3410+
* Reproduces the scenario where INSERT INTO TABLE (col) VALUES (?), (?) should return 2 but returns 1.
3411+
* This test validates the fix for TDS token processing with triggers that affect update counts.
3412+
*
3413+
* @throws SQLException
3414+
*/
3415+
@Test
3416+
public void testPreparedStatementInsertMultipleValuesWithTrigger() throws SQLException {
3417+
// Create separate test tables to avoid conflicts with existing setup
3418+
String testTableA = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("UpdateCountTestTableA"));
3419+
String testTableB = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("UpdateCountTestTableB"));
3420+
String testTrigger = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("UpdateCountTestTrigger"));
3421+
3422+
try (Connection conn = getConnection();
3423+
Statement stmt = conn.createStatement()) {
3424+
3425+
TestUtils.dropTriggerIfExists(testTrigger, stmt);
3426+
TestUtils.dropTableIfExists(testTableB, stmt);
3427+
TestUtils.dropTableIfExists(testTableA, stmt);
3428+
3429+
stmt.executeUpdate("CREATE TABLE " + testTableA + " (ID int NOT NULL IDENTITY(1,1) PRIMARY KEY, NAME varchar(32))");
3430+
stmt.executeUpdate("CREATE TABLE " + testTableB + " (ID int NOT NULL IDENTITY(1,1) PRIMARY KEY)");
3431+
3432+
3433+
stmt.executeUpdate("CREATE TRIGGER " + testTrigger + " ON " + testTableA + " FOR INSERT AS "
3434+
+ "INSERT INTO " + testTableB + " DEFAULT VALUES");
3435+
3436+
// Test case: INSERT with multiple values should return correct update count
3437+
String sql = "INSERT INTO " + testTableA + " (NAME) VALUES (?), (?)";
3438+
try (PreparedStatement ps = conn.prepareStatement(sql)) {
3439+
ps.setString(1, "value1");
3440+
ps.setString(2, "value2");
3441+
3442+
boolean hasResultSet = ps.execute();
3443+
3444+
if (!hasResultSet) {
3445+
int updateCount = ps.getUpdateCount();
3446+
// This should return 2 (for 2 inserted rows), not 1
3447+
assertEquals(2, updateCount, "Update count should be 2 for INSERT with 2 values, but got: " + updateCount);
3448+
} else {
3449+
fail("Expected update count, but got ResultSet instead");
3450+
}
3451+
}
3452+
TestUtils.dropTriggerIfExists(testTrigger, stmt);
3453+
TestUtils.dropTableIfExists(testTableB, stmt);
3454+
TestUtils.dropTableIfExists(testTableA, stmt);
3455+
}
3456+
}
3457+
34083458
@AfterEach
34093459
public void terminate() {
34103460
try (Connection con = getConnection(); Statement stmt = con.createStatement()) {

0 commit comments

Comments
 (0)