in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java [2974:3097]
private void writeColumn(TDSWriter tdsWriter, int srcColOrdinal, int destColOrdinal,
Object colValue) throws SQLServerException {
String destName = destColumnMetadata.get(destColOrdinal).columnName;
int srcPrecision, srcScale, destPrecision, srcJdbcType;
SSType destSSType = null;
boolean isStreaming, srcNullable;
srcPrecision = srcColumnMetadata.get(srcColOrdinal).precision;
srcScale = srcColumnMetadata.get(srcColOrdinal).scale;
srcJdbcType = srcColumnMetadata.get(srcColOrdinal).jdbcType;
srcNullable = srcColumnMetadata.get(srcColOrdinal).isNullable;
destPrecision = destColumnMetadata.get(destColOrdinal).precision;
if ((java.sql.Types.NCHAR == srcJdbcType) || (java.sql.Types.NVARCHAR == srcJdbcType)
|| (java.sql.Types.LONGNVARCHAR == srcJdbcType)) {
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);
}
CryptoMetadata destCryptoMeta = destColumnMetadata.get(destColOrdinal).cryptoMeta;
if (null != destCryptoMeta) {
destSSType = destCryptoMeta.baseTypeInfo.getSSType();
}
// Get the cell from the source result set if we are copying from result set.
// If we are copying from a bulk reader colValue will be passed as the argument.
if (null != sourceResultSet) {
colValue = readColumnFromResultSet(srcColOrdinal, srcJdbcType, isStreaming, (null != destCryptoMeta));
validateStringBinaryLengths(colValue, srcColOrdinal, destColOrdinal);
// if AllowEncryptedValueModifications is set send varbinary read from source without checking type
// conversion
if (!((copyOptions.isAllowEncryptedValueModifications())
// normalizationCheck() will be called for encrypted columns so skip this validation
|| ((null != destCryptoMeta) && (null != colValue)))) {
validateDataTypeConversions(srcColOrdinal, destColOrdinal);
}
}
// If we are using ISQLBulkRecord and the data we are passing is char type, we need to check the source and dest
// precision
else if (null != serverBulkData && (null == destCryptoMeta)) {
validateStringBinaryLengths(colValue, srcColOrdinal, destColOrdinal);
} else if ((null != serverBulkData) && (null != destCryptoMeta)) {
// From CSV to encrypted column. Convert to respective object.
if ((java.sql.Types.DATE == srcJdbcType) || (java.sql.Types.TIME == srcJdbcType)
|| (java.sql.Types.TIMESTAMP == srcJdbcType) || (microsoft.sql.Types.DATETIMEOFFSET == srcJdbcType)
|| (2013 == srcJdbcType) || (2014 == srcJdbcType)) {
colValue = getTemporalObjectFromCSV(colValue, srcJdbcType, srcColOrdinal);
} else if ((java.sql.Types.NUMERIC == srcJdbcType) || (java.sql.Types.DECIMAL == srcJdbcType)) {
int baseDestPrecision = destCryptoMeta.baseTypeInfo.getPrecision();
int baseDestScale = destCryptoMeta.baseTypeInfo.getScale();
if ((srcScale != baseDestScale) || (srcPrecision != baseDestPrecision)) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidDataForAE"));
String src = JDBCType.of(srcJdbcType) + "(" + srcPrecision + "," + srcScale + ")";
String dest = destSSType + "(" + baseDestPrecision + "," + baseDestScale + ")";
Object[] msgArgs = {src, dest, destName};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
}
}
CryptoMetadata srcCryptoMeta = srcColumnMetadata.get(srcColOrdinal).cryptoMeta;
// If destination is encrypted column, transparently encrypt the data
if ((null != destCryptoMeta) && (null != colValue)) {
JDBCType baseSrcJdbcType = (null != srcCryptoMeta) ? srcColumnMetadata
.get(srcColOrdinal).cryptoMeta.baseTypeInfo.getSSType().getJDBCType() : JDBCType.of(srcJdbcType);
if (JDBCType.TIMESTAMP == baseSrcJdbcType) {
if (SSType.DATETIME == destSSType) {
baseSrcJdbcType = JDBCType.DATETIME;
} else if (SSType.SMALLDATETIME == destSSType) {
baseSrcJdbcType = JDBCType.SMALLDATETIME;
}
}
if (!((SSType.MONEY == destSSType && JDBCType.DECIMAL == baseSrcJdbcType)
|| (SSType.SMALLMONEY == destSSType && JDBCType.DECIMAL == baseSrcJdbcType)
|| (SSType.GUID == destSSType && JDBCType.CHAR == baseSrcJdbcType))) {
// check for bulkcopy from other than SQLServer, for instance for MYSQL, if anykind of chartype pass
if (!(Util.isCharType(destSSType) && Util.isCharType(srcJdbcType))
&& !(sourceResultSet instanceof SQLServerResultSet))
// check for normalization of AE data types
if (!baseSrcJdbcType.normalizationCheck(destSSType)) {
MessageFormat form = new MessageFormat(
SQLServerException.getErrString("R_unsupportedConversionAE"));
Object[] msgArgs = {baseSrcJdbcType, destSSType};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
}
// if source is encrypted and temporal, call IOBuffer functions to encrypt
if ((baseSrcJdbcType == JDBCType.DATE) || (baseSrcJdbcType == JDBCType.TIMESTAMP)
|| (baseSrcJdbcType == JDBCType.TIME) || (baseSrcJdbcType == JDBCType.DATETIMEOFFSET)
|| (baseSrcJdbcType == JDBCType.DATETIME) || (baseSrcJdbcType == JDBCType.SMALLDATETIME)) {
colValue = getEncryptedTemporalBytes(tdsWriter, baseSrcJdbcType, colValue, srcColOrdinal,
destCryptoMeta.baseTypeInfo.getScale());
} else {
TypeInfo destTypeInfo = destCryptoMeta.getBaseTypeInfo();
JDBCType destJdbcType = destTypeInfo.getSSType().getJDBCType();
/*
* the following if checks that no casting exception would be thrown in the normalizedValue() method
* below a SQLServerException is then thrown before the ClassCastException could occur an example of how
* this situation could arise would be if the application creates encrypted source and destination
* tables the result set used to read the source would have AE disabled (causing colValue to be
* varbinary) AE would be enabled on the connection used to complete the bulkCopy operation
*/
if ((!Util.isBinaryType(destJdbcType.getIntValue())) && (colValue instanceof byte[])) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidDataForAE"));
Object[] msgArgs = {baseSrcJdbcType, destJdbcType, destName};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
}
// normalize the values before encrypting them
colValue = SQLServerSecurityUtility.encryptWithKey(normalizedValue(destJdbcType, colValue,
baseSrcJdbcType, destTypeInfo.getPrecision(), destTypeInfo.getScale(), destName),
destCryptoMeta, connection, null);
}
}
writeColumnToTdsWriter(tdsWriter, srcPrecision, srcScale, srcJdbcType, srcNullable, srcColOrdinal,
destColOrdinal, isStreaming, colValue);
}