@@ -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