diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java index 4743407b4..b6e789b5c 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java @@ -26,6 +26,7 @@ import java.util.Calendar; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.Vector; import java.util.logging.Level; @@ -2087,6 +2088,7 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL SQLServerResultSet rs = stmt .executeQueryInternal("sp_executesql N'SET FMTONLY ON SELECT * FROM " + Util.escapeSingleQuotes(tableName) + " '")) { + Map columnMappings = null; if (null != columnList && !columnList.isEmpty()) { if (columnList.size() != valueList.size()) { @@ -2095,6 +2097,7 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL Object[] msgArgs = {columnList.size(), valueList.size()}; throw new IllegalArgumentException(form.format(msgArgs)); } + columnMappings = new HashMap<>(columnList.size()); } else { if (rs.getColumnCount() != valueList.size()) { MessageFormat form = new MessageFormat( @@ -2118,8 +2121,17 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL } else { jdbctype = ti.getSSType().getJDBCType().getIntValue(); } - batchRecord.addColumnMetadata(i, c.getColumnName(), jdbctype, ti.getPrecision(), - ti.getScale()); + if (null != columnList && columnList.size() > 0) { + int columnIndex = columnList.indexOf(c.getColumnName()); + if (columnIndex > -1) { + columnMappings.put(columnIndex + 1, i); + batchRecord.addColumnMetadata(columnIndex + 1, c.getColumnName(), jdbctype, + ti.getPrecision(), ti.getScale()); + } + } else { + batchRecord.addColumnMetadata(i, c.getColumnName(), jdbctype, ti.getPrecision(), + ti.getScale()); + } } SQLServerBulkCopy bcOperation = new SQLServerBulkCopy(connection); @@ -2127,6 +2139,11 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL option.setBulkCopyTimeout(queryTimeout); bcOperation.setBulkCopyOptions(option); bcOperation.setDestinationTableName(tableName); + if (columnMappings != null) { + for (Entry pair : columnMappings.entrySet()) { + bcOperation.addColumnMapping(pair.getKey(), pair.getValue()); + } + } bcOperation.setStmtColumnEncriptionSetting(this.getStmtColumnEncriptionSetting()); bcOperation.setDestinationTableMetadata(rs); bcOperation.writeToServer(batchRecord); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithBulkCopyTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithBulkCopyTest.java index 4178c15df..dbccf4e7d 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithBulkCopyTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithBulkCopyTest.java @@ -721,6 +721,45 @@ public void testNonSupportedColumns() throws Exception { } } + @Test + public void testReverseColumnOrder() throws Exception { + String valid = "insert into " + AbstractSQLGenerator.escapeIdentifier(tableName) + " (c2, c1) values " + + "(" + "?, " + "? " + ")"; + + try (Connection connection = PrepUtil.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(valid); + Statement stmt = connection.createStatement()) { + Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); + f1.setAccessible(true); + f1.set(connection, true); + + TestUtils.dropTableIfExists(AbstractSQLGenerator.escapeIdentifier(tableName), stmt); + String createTable = "create table " + AbstractSQLGenerator.escapeIdentifier(tableName) + + " (c1 varchar(1), c2 varchar(3))"; + stmt.execute(createTable); + + pstmt.setString(1, "One"); + pstmt.setString(2, "1"); + pstmt.addBatch(); + + pstmt.executeBatch(); + + try (ResultSet rs = stmt + .executeQuery("select c1, c2 from " + AbstractSQLGenerator.escapeIdentifier(tableName))) { + + Object[] expected = new Object[2]; + + expected[0] = "1"; + expected[1] = "One"; + rs.next(); + + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], rs.getObject(i + 1)); + } + } + } + } + @BeforeAll public static void setupTests() throws Exception { setConnection();