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

Use Bulk Copy API for batch insert operation #686

Merged
merged 43 commits into from
Jun 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
b727aa0
Use Bulk Copy API for batch insert operation
peterbae Apr 20, 2018
52da9aa
Parse bug fixing and test added
peterbae Apr 27, 2018
5bb79a2
bug fix + additional tests
peterbae May 1, 2018
5cf28ad
change reflection for testing
peterbae May 1, 2018
59d29d7
more test changes
peterbae May 1, 2018
dc42708
Add parsing logic for -- comment
peterbae May 1, 2018
f67cad1
Merge branch 'dev' of https://github.com/Microsoft/mssql-jdbc into ba…
peterbae May 3, 2018
dca4cb5
refactoring
peterbae May 3, 2018
1c6a186
Merge branch 'dev' into batch-insert-improvement
cheenamalhotra May 3, 2018
80112c5
Merge branch 'dev' of https://github.com/Microsoft/mssql-jdbc into ba…
peterbae May 7, 2018
8ed14fe
Merge branch 'batch-insert-improvement' of https://github.com/peterba…
peterbae May 7, 2018
b67ccfb
Bug fix / testing change
peterbae May 8, 2018
a677b28
Reflect comment change
peterbae May 8, 2018
60b437e
Refactor two Bulk files into a common parent
peterbae May 25, 2018
8604ff4
javadoc changes
peterbae May 25, 2018
34d8bb1
fix problem with precision / scale
peterbae May 28, 2018
39060b7
fix issue with setting all to true
peterbae May 29, 2018
d80908e
make bamoo fixes
peterbae May 29, 2018
aa34276
Merge branch 'dev' of https://github.com/Microsoft/mssql-jdbc into ba…
peterbae May 30, 2018
8d044b1
undo some changes made to SQLServerConnection
peterbae May 30, 2018
70bea50
apply resource bundling changes
peterbae May 30, 2018
8b45a21
Merge branch 'dev' of https://github.com/Microsoft/mssql-jdbc into ba…
peterbae Jun 4, 2018
c204354
remove on_dw, and remove redundant fmtonly
peterbae Jun 5, 2018
f218fe3
formatting
peterbae Jun 5, 2018
3c5d023
Reformatting + adding more tests
peterbae Jun 6, 2018
dcd63d3
inherit the connection property in statement + fix issue with null / …
peterbae Jun 8, 2018
c322174
comment revisions
peterbae Jun 13, 2018
0700749
Merge branch 'dev' of https://github.com/Microsoft/mssql-jdbc into ba…
peterbae Jun 14, 2018
7dd2d42
Fixing logic / adding more tests
peterbae Jun 19, 2018
84acbb8
dont use test database in tests
peterbae Jun 19, 2018
38bcdc6
Change exception handling as per JDBC specs
peterbae Jun 20, 2018
b4d4b26
remove some comments
peterbae Jun 20, 2018
9b7f40c
reflect comments
peterbae Jun 22, 2018
c6f8011
Merge branch 'dev' of https://github.com/Microsoft/mssql-jdbc into ba…
peterbae Jun 22, 2018
405b47e
changed how logger works, refactored code in SQLServerBulkCommon due …
peterbae Jun 22, 2018
66c0b19
add more tests, make the prepared statement property go away
peterbae Jun 22, 2018
0b65647
Merge branch 'dev' into batch-insert-improvement
cheenamalhotra Jun 24, 2018
80b396a
Merge branch 'dev' of https://github.com/Microsoft/mssql-jdbc into ba…
peterbae Jun 25, 2018
d2d5d23
Merge branch 'batch-insert-improvement' of https://github.com/peterba…
peterbae Jun 25, 2018
2369bb2
Added getter/setter public for the useBulkCopyForBatchInsert connecti…
peterbae Jun 25, 2018
bae637c
Change implementation of child classes a bit
peterbae Jun 25, 2018
b8afb58
Fix bamboo problem + refactor test code
peterbae Jun 26, 2018
096d78e
Replace all connection and statements with try blocks
peterbae Jun 26, 2018
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
4 changes: 4 additions & 0 deletions src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,10 @@ Object getValue(JDBCType jdbcType,
// statement level), cryptoMeta would be null.
return getterDTV.getValue(jdbcType, outScale, getterArgs, cal, typeInfo, cryptoMeta, tdsReader);
}

Object getSetterValue() {
return setterDTV.getSetterValue();
}

