From 442c816c7c5c080668faddbb8f7a4f1f72860d12 Mon Sep 17 00:00:00 2001 From: mobilebilly Date: Sun, 7 Jul 2024 10:18:10 +0800 Subject: [PATCH 1/6] Add order Hints for Bulk Copy operations (#1481) --- .../sqlserver/jdbc/SQLServerBulkCopy.java | 99 ++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java index 199c15306..40f7a6e53 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java @@ -41,6 +41,7 @@ import java.util.Collections; import java.util.GregorianCalendar; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -113,6 +114,22 @@ private class ColumnMapping implements Serializable { } } + private class ColumnOrderHint implements Serializable { + /** + * Always update serialVersionUID when prompted. + */ + private static final long serialVersionUID = 6132627333120344137L; + + String columnName = null; + + SQLServerSortOrder sortOrder; + + ColumnOrderHint(String columnName, SQLServerSortOrder sortOrder) { + this.columnName = columnName; + this.sortOrder = sortOrder; + } + } + /** * Class name for logging. */ @@ -138,6 +155,11 @@ private class ColumnMapping implements Serializable { */ private List columnMappings; + /** + * Column order hints describe the sort order of columns in the clustered index of the destination + */ + private List columnOrderHints; + /** * Flag if SQLServerBulkCopy owns the connection and should close it when Close is called */ @@ -459,6 +481,43 @@ public void clearColumnMappings() { loggerExternal.exiting(loggerClassName, "clearColumnMappings"); } + /** + * Adds a new column mapping, using column names to specify both source and destination columns. + * + * @param columnName + * Column name. + * @param sortOrder + * Column sort order. + * @throws SQLServerException + * If the column order hint is invalid + */ + public void addColumnOrderHint(String columnName, SQLServerSortOrder sortOrder) throws SQLServerException { + if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) { + loggerExternal.entering(loggerClassName, "addColumnOrderHint", + new Object[] {columnName, sortOrder}); + } + + if (null == columnName || columnName.isEmpty()) { + throwInvalidArgument("columnName"); + } else if (null == sortOrder || SQLServerSortOrder.UNSPECIFIED == sortOrder) { + throwInvalidArgument("sortOrder"); + } + columnOrderHints.add(new ColumnOrderHint(columnName, sortOrder)); + + loggerExternal.exiting(loggerClassName, "addColumnOrderHint"); + } + + /** + * Clears the contents of the column order hints + */ + public void clearColumnOrderHints() { + loggerExternal.entering(loggerClassName, "clearColumnOrderHints"); + + columnOrderHints.clear(); + + loggerExternal.exiting(loggerClassName, "clearColumnOrderHints"); + } + /** * Closes the SQLServerBulkCopy instance */ @@ -648,6 +707,7 @@ public void writeToServer(ISQLServerBulkData sourceData) throws SQLServerExcepti */ private void initializeDefaults() { columnMappings = new ArrayList<>(); + columnOrderHints = new ArrayList<>(); destinationTableName = null; serverBulkData = null; sourceResultSet = null; @@ -1482,6 +1542,7 @@ private String getDestTypeFromSrcType(int srcColIndx, int destColIndx, private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerException { StringBuilder bulkCmd = new StringBuilder(); List bulkOptions = new ArrayList<>(); + Set destColumns = new HashSet<>(); String endColumn = " , "; bulkCmd.append("INSERT BULK ").append(destinationTableName).append(" ("); @@ -1490,8 +1551,12 @@ private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerExce endColumn = " ) "; } ColumnMapping colMapping = columnMappings.get(i); - String columnCollation = destColumnMetadata - .get(columnMappings.get(i).destinationColumnOrdinal).collationName; + + BulkColumnMetaData columnMetaData = destColumnMetadata + .get(columnMappings.get(i).destinationColumnOrdinal); + destColumns.add(columnMetaData.columnName); + + String columnCollation = columnMetaData.collationName; String addCollate = ""; String destType = getDestTypeFromSrcType(colMapping.sourceColumnOrdinal, @@ -1536,6 +1601,36 @@ private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerExce bulkOptions.add("ALLOW_ENCRYPTED_VALUE_MODIFICATIONS"); } + if (0 < columnOrderHints.size()) { + StringBuilder orderHintText = new StringBuilder("ORDER("); + + for (ColumnOrderHint columnOrderHint : columnOrderHints) { + String columnName = columnOrderHint.columnName; + + if (!destColumns.contains(columnName)) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_invalidColumn")); + Object[] msgArgs = { columnName }; + throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, + DriverError.NOT_SET, null); + } + + String sortOrderText = columnOrderHint.sortOrder == SQLServerSortOrder.DESCENDING ? "DESC" : "ASC"; + + if (columnName.contains("]")) { + String escapedColumnName = columnName.replaceAll("]", "]]"); + orderHintText.append(escapedColumnName).append(" ").append(sortOrderText).append(", "); + } else { + orderHintText.append(columnName).append(" ").append(sortOrderText).append(", "); + } + } + + orderHintText.setLength(orderHintText.length() - 2); + orderHintText.append(")"); + + bulkOptions.add(orderHintText.toString()); + } + Iterator it = bulkOptions.iterator(); if (it.hasNext()) { bulkCmd.append(" with ("); From 1629062f6b4127946b7dd3572868027ef74b13b1 Mon Sep 17 00:00:00 2001 From: mobilebilly Date: Sun, 7 Jul 2024 10:38:51 +0800 Subject: [PATCH 2/6] Correct the wrong javadoc in SQLServerBulkCopy.addColumnOrderHint --- .../java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java index 40f7a6e53..80cbc7f52 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java @@ -482,7 +482,7 @@ public void clearColumnMappings() { } /** - * Adds a new column mapping, using column names to specify both source and destination columns. + * Adds a new column order hint, specify the column name and sort order * * @param columnName * Column name. From 8da2481f933c9e0a6bca9780cb536fd69c69679d Mon Sep 17 00:00:00 2001 From: mobilebilly Date: Sun, 7 Jul 2024 14:37:47 +0800 Subject: [PATCH 3/6] Escape the column name in the order hints with square bracket correctly --- .../java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java index 80cbc7f52..6eec44435 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java @@ -1619,9 +1619,9 @@ private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerExce if (columnName.contains("]")) { String escapedColumnName = columnName.replaceAll("]", "]]"); - orderHintText.append(escapedColumnName).append(" ").append(sortOrderText).append(", "); + orderHintText.append("[").append(escapedColumnName).append("] ").append(sortOrderText).append(", "); } else { - orderHintText.append(columnName).append(" ").append(sortOrderText).append(", "); + orderHintText.append("[").append(columnName).append("] ").append(sortOrderText).append(", "); } } From e35d099c342775dbc23eac9a5b50bb3bf0af49f0 Mon Sep 17 00:00:00 2001 From: mobilebilly Date: Sun, 7 Jul 2024 14:38:31 +0800 Subject: [PATCH 4/6] Add overload addColumn which accept custom column name --- .../microsoft/sqlserver/testframework/DBTable.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java index 42e25d303..fc8cc214c 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java @@ -435,8 +435,18 @@ String dropTableSql() { * @param sqlType */ public void addColumn(SqlType sqlType) { + this.addColumn(sqlType, RandomUtil.getIdentifier(sqlType.getName())); + } + + /** + * new column to add to DBTable based on the SqlType and column name + * + * @param sqlType + * @param columnName + */ + public void addColumn(SqlType sqlType, String columnName) { schema.addSqlTpe(sqlType); - DBColumn column = new DBColumn(RandomUtil.getIdentifier(sqlType.getName()), sqlType); + DBColumn column = new DBColumn(columnName, sqlType); columns.add(column); ++totalColumns; } From dcead0d12d9cc039684bf0e8facb00f6a304cfb6 Mon Sep 17 00:00:00 2001 From: mobilebilly Date: Sun, 7 Jul 2024 14:39:34 +0800 Subject: [PATCH 5/6] Escape the Close escape character correctly in the escapeIdentifier method --- .../sqlserver/testframework/AbstractSQLGenerator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/com/microsoft/sqlserver/testframework/AbstractSQLGenerator.java b/src/test/java/com/microsoft/sqlserver/testframework/AbstractSQLGenerator.java index 1cff7b37c..acf08434b 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/AbstractSQLGenerator.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/AbstractSQLGenerator.java @@ -66,6 +66,10 @@ public static void setEscapeIdentifier(String openIdentifier, String closeIdenti * @return escaped literal */ public static String escapeIdentifier(String value) { + if(value != null && value.contains(CLOSE_ESCAPE_IDENTIFIER)) { + value = value.replace(CLOSE_ESCAPE_IDENTIFIER, CLOSE_ESCAPE_IDENTIFIER + CLOSE_ESCAPE_IDENTIFIER); + } + return OPEN_ESCAPE_IDENTIFIER + value + CLOSE_ESCAPE_IDENTIFIER; } From e3c765b3ed35301b989aa4ea88f281f9424796a4 Mon Sep 17 00:00:00 2001 From: mobilebilly Date: Sun, 7 Jul 2024 14:41:14 +0800 Subject: [PATCH 6/6] Add unit test cases to the column order hints enhancement --- .../bulkCopy/BulkCopyColumnOrderHintTest.java | 251 ++++++++++++++++++ .../jdbc/bulkCopy/BulkCopyTestUtil.java | 25 ++ .../jdbc/bulkCopy/BulkCopyTestWrapper.java | 31 +++ 3 files changed, 307 insertions(+) create mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnOrderHintTest.java diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnOrderHintTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnOrderHintTest.java new file mode 100644 index 000000000..6901a815b --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnOrderHintTest.java @@ -0,0 +1,251 @@ +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc.bulkCopy; + +import com.microsoft.sqlserver.jdbc.*; +import com.microsoft.sqlserver.testframework.*; +import com.microsoft.sqlserver.testframework.sqlType.SqlVarChar; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; +import java.sql.*; +import static org.junit.jupiter.api.Assertions.fail; + + +/** + * Test BulkCopy Column Order Hints + */ +@RunWith(JUnitPlatform.class) +@DisplayName("BulkCopy Column Order Hints Test") +public class BulkCopyColumnOrderHintTest extends BulkCopyTestSetUp { + private String prcdb = RandomUtil.getIdentifier("BulkCopy_PRC_DB"); + + @Test + @DisplayName("BulkCopy:test no column order hints") + @Tag(Constants.xAzureSQLDW) + public void testNoCOH() throws SQLException { + try (DBConnection con = new DBConnection(connectionString); DBStatement stmt = con.createStatement()) { + DBTable destTable = null; + try { + // create destination table + destTable = sourceTable.cloneSchema(); + stmt.createTable(destTable); + + BulkCopyTestWrapper bulkWrapper = new BulkCopyTestWrapper(connectionString); + bulkWrapper.setUsingConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, ds); + bulkWrapper.setUsingXAConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsXA); + bulkWrapper.setUsingPooledConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsPool); + BulkCopyTestUtil.performBulkCopy(bulkWrapper, sourceTable, destTable); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + TestUtils.dropTableIfExists(destTable.getEscapedTableName(), (Statement) stmt.product()); + } + } + } + + @Test + @DisplayName("BulkCopy:test column order hints") + @Tag(Constants.xAzureSQLDW) + public void testCOH() throws SQLException { + try (DBConnection con = new DBConnection(connectionString); DBStatement stmt = con.createStatement()) { + DBTable destTable = null; + try { + // create destination table + destTable = sourceTable.cloneSchema(); + stmt.createTable(destTable); + + BulkCopyTestWrapper bulkWrapper = new BulkCopyTestWrapper(connectionString); + bulkWrapper.setUsingConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, ds); + bulkWrapper.setUsingXAConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsXA); + bulkWrapper.setUsingPooledConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsPool); + + bulkWrapper.setColumnOrderHint(destTable.getColumnName(0), SQLServerSortOrder.ASCENDING); + + BulkCopyTestUtil.performBulkCopy(bulkWrapper, sourceTable, destTable); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + TestUtils.dropTableIfExists(destTable.getEscapedTableName(), (Statement) stmt.product()); + } + } + } + + @Test + @DisplayName("BulkCopy:test column order hints with multiple columns") + @Tag(Constants.xAzureSQLDW) + public void testMultiColumnsCOH() throws SQLException { + try (DBConnection con = new DBConnection(connectionString); DBStatement stmt = con.createStatement()) { + DBTable destTable = null; + try { + // create destination table + destTable = sourceTable.cloneSchema(); + stmt.createTable(destTable); + + BulkCopyTestWrapper bulkWrapper = new BulkCopyTestWrapper(connectionString); + bulkWrapper.setUsingConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, ds); + bulkWrapper.setUsingXAConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsXA); + bulkWrapper.setUsingPooledConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsPool); + + bulkWrapper.setColumnOrderHint(destTable.getColumnName(0), SQLServerSortOrder.ASCENDING); + bulkWrapper.setColumnOrderHint(destTable.getColumnName(1), SQLServerSortOrder.ASCENDING); + + BulkCopyTestUtil.performBulkCopy(bulkWrapper, sourceTable, destTable); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + TestUtils.dropTableIfExists(destTable.getEscapedTableName(), (Statement) stmt.product()); + } + } + } + + @Test + @DisplayName("BulkCopy:test unicode column name") + public void testUnicodeCOH() throws SQLException { + try (DBConnection con = new DBConnection(connectionString); DBStatement stmt = con.createStatement()) { + DBTable sourceTableUnicode = null; + DBTable destTableUnicode = null; + try { + // create source unicode table + sourceTableUnicode = new DBTable(true, true); + stmt.createTable(sourceTableUnicode); + + // create destination unicode table with same schema as source + destTableUnicode = sourceTableUnicode.cloneSchema(); + stmt.createTable(destTableUnicode); + + BulkCopyTestWrapper bulkWrapper = new BulkCopyTestWrapper(connectionString); + bulkWrapper.setUsingConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, ds); + bulkWrapper.setUsingXAConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsXA); + bulkWrapper.setUsingPooledConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsPool); + + bulkWrapper.setColumnOrderHint(destTableUnicode.getColumnName(1), SQLServerSortOrder.ASCENDING); + + BulkCopyTestUtil.performBulkCopy(bulkWrapper, sourceTableUnicode, destTableUnicode); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + TestUtils.dropTableIfExists(sourceTableUnicode.getEscapedTableName(), (Statement) stmt.product()); + TestUtils.dropTableIfExists(destTableUnicode.getEscapedTableName(), (Statement) stmt.product()); + } + } + } + + @Test + @DisplayName("BulkCopy:test column name with escape character") + public void testCOHWithEscapeChar() throws SQLException { + try (DBConnection con = new DBConnection(connectionString); DBStatement stmt = con.createStatement()) { + DBTable sourceTableEscape = null; + DBTable destTableEscape = null; + try { + // create source unicode table + sourceTableEscape = new DBTable(true); + sourceTableEscape.addColumn(new SqlVarChar(), "COLUMN_NAME]"); + stmt.createTable(sourceTableEscape); + + // create destination unicode table with same schema as source + destTableEscape = sourceTableEscape.cloneSchema(); + stmt.createTable(destTableEscape); + + BulkCopyTestWrapper bulkWrapper = new BulkCopyTestWrapper(connectionString); + bulkWrapper.setUsingConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, ds); + bulkWrapper.setUsingXAConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsXA); + bulkWrapper.setUsingPooledConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsPool); + + bulkWrapper.setColumnOrderHint(destTableEscape.getColumnName(destTableEscape.totalColumns() - 1), SQLServerSortOrder.ASCENDING); + + BulkCopyTestUtil.performBulkCopy(bulkWrapper, sourceTableEscape, destTableEscape); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + TestUtils.dropTableIfExists(sourceTableEscape.getEscapedTableName(), (Statement) stmt.product()); + TestUtils.dropTableIfExists(destTableEscape.getEscapedTableName(), (Statement) stmt.product()); + } + } + } + + @Test + @DisplayName("BulkCopy:test column order hints in descending order") + @Tag(Constants.xAzureSQLDW) + public void testCOHDescOrder() throws SQLException { + try (DBConnection con = new DBConnection(connectionString); DBStatement stmt = con.createStatement()) { + DBTable destTable = null; + try { + // create destination table + destTable = sourceTable.cloneSchema(); + stmt.createTable(destTable); + + BulkCopyTestWrapper bulkWrapper = new BulkCopyTestWrapper(connectionString); + bulkWrapper.setUsingConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, ds); + bulkWrapper.setUsingXAConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsXA); + bulkWrapper.setUsingPooledConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsPool); + + bulkWrapper.setColumnOrderHint(destTable.getColumnName(0), SQLServerSortOrder.DESCENDING); + + BulkCopyTestUtil.performBulkCopy(bulkWrapper, sourceTable, destTable); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + TestUtils.dropTableIfExists(destTable.getEscapedTableName(), (Statement) stmt.product()); + } + } + } + + + + @Test + @DisplayName("BulkCopy:test colmun order hints with unspecified sort order") + public void testInvalidCOHWithUnspecifiedSortOrder() throws SQLException { + try (DBConnection con = new DBConnection(connectionString); DBStatement stmt = con.createStatement()) { + DBTable destTable = null; + try { + // create destination table + destTable = sourceTable.cloneSchema(); + stmt.createTable(destTable); + + BulkCopyTestWrapper bulkWrapper = new BulkCopyTestWrapper(connectionString); + bulkWrapper.setUsingConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, ds); + bulkWrapper.setUsingXAConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsXA); + bulkWrapper.setUsingPooledConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsPool); + + bulkWrapper.setColumnOrderHint(destTable.getColumnName(0), SQLServerSortOrder.UNSPECIFIED); + + BulkCopyTestUtil.performBulkCopy(bulkWrapper, sourceTable, destTable, true, true); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + TestUtils.dropTableIfExists(destTable.getEscapedTableName(), (Statement) stmt.product()); + } + } + } + + @Test + @DisplayName("BulkCopy:test colmun order hints with invalid column name") + public void testInvalidCOHWithInvalidColumnName() throws SQLException { + try (DBConnection con = new DBConnection(connectionString); DBStatement stmt = con.createStatement()) { + DBTable destTable = null; + try { + // create destination table + destTable = sourceTable.cloneSchema(); + stmt.createTable(destTable); + + BulkCopyTestWrapper bulkWrapper = new BulkCopyTestWrapper(connectionString); + bulkWrapper.setUsingConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, ds); + bulkWrapper.setUsingXAConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsXA); + bulkWrapper.setUsingPooledConnection((0 == Constants.RANDOM.nextInt(2)) ? true : false, dsPool); + + bulkWrapper.setColumnOrderHint("INVALID_COLUMN_NAME", SQLServerSortOrder.ASCENDING); + + BulkCopyTestUtil.performBulkCopy(bulkWrapper, sourceTable, destTable, true, true); + } catch (Exception e) { + fail(e.getMessage()); + } finally { + TestUtils.dropTableIfExists(destTable.getEscapedTableName(), (Statement) stmt.product()); + } + } + } +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java index 57c8bdf50..243dbc5b6 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java @@ -87,6 +87,12 @@ static void performBulkCopy(BulkCopyTestWrapper wrapper, DBTable sourceTable, bo } } } + if(wrapper.isUsingColumnOrderHints()) { + for (int i = 0; i < wrapper.coh.size(); i++) { + BulkCopyTestWrapper.ColumnOrderHint columnOrderHint = wrapper.coh.get(i); + bulkCopy.addColumnOrderHint(columnOrderHint.columnName, columnOrderHint.sortOrder); + } + } bulkCopy.writeToServer((ResultSet) srcResultSet.product()); if (validateResult) { validateValues(con, sourceTable, destinationTable); @@ -138,6 +144,13 @@ static void performBulkCopy(BulkCopyTestWrapper wrapper, DBTable sourceTable, DB } } } + if(wrapper.isUsingColumnOrderHints()) { + for (int i = 0; i < wrapper.coh.size(); i++) { + BulkCopyTestWrapper.ColumnOrderHint columnOrderHint = wrapper.coh.get(i); + bulkCopy.addColumnOrderHint(columnOrderHint.columnName, columnOrderHint.sortOrder); + } + } + bulkCopy.writeToServer((ResultSet) srcResultSet.product()); if (validateResult) { validateValues(con, sourceTable, destinationTable); @@ -184,6 +197,12 @@ static void performBulkCopy(BulkCopyTestWrapper wrapper, DBTable sourceTable, DB } } } + if(wrapper.isUsingColumnOrderHints()) { + for (int i = 0; i < wrapper.coh.size(); i++) { + BulkCopyTestWrapper.ColumnOrderHint columnOrderHint = wrapper.coh.get(i); + bulkCopy.addColumnOrderHint(columnOrderHint.columnName, columnOrderHint.sortOrder); + } + } bulkCopy.writeToServer((ResultSet) srcResultSet.product()); if (fail) fail(TestResource.getResource("R_expectedExceptionNotThrown")); @@ -244,6 +263,12 @@ static void performBulkCopy(BulkCopyTestWrapper wrapper, DBTable sourceTable, DB } } } + if(wrapper.isUsingColumnOrderHints()) { + for (int i = 0; i < wrapper.coh.size(); i++) { + BulkCopyTestWrapper.ColumnOrderHint columnOrderHint = wrapper.coh.get(i); + bulkCopy.addColumnOrderHint(columnOrderHint.columnName, columnOrderHint.sortOrder); + } + } bulkCopy.writeToServer((ResultSet) srcResultSet.product()); if (fail) fail(TestResource.getResource("R_expectedExceptionNotThrown")); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestWrapper.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestWrapper.java index 62b51e5a7..5db217db3 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestWrapper.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestWrapper.java @@ -8,6 +8,7 @@ import com.microsoft.sqlserver.jdbc.ISQLServerDataSource; import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions; +import com.microsoft.sqlserver.jdbc.SQLServerSortOrder; /** @@ -44,8 +45,15 @@ class BulkCopyTestWrapper { */ private boolean isUsingColumnMapping = false; + /** + * true if SQLServerBulkCopy should use column order hints + */ + private boolean isUsingColumnOrderHints = false; + public LinkedList cm = new LinkedList<>(); + public LinkedList coh = new LinkedList<>(); + private SQLServerBulkCopyOptions bulkOptions; private String connectionString; @@ -167,10 +175,18 @@ public void setUsingColumnMapping() { this.isUsingColumnMapping = true; } + public void setUsingColumnOrderHints() { + this.isUsingColumnOrderHints = true; + } + public boolean isUsingColumnMapping() { return isUsingColumnMapping; } + public boolean isUsingColumnOrderHints() { + return isUsingColumnOrderHints; + } + public void setColumnMapping(int sourceColOrdinal, int destColOrdinal) { setUsingColumnMapping(); cm.add(new ColumnMap(sourceColOrdinal, destColOrdinal)); @@ -191,6 +207,11 @@ public void setColumnMapping(String sourceColName, int destColOrdinal) { cm.add(new ColumnMap(sourceColName, destColOrdinal)); } + public void setColumnOrderHint(String columnName, SQLServerSortOrder sortOrder) { + setUsingColumnOrderHints(); + coh.add(new ColumnOrderHint(columnName, sortOrder)); + } + class ColumnMap { boolean sourceIsInt = false; boolean destIsInt = false; @@ -232,4 +253,14 @@ class ColumnMap { this.destString = dest; } } + + class ColumnOrderHint { + String columnName; + + SQLServerSortOrder sortOrder; + ColumnOrderHint(String columnName, SQLServerSortOrder sortOrder) { + this.columnName = columnName; + this.sortOrder = sortOrder; + } + } }