in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java [1210:1461]
private String getDestTypeFromSrcType(int srcColIndx, int destColIndx,
TDSWriter tdsWriter) throws SQLServerException {
boolean isStreaming;
SSType destSSType = (null != destColumnMetadata.get(destColIndx).cryptoMeta) ? destColumnMetadata
.get(destColIndx).cryptoMeta.baseTypeInfo.getSSType() : destColumnMetadata.get(destColIndx).ssType;
int bulkJdbcType, bulkPrecision, bulkScale;
int srcPrecision;
bulkJdbcType = srcColumnMetadata.get(srcColIndx).jdbcType;
// For char/varchar precision is the size.
bulkPrecision = srcPrecision = srcColumnMetadata.get(srcColIndx).precision;
int destPrecision = destColumnMetadata.get(destColIndx).precision;
bulkScale = srcColumnMetadata.get(srcColIndx).scale;
CryptoMetadata destCryptoMeta = destColumnMetadata.get(destColIndx).cryptoMeta;
if (null != destCryptoMeta || (null == destCryptoMeta && copyOptions.isAllowEncryptedValueModifications())) {
// Encrypted columns are sent as binary data.
tdsWriter.setCryptoMetaData(destColumnMetadata.get(destColIndx).cryptoMeta);
/*
* if source is encrypted and destination is unencrypted, use destination's sql type to send since there is
* no way of finding if source is encrypted without accessing the resultset. Send destination type if source
* resultset set is of type SQLServer, encryption is enabled and destination column is not encrypted
*/
if ((sourceResultSet instanceof SQLServerResultSet) && (connection.isColumnEncryptionSettingEnabled())
&& (null != destCryptoMeta)) {
bulkJdbcType = destColumnMetadata.get(destColIndx).jdbcType;
bulkPrecision = destPrecision;
bulkScale = destColumnMetadata.get(destColIndx).scale;
}
// if destination is encrypted send metadata from destination and not from source
if (DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision) {
return "varbinary(max)";
} else {
return "varbinary(" + destColumnMetadata.get(destColIndx).precision + ")";
}
}
// isAllowEncryptedValueModifications is used only with source result set.
if ((null != sourceResultSet) && (null != destColumnMetadata.get(destColIndx).encryptionType)
&& copyOptions.isAllowEncryptedValueModifications()) {
return "varbinary(" + bulkPrecision + ")";
}
bulkPrecision = validateSourcePrecision(srcPrecision, bulkJdbcType, destPrecision);
if ((java.sql.Types.NCHAR == bulkJdbcType) || (java.sql.Types.NVARCHAR == bulkJdbcType)
|| (java.sql.Types.LONGNVARCHAR == bulkJdbcType)) {
isStreaming = (DataTypes.SHORT_VARTYPE_MAX_CHARS < srcPrecision)
|| (DataTypes.SHORT_VARTYPE_MAX_CHARS < destPrecision);
} else {
isStreaming = (DataTypes.SHORT_VARTYPE_MAX_BYTES < srcPrecision)
|| (DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision);
}
// SQL Server does not convert string to binary, we will have to explicitly convert before sending.
if (Util.isCharType(bulkJdbcType) && Util.isBinaryType(destSSType)) {
if (isStreaming)
return "varbinary(max)";
else
// Return binary(n) or varbinary(n) or varbinary(max) depending on destination type/precision.
return destSSType.toString() + "("
+ ((DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision) ? "max" : destPrecision) + ")";
}
switch (bulkJdbcType) {
case java.sql.Types.INTEGER:
return "int";
case java.sql.Types.SMALLINT:
return "smallint";
case java.sql.Types.BIGINT:
return "bigint";
case java.sql.Types.BIT:
return "bit";
case java.sql.Types.TINYINT:
return "tinyint";
case java.sql.Types.FLOAT:
case java.sql.Types.DOUBLE:
return "float";
case java.sql.Types.REAL:
return "real";
case microsoft.sql.Types.MONEY:
return "money";
case microsoft.sql.Types.SMALLMONEY:
return "smallmoney";
case java.sql.Types.DECIMAL:
/*
* SQL Server allows the insertion of decimal and numeric into a money (and smallmoney) column, but
* Azure DW only accepts money types for money column. To make the code compatible against both SQL
* Server and Azure DW, always send decimal and numeric as money/smallmoney if the destination column is
* money/smallmoney and the source is decimal/numeric.
*/
if (destSSType == SSType.MONEY) {
return "money";
} else if (destSSType == SSType.SMALLMONEY) {
return "smallmoney";
}
return "decimal(" + bulkPrecision + ", " + bulkScale + ")";
case java.sql.Types.NUMERIC:
if (destSSType == SSType.MONEY) {
return "money";
} else if (destSSType == SSType.SMALLMONEY) {
return "smallmoney";
}
return "numeric(" + bulkPrecision + ", " + bulkScale + ")";
case microsoft.sql.Types.GUID:
// For char the value has to be between 0 to 8000.
return "char(" + bulkPrecision + ")";
case java.sql.Types.CHAR:
if (unicodeConversionRequired(bulkJdbcType, destSSType)) {
return "nchar(" + bulkPrecision + ")";
} else {
return "char(" + bulkPrecision + ")";
}
case java.sql.Types.NCHAR:
return "NCHAR(" + bulkPrecision + ")";
case java.sql.Types.LONGVARCHAR:
case java.sql.Types.VARCHAR:
// Here the actual size of the varchar is used from the source table.
// Doesn't need to match with the exact size of data or with the destination column size.
if (unicodeConversionRequired(bulkJdbcType, destSSType)) {
if (isStreaming) {
return "nvarchar(max)";
} else {
return "nvarchar(" + bulkPrecision + ")";
}
} else {
if (isStreaming) {
return "varchar(max)";
} else {
return "varchar(" + bulkPrecision + ")";
}
}
// For INSERT BULK operations, XMLTYPE is to be sent as NVARCHAR(N) or NVARCHAR(MAX) data type.
// An error is produced if XMLTYPE is specified.
case java.sql.Types.LONGNVARCHAR:
case java.sql.Types.NVARCHAR:
if (isStreaming) {
return "NVARCHAR(MAX)";
} else {
return "NVARCHAR(" + bulkPrecision + ")";
}
case java.sql.Types.BINARY:
// For binary the value has to be between 0 to 8000.
return "binary(" + bulkPrecision + ")";
case java.sql.Types.LONGVARBINARY:
case java.sql.Types.VARBINARY:
if (isStreaming)
return "varbinary(max)";
else
return "varbinary(" + bulkPrecision + ")";
case microsoft.sql.Types.DATETIME:
case microsoft.sql.Types.SMALLDATETIME:
case java.sql.Types.TIMESTAMP:
switch (destSSType) {
case SMALLDATETIME:
if (null != serverBulkData && connection.getSendTemporalDataTypesAsStringForBulkCopy()) {
return "varchar("
+ ((0 == bulkPrecision) ? sourceBulkRecordTemporalMaxPrecision : bulkPrecision)
+ ")";
} else {
return "smalldatetime";
}
case DATETIME:
if (null != serverBulkData && connection.getSendTemporalDataTypesAsStringForBulkCopy()) {
return "varchar("
+ ((0 == bulkPrecision) ? sourceBulkRecordTemporalMaxPrecision : bulkPrecision)
+ ")";
} else {
return "datetime";
}
default:
// datetime2
/*
* If encrypted, varbinary will be returned before. The code will come here only if unencrypted.
* For unencrypted bulk copy if the source is CSV, we send the data as varchar and SQL Server
* will do the conversion. if the source is ResultSet, we send the data as the corresponding
* temporal type.
*/
if (null != serverBulkData && connection.getSendTemporalDataTypesAsStringForBulkCopy()) {
return "varchar(" + ((0 == bulkPrecision) ? destPrecision : bulkPrecision) + ")";
} else {
return "datetime2(" + bulkScale + ")";
}
}
case java.sql.Types.DATE:
/*
* If encrypted, varbinary will be returned before. The code will come here only if unencrypted. For
* unencrypted bulk copy if the source is CSV, we send the data as varchar and SQL Server will do the
* conversion. if the source is ResultSet, we send the data as the corresponding temporal type.
*/
if (null != serverBulkData && connection.getSendTemporalDataTypesAsStringForBulkCopy()) {
return "varchar(" + ((0 == bulkPrecision) ? destPrecision : bulkPrecision) + ")";
} else {
return "date";
}
case java.sql.Types.TIME:
/*
* If encrypted, varbinary will be returned before. The code will come here only if unencrypted. For
* unencrypted bulk copy if the source is CSV, we send the data as varchar and SQL Server will do the
* conversion. if the source is ResultSet, we send the data as the corresponding temporal type.
*/
if (null != serverBulkData && connection.getSendTemporalDataTypesAsStringForBulkCopy()) {
return "varchar(" + ((0 == bulkPrecision) ? destPrecision : bulkPrecision) + ")";
} else {
return "time(" + bulkScale + ")";
}
// Return DATETIMEOFFSET for TIME_WITH_TIMEZONE and TIMESTAMP_WITH_TIMEZONE
case 2013: // java.sql.Types.TIME_WITH_TIMEZONE
case 2014: // java.sql.Types.TIMESTAMP_WITH_TIMEZONE
return "datetimeoffset(" + bulkScale + ")";
case microsoft.sql.Types.DATETIMEOFFSET:
/*
* If encrypted, varbinary will be returned before. The code will come here only if unencrypted. For
* unencrypted bulk copy if the source is CSV, we send the data as varchar and SQL Server will do the
* conversion. if the source is ResultSet, we send the data as the corresponding temporal type.
*/
if (null != serverBulkData && connection.getSendTemporalDataTypesAsStringForBulkCopy()) {
return "varchar(" + ((0 == bulkPrecision) ? destPrecision : bulkPrecision) + ")";
} else {
return "datetimeoffset(" + bulkScale + ")";
}
case microsoft.sql.Types.SQL_VARIANT:
return "sql_variant";
default: {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported"));
Object[] msgArgs = {JDBCType.of(bulkJdbcType).toString().toLowerCase(Locale.ENGLISH)};
SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true);
}
}
return null;
}