int getInt(TDSReader tdsReader) throws SQLServerException {
Integer value = (Integer) getValue(JDBCType.INTEGER, null, null, tdsReader);
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

205 changes: 205 additions & 0 deletions src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCommon.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/*
* 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;

import java.text.MessageFormat;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Map.Entry;

abstract class SQLServerBulkCommon {

/*
* Class to represent the column metadata
*/
protected class ColumnMetadata {
String columnName;
int columnType;
int precision;
int scale;
DateTimeFormatter dateTimeFormatter = null;

ColumnMetadata(String name,
int type,
int precision,
int scale,
DateTimeFormatter dateTimeFormatter) {
columnName = name;
columnType = type;
this.precision = precision;
this.scale = scale;
this.dateTimeFormatter = dateTimeFormatter;
}
}

/*
* Contains all the column names if firstLineIsColumnNames is true
*/
protected String[] columnNames = null;

/*
* Metadata to represent the columns in the batch/file. Each column should be mapped to its corresponding position within the parameter (from
* position 1 and onwards)
*/
protected Map<Integer, ColumnMetadata> columnMetadata;

/*
* Contains the format that java.sql.Types.TIMESTAMP_WITH_TIMEZONE data should be read in as.
*/
protected DateTimeFormatter dateTimeFormatter = null;

/*
* Contains the format that java.sql.Types.TIME_WITH_TIMEZONE data should be read in as.
*/
protected DateTimeFormatter timeFormatter = null;

/**
* Adds metadata for the given column in the batch/file.
*
* @param positionInSource
* Indicates which column the metadata is for. Columns start at 1.
* @param name
* Name for the column (optional if only using column ordinal in a mapping for SQLServerBulkCopy operation)
* @param jdbcType
* JDBC data type of the column
* @param precision
* Precision for the column (ignored for the appropriate data types)
* @param scale
* Scale for the column (ignored for the appropriate data types)
* @param dateTimeFormatter
* format to parse data that is sent
* @throws SQLServerException
* when an error occurs
*/
public void addColumnMetadata(int positionInSource,
String name,
int jdbcType,
int precision,
int scale,
DateTimeFormatter dateTimeFormatter) throws SQLServerException {
addColumnMetadataInternal(positionInSource, name, jdbcType, precision, scale, dateTimeFormatter);
}

/**
* Adds metadata for the given column in the batch/file.
*
* @param positionInSource
* Indicates which column the metadata is for. Columns start at 1.
* @param name
* Name for the column (optional if only using column ordinal in a mapping for SQLServerBulkCopy operation)
* @param jdbcType
* JDBC data type of the column
* @param precision
* Precision for the column (ignored for the appropriate data types)
* @param scale
* Scale for the column (ignored for the appropriate data types)
* @throws SQLServerException
* when an error occurs
*/
public void addColumnMetadata(int positionInSource,
String name,
int jdbcType,
int precision,
int scale) throws SQLServerException {
addColumnMetadataInternal(positionInSource, name, jdbcType, precision, scale, null);
}

/**
* Adds metadata for the given column in the batch/file.
*
* @param positionInSource
* Indicates which column the metadata is for. Columns start at 1.
* @param name
* Name for the column (optional if only using column ordinal in a mapping for SQLServerBulkCopy operation)
* @param jdbcType
* JDBC data type of the column
* @param precision
* Precision for the column (ignored for the appropriate data types)
* @param scale
* Scale for the column (ignored for the appropriate data types)
* @param dateTimeFormatter
* format to parse data that is sent
* @throws SQLServerException
* when an error occurs
*/
void addColumnMetadataInternal(int positionInSource,
String name,
int jdbcType,
int precision,
int scale,
DateTimeFormatter dateTimeFormatter) throws SQLServerException {
}

/**
* Set the format for reading in dates from the batch/file.
*
* @param dateTimeFormat
* format to parse data sent as java.sql.Types.TIMESTAMP_WITH_TIMEZONE
*/
public void setTimestampWithTimezoneFormat(String dateTimeFormat) {
this.dateTimeFormatter = DateTimeFormatter.ofPattern(dateTimeFormat);
}

/**
* Set the format for reading in dates from the batch/file.
*
* @param dateTimeFormatter
* format to parse data sent as java.sql.Types.TIMESTAMP_WITH_TIMEZONE
*/
public void setTimestampWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) {
this.dateTimeFormatter = dateTimeFormatter;
}

/**
* Set the format for reading in dates from the batch/file.
*
* @param timeFormat
* format to parse data sent as java.sql.Types.TIME_WITH_TIMEZONE
*/
public void setTimeWithTimezoneFormat(String timeFormat) {
this.timeFormatter = DateTimeFormatter.ofPattern(timeFormat);
}

