38
38
import java .util .Collections ;
39
39
import java .util .GregorianCalendar ;
40
40
import java .util .HashMap ;
41
+ import java .util .HashSet ;
41
42
import java .util .Iterator ;
42
43
import java .util .List ;
43
44
import java .util .Locale ;
@@ -111,6 +112,22 @@ private class ColumnMapping implements Serializable {
111
112
}
112
113
}
113
114
115
+ private class ColumnOrderHint implements Serializable {
116
+ /**
117
+ * Always update serialVersionUID when prompted.
118
+ */
119
+ private static final long serialVersionUID = 6132627333120344137L ;
120
+
121
+ String columnName = null ;
122
+
123
+ SQLServerSortOrder sortOrder ;
124
+
125
+ ColumnOrderHint (String columnName , SQLServerSortOrder sortOrder ) {
126
+ this .columnName = columnName ;
127
+ this .sortOrder = sortOrder ;
128
+ }
129
+ }
130
+
114
131
/**
115
132
* Class name for logging.
116
133
*/
@@ -136,6 +153,11 @@ private class ColumnMapping implements Serializable {
136
153
*/
137
154
private List <ColumnMapping > columnMappings ;
138
155
156
+ /**
157
+ * Column order hints describe the sort order of columns in the clustered index of the destination
158
+ */
159
+ private List <ColumnOrderHint > columnOrderHints ;
160
+
139
161
/**
140
162
* Flag if SQLServerBulkCopy owns the connection and should close it when Close is called
141
163
*/
@@ -457,6 +479,43 @@ public void clearColumnMappings() {
457
479
loggerExternal .exiting (loggerClassName , "clearColumnMappings" );
458
480
}
459
481
482
+ /**
483
+ * Adds a new column order hint, specify the column name and sort order
484
+ *
485
+ * @param columnName
486
+ * Column name.
487
+ * @param sortOrder
488
+ * Column sort order.
489
+ * @throws SQLServerException
490
+ * If the column order hint is invalid
491
+ */
492
+ public void addColumnOrderHint (String columnName , SQLServerSortOrder sortOrder ) throws SQLServerException {
493
+ if (loggerExternal .isLoggable (java .util .logging .Level .FINER )) {
494
+ loggerExternal .entering (loggerClassName , "addColumnOrderHint" ,
495
+ new Object [] {columnName , sortOrder });
496
+ }
497
+
498
+ if (null == columnName || columnName .isEmpty ()) {
499
+ throwInvalidArgument ("columnName" );
500
+ } else if (null == sortOrder || SQLServerSortOrder .UNSPECIFIED == sortOrder ) {
501
+ throwInvalidArgument ("sortOrder" );
502
+ }
503
+ columnOrderHints .add (new ColumnOrderHint (columnName , sortOrder ));
504
+
505
+ loggerExternal .exiting (loggerClassName , "addColumnOrderHint" );
506
+ }
507
+
508
+ /**
509
+ * Clears the contents of the column order hints
510
+ */
511
+ public void clearColumnOrderHints () {
512
+ loggerExternal .entering (loggerClassName , "clearColumnOrderHints" );
513
+
514
+ columnOrderHints .clear ();
515
+
516
+ loggerExternal .exiting (loggerClassName , "clearColumnOrderHints" );
517
+ }
518
+
460
519
/**
461
520
* Closes the SQLServerBulkCopy instance
462
521
*/
@@ -646,6 +705,7 @@ public void writeToServer(ISQLServerBulkData sourceData) throws SQLServerExcepti
646
705
*/
647
706
private void initializeDefaults () {
648
707
columnMappings = new ArrayList <>();
708
+ columnOrderHints = new ArrayList <>();
649
709
destinationTableName = null ;
650
710
serverBulkData = null ;
651
711
sourceResultSet = null ;
@@ -1493,6 +1553,7 @@ private String getDestTypeFromSrcType(int srcColIndx, int destColIndx,
1493
1553
private String createInsertBulkCommand (TDSWriter tdsWriter ) throws SQLServerException {
1494
1554
StringBuilder bulkCmd = new StringBuilder ();
1495
1555
List <String > bulkOptions = new ArrayList <>();
1556
+ Set <String > destColumns = new HashSet <>();
1496
1557
String endColumn = " , " ;
1497
1558
bulkCmd .append ("INSERT BULK " ).append (destinationTableName ).append (" (" );
1498
1559
@@ -1501,8 +1562,12 @@ private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerExce
1501
1562
endColumn = " ) " ;
1502
1563
}
1503
1564
ColumnMapping colMapping = columnMappings .get (i );
1504
- String columnCollation = destColumnMetadata
1505
- .get (columnMappings .get (i ).destinationColumnOrdinal ).collationName ;
1565
+
1566
+ BulkColumnMetaData columnMetaData = destColumnMetadata
1567
+ .get (columnMappings .get (i ).destinationColumnOrdinal );
1568
+ destColumns .add (columnMetaData .columnName );
1569
+
1570
+ String columnCollation = columnMetaData .collationName ;
1506
1571
String addCollate = "" ;
1507
1572
1508
1573
String destType = getDestTypeFromSrcType (colMapping .sourceColumnOrdinal ,
@@ -1547,6 +1612,36 @@ private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerExce
1547
1612
bulkOptions .add ("ALLOW_ENCRYPTED_VALUE_MODIFICATIONS" );
1548
1613
}
1549
1614
1615
+ if (0 < columnOrderHints .size ()) {
1616
+ StringBuilder orderHintText = new StringBuilder ("ORDER(" );
1617
+
1618
+ for (ColumnOrderHint columnOrderHint : columnOrderHints ) {
1619
+ String columnName = columnOrderHint .columnName ;
1620
+
1621
+ if (!destColumns .contains (columnName )) {
1622
+ MessageFormat form = new MessageFormat (
1623
+ SQLServerException .getErrString ("R_invalidColumn" ));
1624
+ Object [] msgArgs = { columnName };
1625
+ throw new SQLServerException (form .format (msgArgs ), SQLState .COL_NOT_FOUND ,
1626
+ DriverError .NOT_SET , null );
1627
+ }
1628
+
1629
+ String sortOrderText = columnOrderHint .sortOrder == SQLServerSortOrder .DESCENDING ? "DESC" : "ASC" ;
1630
+
1631
+ if (columnName .contains ("]" )) {
1632
+ String escapedColumnName = columnName .replaceAll ("]" , "]]" );
1633
+ orderHintText .append ("[" ).append (escapedColumnName ).append ("] " ).append (sortOrderText ).append (", " );
1634
+ } else {
1635
+ orderHintText .append ("[" ).append (columnName ).append ("] " ).append (sortOrderText ).append (", " );
1636
+ }
1637
+ }
1638
+
1639
+ orderHintText .setLength (orderHintText .length () - 2 );
1640
+ orderHintText .append (")" );
1641
+
1642
+ bulkOptions .add (orderHintText .toString ());
1643
+ }
1644
+
1550
1645
Iterator <String > it = bulkOptions .iterator ();
1551
1646
if (it .hasNext ()) {
1552
1647
bulkCmd .append (" with (" );
0 commit comments