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 @@ -788,20 +788,6 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException {
return false;
}

/**
* Override TDS token processing behavior for PreparedStatement.
* For regular Statement, the execute API for INSERT requires reading an additional explicit
* TDS_DONE token that contains the actual update count returned by the server.
* PreparedStatement does not require this additional token processing, unless
* generated keys were requested (which requires processing additional TDS tokens).
*/
@Override
protected boolean hasUpdateCountTDSTokenForInsertCmd() {
// When generated keys are requested, we need to process additional TDS tokens
// to properly locate the ResultSet containing the generated keys
return bRequestedGeneratedKeys;
}

/**
* Sends the statement parameters by RPC.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1602,7 +1602,7 @@ boolean onDone(TDSReader tdsReader) throws SQLServerException {
return false;

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

/**
* Determines whether to continue processing additional TDS_DONE tokens for INSERT statements.
* For INSERT operations, regular Statement requires reading an additional TDS_DONE token that contains
* the actual update count. This method can be overridden by subclasses to customize
* TDS token processing behavior.
*
* @return true to continue processing more tokens to get the actual update count for INSERT operations
*/
protected boolean hasUpdateCountTDSTokenForInsertCmd() {
// For Insert, we must fetch additional TDS_DONE token that comes with the actual update count
return true;
}

// --------------------------JDBC 2.0-----------------------------

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3405,6 +3405,56 @@ public void testPreparedStatementWithTriggersAndGeneratedKeys() throws SQLExcept
}
}

/**
* Tests PreparedStatement INSERT with multiple values and trigger to validate update count.
* Reproduces the scenario where INSERT INTO TABLE (col) VALUES (?), (?) should return 2 but returns 1.
* This test validates the fix for TDS token processing with triggers that affect update counts.
*
* @throws SQLException
*/
@Test
public void testPreparedStatementInsertMultipleValuesWithTrigger() throws SQLException {
// Create separate test tables to avoid conflicts with existing setup
String testTableA = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("UpdateCountTestTableA"));
String testTableB = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("UpdateCountTestTableB"));
String testTrigger = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("UpdateCountTestTrigger"));

try (Connection conn = getConnection();
Statement stmt = conn.createStatement()) {

TestUtils.dropTriggerIfExists(testTrigger, stmt);
TestUtils.dropTableIfExists(testTableB, stmt);
TestUtils.dropTableIfExists(testTableA, stmt);

stmt.executeUpdate("CREATE TABLE " + testTableA + " (ID int NOT NULL IDENTITY(1,1) PRIMARY KEY, NAME varchar(32))");
stmt.executeUpdate("CREATE TABLE " + testTableB + " (ID int NOT NULL IDENTITY(1,1) PRIMARY KEY)");


stmt.executeUpdate("CREATE TRIGGER " + testTrigger + " ON " + testTableA + " FOR INSERT AS "
+ "INSERT INTO " + testTableB + " DEFAULT VALUES");

// Test case: INSERT with multiple values should return correct update count
String sql = "INSERT INTO " + testTableA + " (NAME) VALUES (?), (?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, "value1");
ps.setString(2, "value2");

boolean hasResultSet = ps.execute();

if (!hasResultSet) {
int updateCount = ps.getUpdateCount();
// This should return 2 (for 2 inserted rows), not 1
assertEquals(2, updateCount, "Update count should be 2 for INSERT with 2 values, but got: " + updateCount);
} else {
fail("Expected update count, but got ResultSet instead");
}
}
TestUtils.dropTriggerIfExists(testTrigger, stmt);
TestUtils.dropTableIfExists(testTableB, stmt);
TestUtils.dropTableIfExists(testTableA, stmt);
}
}

@AfterEach
public void terminate() {
try (Connection con = getConnection(); Statement stmt = con.createStatement()) {
Expand Down