Skip to content

Commit d6861e5

Browse files
authored
Fix to address bulk copy batch insert operation on persisted computed column (#2855)
* Added test scenario to validate bulk copy batch insert for persisted computed column * Clean up unused imports in BatchExecutionWithBulkCopyTest Removed unused logging imports from the test file. * Added fix * fix Updated comment to clarify the validation of inserted rows. * merge main * Update Byte Buddy dependencies to version 1.18.2 * Update Byte Buddy dependencies to version 1.18.2 * Downgrade Byte Buddy dependencies to version 1.17.5 * Downgrade byte-buddy version to 1.17.5
1 parent 74d1072 commit d6861e5

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2092,7 +2092,7 @@ private void validateColumnMappings() throws SQLServerException {
20922092
throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND,
20932093
DriverError.NOT_SET, null);
20942094
}
2095-
} else if (0 > cm.destinationColumnOrdinal || destColumnCount < cm.destinationColumnOrdinal) {
2095+
} else if (0 > cm.destinationColumnOrdinal || !destColumnMetadata.containsKey(cm.destinationColumnOrdinal)) {
20962096
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidColumn"));
20972097
Object[] msgArgs = {cm.destinationColumnOrdinal};
20982098
throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET,

src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithBulkCopyTest.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,70 @@ public void testInsertWithBulkCopyPerformance() throws SQLException {
14011401
System.out.println("Insert for " + recordCount + " records in " + durationMs + " ms.");
14021402
}
14031403

1404+
/**
1405+
* GitHub issue 2847: Persisted computed columns break useBulkCopyForBatchInsert.
1406+
*
1407+
* Verifies that batch inserts using bulk copy work correctly when the target table
1408+
* contains a persisted computed column. The computed column is not included in the
1409+
* INSERT statement, and the bulk copy operation correctly ignores it while
1410+
* inserting the remaining data.
1411+
*
1412+
* @throws Exception
1413+
*/
1414+
@Test
1415+
public void testBulkCopyBatchInsertWithPersistedComputedColumn() throws Exception {
1416+
1417+
String tableName = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("BulkCopyPersistedComputed"));
1418+
String insertSQL = "INSERT INTO " + tableName + " (QtyAvailable, UnitPrice) VALUES (?, ?)";
1419+
1420+
try (Connection connection = PrepUtil.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;");
1421+
SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(insertSQL);
1422+
Statement stmt = connection.createStatement()) {
1423+
1424+
TestUtils.dropTableIfExists(tableName, stmt);
1425+
1426+
// Create table with persisted computed column
1427+
String createTable = "CREATE TABLE " + tableName + " ("
1428+
+ "ProductID int IDENTITY(1,1) NOT NULL, "
1429+
+ "QtyAvailable SMALLINT, "
1430+
+ "InventoryValue AS QtyAvailable * UnitPrice PERSISTED, "
1431+
+ "UnitPrice MONEY)";
1432+
stmt.execute(createTable);
1433+
1434+
// Test batch insert
1435+
pstmt.setInt(1, 10);
1436+
pstmt.setBigDecimal(2, new BigDecimal("15.99"));
1437+
pstmt.addBatch();
1438+
1439+
pstmt.setInt(1, 20);
1440+
pstmt.setBigDecimal(2, new BigDecimal("25.50"));
1441+
pstmt.addBatch();
1442+
1443+
int[] updateCounts = pstmt.executeBatch();
1444+
assertEquals(2, updateCounts.length);
1445+
1446+
// Validate inserted rows, including computed values
1447+
try (ResultSet rs = stmt.executeQuery("SELECT ProductID, QtyAvailable, InventoryValue, UnitPrice FROM "
1448+
+ tableName + " ORDER BY ProductID")) {
1449+
assertTrue(rs.next());
1450+
assertEquals(1, rs.getInt(1));
1451+
assertEquals(10, rs.getInt(2));
1452+
assertEquals(new BigDecimal("159.9000"), rs.getBigDecimal(3));
1453+
assertEquals(new BigDecimal("15.9900"), rs.getBigDecimal(4));
1454+
1455+
assertTrue(rs.next());
1456+
assertEquals(2, rs.getInt(1));
1457+
assertEquals(20, rs.getInt(2));
1458+
assertEquals(new BigDecimal("510.0000"), rs.getBigDecimal(3));
1459+
assertEquals(new BigDecimal("25.5000"), rs.getBigDecimal(4));
1460+
}
1461+
} finally {
1462+
try (Connection connection = getConnection(); Statement stmt = connection.createStatement()) {
1463+
TestUtils.dropTableIfExists(tableName, stmt);
1464+
}
1465+
}
1466+
}
1467+
14041468
private void getCreateTableTemporalSQL(String tableName) throws SQLException {
14051469
try (Statement stmt = connection.createStatement()) {
14061470
TestUtils.dropTableIfExists(AbstractSQLGenerator.escapeIdentifier(tableName), stmt);

0 commit comments

Comments
 (0)