Skip to content

Commit a3178ba

Browse files
authored
Fix to ignore computed columns during BulkCopy (#1562)
1 parent 3447893 commit a3178ba

File tree

3 files changed

+55
-16
lines changed

3 files changed

+55
-16
lines changed

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

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,40 +1729,36 @@ private void getDestinationMetadata() throws SQLServerException {
17291729
if (null != destinationTableMetadata) {
17301730
rs = (SQLServerResultSet) destinationTableMetadata;
17311731
} else {
1732-
stmt = (SQLServerStatement) connection.createStatement(ResultSet.TYPE_FORWARD_ONLY,
1733-
ResultSet.CONCUR_READ_ONLY, connection.getHoldability(), stmtColumnEncriptionSetting);
1732+
stmt = (SQLServerStatement) connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connection.getHoldability(), stmtColumnEncriptionSetting);
17341733

17351734
// Get destination metadata
1736-
rs = stmt.executeQueryInternal(
1737-
"sp_executesql N'SET FMTONLY ON SELECT * FROM " + escapedDestinationTableName + " '");
1735+
rs = stmt.executeQueryInternal("sp_executesql N'SET FMTONLY ON SELECT * FROM " + escapedDestinationTableName + " '");
17381736
}
17391737

1740-
destColumnCount = rs.getMetaData().getColumnCount();
1738+
int destColumnMetadataCount = rs.getMetaData().getColumnCount();
17411739
destColumnMetadata = new HashMap<>();
17421740
destCekTable = rs.getCekTable();
17431741

1744-
if (!connection.getServerSupportsColumnEncryption()) {
1745-
metaDataQuery = "select collation_name from sys.columns where " + "object_id=OBJECT_ID('"
1746-
+ escapedDestinationTableName + "') " + "order by column_id ASC";
1747-
} else {
1748-
metaDataQuery = "select collation_name, encryption_type from sys.columns where "
1749-
+ "object_id=OBJECT_ID('" + escapedDestinationTableName + "') " + "order by column_id ASC";
1750-
}
1742+
metaDataQuery = "select * from sys.columns where " + "object_id=OBJECT_ID('" + escapedDestinationTableName + "') " + "order by column_id ASC";
17511743

17521744
try (SQLServerStatement statementMoreMetadata = (SQLServerStatement) connection.createStatement();
1753-
SQLServerResultSet rsMoreMetaData = statementMoreMetadata.executeQueryInternal(metaDataQuery)) {
1754-
for (int i = 1; i <= destColumnCount; ++i) {
1745+
SQLServerResultSet rsMoreMetaData = statementMoreMetadata.executeQueryInternal(metaDataQuery)) {
1746+
for (int i = 1; i <= destColumnMetadataCount; ++i) {
17551747
if (rsMoreMetaData.next()) {
17561748
String bulkCopyEncryptionType = null;
17571749
if (connection.getServerSupportsColumnEncryption()) {
17581750
bulkCopyEncryptionType = rsMoreMetaData.getString("encryption_type");
17591751
}
1760-
destColumnMetadata.put(i, new BulkColumnMetaData(rs.getColumn(i),
1761-
rsMoreMetaData.getString("collation_name"), bulkCopyEncryptionType));
1752+
// Skip computed columns
1753+
if (!rsMoreMetaData.getBoolean("is_computed")) {
1754+
destColumnMetadata.put(i, new BulkColumnMetaData(rs.getColumn(i), rsMoreMetaData.getString("collation_name"),
1755+
bulkCopyEncryptionType));
1756+
}
17621757
} else {
17631758
destColumnMetadata.put(i, new BulkColumnMetaData(rs.getColumn(i)));
17641759
}
17651760
}
1761+
destColumnCount = destColumnMetadata.size();
17661762
}
17671763
} catch (SQLException e) {
17681764
// Unable to retrieve metadata for destination

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2142,6 +2142,9 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL
21422142
CryptoMetadata cryptoMetadata = c.getCryptoMetadata();
21432143
int jdbctype;
21442144
TypeInfo ti = c.getTypeInfo();
2145+
if (ti.getUpdatability() == 0) { // Skip read only columns
2146+
continue;
2147+
}
21452148
checkValidColumns(ti);
21462149
if (null != cryptoMetadata) {
21472150
jdbctype = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType().getIntValue();

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public class BatchExecutionWithBulkCopyTest extends AbstractTest {
5959
static String squareBracketTableName = RandomUtil.getIdentifier("BulkCopy]]]]test'");
6060
static String doubleQuoteTableName = RandomUtil.getIdentifier("\"BulkCopy\"\"\"\"test\"");
6161
static String schemaTableName = "\"dbo\" . /*some comment */ " + squareBracketTableName;
62+
static String tableNameBulkComputedCols = RandomUtil.getIdentifier("BulkCopyComputedCols");
6263

6364
private Object[] generateExpectedValues() {
6465
float randomFloat = RandomData.generateReal(false);
@@ -760,6 +761,45 @@ public void testReverseColumnOrder() throws Exception {
760761
}
761762
}
762763

764+
@Test
765+
@Tag(Constants.xAzureSQLDW)
766+
@Tag(Constants.xSQLv12)
767+
public void testComputedCols() throws Exception {
768+
String valid = "insert into " + AbstractSQLGenerator.escapeIdentifier(tableNameBulkComputedCols) + " (id, json)"
769+
+ " values (?, ?)";
770+
771+
try (Connection connection = PrepUtil.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;");
772+
SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(valid);
773+
Statement stmt = (SQLServerStatement) connection.createStatement();) {
774+
Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW");
775+
f1.setAccessible(true);
776+
f1.set(connection, true);
777+
778+
TestUtils.dropTableIfExists(AbstractSQLGenerator.escapeIdentifier(tableNameBulkComputedCols), stmt);
779+
String createTable = "create table " + AbstractSQLGenerator.escapeIdentifier(tableNameBulkComputedCols)
780+
+ " (id nvarchar(100) not null, json nvarchar(max) not null,"
781+
+ " vcol1 as json_value([json], '$.vcol1'), vcol2 as json_value([json], '$.vcol2'))";
782+
stmt.execute(createTable);
783+
784+
String jsonValue =
785+
"{\"vcol1\":\"" + UUID.randomUUID().toString() + "\",\"vcol2\":\"" + UUID.randomUUID().toString()
786+
+ "\" }";
787+
String idValue = UUID.randomUUID().toString();
788+
pstmt.setString(1, idValue);
789+
pstmt.setString(2, jsonValue);
790+
pstmt.addBatch();
791+
pstmt.executeBatch();
792+
793+
try (ResultSet rs = stmt.executeQuery(
794+
"select * from " + AbstractSQLGenerator.escapeIdentifier(tableNameBulkComputedCols))) {
795+
rs.next();
796+
797+
assertEquals(idValue, rs.getObject(1));
798+
assertEquals(jsonValue, rs.getObject(2));
799+
}
800+
}
801+
}
802+
763803
@BeforeAll
764804
public static void setupTests() throws Exception {
765805
setConnection();

0 commit comments

Comments
 (0)