/**
* Set the format for reading in dates from the batch/file.
*
* @param dateTimeFormatter
* format to parse data sent as java.sql.Types.TIME_WITH_TIMEZONE
*/
public void setTimeWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) {
this.timeFormatter = dateTimeFormatter;
}

/*
* Helper method to throw a SQLServerExeption with the invalidArgument message and given argument.
*/
protected void throwInvalidArgument(String argument) throws SQLServerException {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument"));
Object[] msgArgs = {argument};
SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, false);
}

/*
* Method to throw a SQLServerExeption for duplicate column names
*/
protected void checkDuplicateColumnName(int positionInTable,
String colName) throws SQLServerException {

if (null != colName && colName.trim().length() != 0) {
for (Entry<Integer, ColumnMetadata> entry : columnMetadata.entrySet()) {
// duplicate check is not performed in case of same positionInTable value
if (null != entry && entry.getKey() != positionInTable) {
if (null != entry.getValue() && colName.trim().equalsIgnoreCase(entry.getValue().columnName)) {
throw new SQLServerException(SQLServerException.getErrString("R_BulkDataDuplicateColumn"), null);
}
}
}
}
}
}
40 changes: 33 additions & 7 deletions src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ private class ColumnMapping {
/* The CekTable for the destination table. */
private CekTable destCekTable = null;

/* Statement level encryption setting needed for querying against encrypted columns. */
private SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting = SQLServerStatementColumnEncryptionSetting.UseConnectionSetting;

private ResultSet destinationTableMetadata;

/*
* Metadata for the destination table columns
*/
Expand Down Expand Up @@ -1490,7 +1495,12 @@ private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerExce
if (null != destType && (destType.toLowerCase(Locale.ENGLISH).trim().startsWith("char") || destType.toLowerCase(Locale.ENGLISH).trim().startsWith("varchar")))
addCollate = " COLLATE " + columnCollation;
}
bulkCmd.append("[" + colMapping.destinationColumnName + "] " + destType + addCollate + endColumn);
if (colMapping.destinationColumnName.contains("]")) {
String escapedColumnName = colMapping.destinationColumnName.replaceAll("]", "]]");
bulkCmd.append("[" + escapedColumnName + "] " + destType + addCollate + endColumn);
} else {
bulkCmd.append("[" + colMapping.destinationColumnName + "] " + destType + addCollate + endColumn);
}
}

if (true == copyOptions.isCheckConstraints()) {
Expand Down Expand Up @@ -1740,11 +1750,19 @@ private void getDestinationMetadata() throws SQLServerException {

SQLServerResultSet rs = null;
SQLServerResultSet rsMoreMetaData = null;

SQLServerStatement stmt = null;

try {
// Get destination metadata
rs = ((SQLServerStatement) connection.createStatement())
.executeQueryInternal("SET FMTONLY ON SELECT * FROM " + destinationTableName + " SET FMTONLY OFF ");
if (null != destinationTableMetadata) {
rs = (SQLServerResultSet) destinationTableMetadata;
}
else {
stmt = (SQLServerStatement) connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
connection.getHoldability(), stmtColumnEncriptionSetting);

// Get destination metadata
rs = stmt.executeQueryInternal("sp_executesql N'SET FMTONLY ON SELECT * FROM " + destinationTableName + " '");
}

destColumnCount = rs.getMetaData().getColumnCount();
destColumnMetadata = new HashMap<>();
Expand Down Expand Up @@ -1783,6 +1801,8 @@ private void getDestinationMetadata() throws SQLServerException {
finally {
if (null != rs)
rs.close();
if (null != stmt)
stmt.close();
if (null != rsMoreMetaData)
rsMoreMetaData.close();
}
Expand Down Expand Up @@ -3059,8 +3079,6 @@ protected Object getTemporalObjectFromCSVWithFormatter(String valueStrUntrimmed,
int srcJdbcType,
int srcColOrdinal,
DateTimeFormatter dateTimeFormatter) throws SQLServerException {
DriverJDBCVersion.checkSupportsJDBC42();

SQLServerBulkCopy42Helper.getTemporalObjectFromCSVWithFormatter(valueStrUntrimmed, srcJdbcType, srcColOrdinal, dateTimeFormatter, connection,
this);

Expand Down Expand Up @@ -3573,4 +3591,12 @@ private boolean writeBatchData(TDSWriter tdsWriter,
}
}
}

protected void setStmtColumnEncriptionSetting(SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting) {
this.stmtColumnEncriptionSetting = stmtColumnEncriptionSetting;
}

protected void setDestinationTableMetadata(SQLServerResultSet rs) {
destinationTableMetadata = rs;
}
}
Loading