Skip to content

Add order Hints for Bulk Copy operations #2701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
442c816
Add order Hints for Bulk Copy operations (#1481)
mobilebilly Jul 7, 2024
1629062
Correct the wrong javadoc in SQLServerBulkCopy.addColumnOrderHint
mobilebilly Jul 7, 2024
8da2481
Escape the column name in the order hints with square bracket correctly
mobilebilly Jul 7, 2024
e35d099
Add overload addColumn which accept custom column name
mobilebilly Jul 7, 2024
dcead0d
Escape the Close escape character correctly in the escapeIdentifier m…
mobilebilly Jul 7, 2024
e3c765b
Add unit test cases to the column order hints enhancement
mobilebilly Jul 7, 2024
31b5d00
Merge branch 'microsoft:main' into main
mobilebilly Jul 10, 2024
e6a3005
Merge branch 'microsoft:main' into main
mobilebilly Aug 2, 2024
9b195c2
Merge branch 'microsoft:main' into main
mobilebilly Aug 24, 2024
f8827a2
Merge branch 'microsoft:main' into main
mobilebilly Aug 29, 2024
c4777de
Merge branch 'microsoft:main' into main
mobilebilly Sep 11, 2024
86e8f98
Merge branch 'microsoft:main' into main
mobilebilly Sep 24, 2024
971c2ec
Merge branch 'microsoft:main' into main
mobilebilly Sep 30, 2024
433da04
Merge branch 'microsoft:main' into main
mobilebilly Nov 9, 2024
761060b
Merge branch 'microsoft:main' into main
mobilebilly Nov 16, 2024
c071e5f
Merge branch 'microsoft:main' into main
mobilebilly Dec 10, 2024
a3cb495
Merge branch 'microsoft:main' into main
mobilebilly Jan 5, 2025
13c683e
Merge branch 'microsoft:main' into main
mobilebilly Jan 18, 2025
fab83aa
Merge branch 'microsoft:main' into main
mobilebilly Feb 3, 2025
87a0bd5
Merge branch 'microsoft:main' into main
mobilebilly Feb 19, 2025
ad6b8a4
Merge branch 'microsoft:main' into main
mobilebilly Feb 23, 2025
c8e872a
Merge branch 'microsoft:main' into main
mobilebilly Mar 4, 2025
02d7758
Merge branch 'microsoft:main' into main
mobilebilly Mar 8, 2025
39cc70e
Merge branch 'microsoft:main' into main
mobilebilly Mar 26, 2025
0c3fe65
Merge branch 'microsoft:main' into main
mobilebilly Apr 3, 2025
45d9060
Merge branch 'microsoft:main' into main
mobilebilly Apr 28, 2025
45daa81
Merge branch 'microsoft:main' into main
mobilebilly May 18, 2025
bf03f21
Merge branch 'microsoft:main' into main
mobilebilly May 31, 2025
11fd746
Merge branch 'microsoft:main' into main
mobilebilly Jun 9, 2025
8bede18
Merge branch 'microsoft:main' into main
mobilebilly Jul 1, 2025
c6508ee
Merge branch 'microsoft:main' into main
mobilebilly Jul 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 97 additions & 2 deletions src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,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;
Expand Down Expand Up @@ -111,6 +112,22 @@
}
}

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.
*/
Expand All @@ -136,6 +153,11 @@
*/
private List<ColumnMapping> columnMappings;

/**
* Column order hints describe the sort order of columns in the clustered index of the destination
*/
private List<ColumnOrderHint> columnOrderHints;

/**
* Flag if SQLServerBulkCopy owns the connection and should close it when Close is called
*/
Expand Down Expand Up @@ -457,6 +479,43 @@
loggerExternal.exiting(loggerClassName, "clearColumnMappings");
}

/**
* Adds a new column order hint, specify the column name and sort order
*
* @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");

Check warning on line 499 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L499 was not covered by tests
} else if (null == sortOrder || SQLServerSortOrder.UNSPECIFIED == sortOrder) {
throwInvalidArgument("sortOrder");

Check warning on line 501 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L501 was not covered by tests
}
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");

Check warning on line 512 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L512 was not covered by tests

columnOrderHints.clear();

Check warning on line 514 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L514 was not covered by tests

loggerExternal.exiting(loggerClassName, "clearColumnOrderHints");
}

Check warning on line 517 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java#L516-L517

Added lines #L516 - L517 were not covered by tests

/**
* Closes the SQLServerBulkCopy instance
*/
Expand Down Expand Up @@ -646,6 +705,7 @@
*/
private void initializeDefaults() {
columnMappings = new ArrayList<>();
columnOrderHints = new ArrayList<>();
destinationTableName = null;
serverBulkData = null;
sourceResultSet = null;
Expand Down Expand Up @@ -1493,6 +1553,7 @@
private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerException {
StringBuilder bulkCmd = new StringBuilder();
List<String> bulkOptions = new ArrayList<>();
Set<String> destColumns = new HashSet<>();
String endColumn = " , ";
bulkCmd.append("INSERT BULK ").append(destinationTableName).append(" (");

Expand All @@ -1501,8 +1562,12 @@
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,
Expand Down Expand Up @@ -1547,6 +1612,36 @@
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("[").append(escapedColumnName).append("] ").append(sortOrderText).append(", ");
} else {
orderHintText.append("[").append(columnName).append("] ").append(sortOrderText).append(", ");
}
}

orderHintText.setLength(orderHintText.length() - 2);
orderHintText.append(")");

bulkOptions.add(orderHintText.toString());
}

Iterator<String> it = bulkOptions.iterator();
if (it.hasNext()) {
bulkCmd.append(" with (");
Expand Down
Loading