Skip to content
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

Add order Hints for Bulk Copy operations #2472

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -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;
Expand Down Expand Up @@ -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.
*/
Expand All @@ -138,6 +155,11 @@ private class ColumnMapping implements Serializable {
*/
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 @@ -459,6 +481,43 @@ public void clearColumnMappings() {
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");
} 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
*/
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1482,6 +1542,7 @@ private String getDestTypeFromSrcType(int srcColIndx, int destColIndx,
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 @@ -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,
Expand Down Expand Up @@ -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("[").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