in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java [2603:2835]
private void writeSqlVariant(TDSWriter tdsWriter, Object colValue, ResultSet sourceResultSet, int srcColOrdinal,
int destColOrdinal, int bulkJdbcType, int bulkScale, boolean isStreaming) throws SQLServerException {
if (null == colValue) {
writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming);
return;
}
SqlVariant variantType = ((SQLServerResultSet) sourceResultSet).getVariantInternalType(srcColOrdinal);
int baseType = variantType.getBaseType();
byte[] srcBytes;
// for sql variant we normally should return the colvalue for time as time string. but for
// bulkcopy we need it to be timestamp. so we have to retrieve it again once we are in bulkcopy
// and make sure that the base type is time.
if (TDSType.TIMEN == TDSType.valueOf(baseType)) {
variantType.setIsBaseTypeTimeValue(true);
((SQLServerResultSet) sourceResultSet).setInternalVariantType(srcColOrdinal, variantType);
colValue = ((SQLServerResultSet) sourceResultSet).getObject(srcColOrdinal);
}
switch (TDSType.valueOf(baseType)) {
case INT8:
writeBulkCopySqlVariantHeader(10, TDSType.INT8.byteValue(), (byte) 0, tdsWriter);
tdsWriter.writeLong(Long.valueOf(colValue.toString()));
break;
case INT4:
writeBulkCopySqlVariantHeader(6, TDSType.INT4.byteValue(), (byte) 0, tdsWriter);
tdsWriter.writeInt(Integer.valueOf(colValue.toString()));
break;
case INT2:
writeBulkCopySqlVariantHeader(4, TDSType.INT2.byteValue(), (byte) 0, tdsWriter);
tdsWriter.writeShort(Short.valueOf(colValue.toString()));
break;
case INT1:
writeBulkCopySqlVariantHeader(3, TDSType.INT1.byteValue(), (byte) 0, tdsWriter);
tdsWriter.writeByte(Byte.valueOf(colValue.toString()));
break;
case FLOAT8:
writeBulkCopySqlVariantHeader(10, TDSType.FLOAT8.byteValue(), (byte) 0, tdsWriter);
tdsWriter.writeDouble(Double.valueOf(colValue.toString()));
break;
case FLOAT4:
writeBulkCopySqlVariantHeader(6, TDSType.FLOAT4.byteValue(), (byte) 0, tdsWriter);
tdsWriter.writeReal(Float.valueOf(colValue.toString()));
break;
case MONEY8:
// For decimalN we right TDSWriter.BIGDECIMAL_MAX_LENGTH as maximum length = 17
// 17 + 2 for basetype and probBytes + 2 for precision and length = 21 the length of data in header
writeBulkCopySqlVariantHeader(21, TDSType.DECIMALN.byteValue(), (byte) 2, tdsWriter);
tdsWriter.writeByte((byte) 38);
tdsWriter.writeByte((byte) 4);
tdsWriter.writeSqlVariantInternalBigDecimal((BigDecimal) colValue, bulkJdbcType);
break;
case MONEY4:
writeBulkCopySqlVariantHeader(21, TDSType.DECIMALN.byteValue(), (byte) 2, tdsWriter);
tdsWriter.writeByte((byte) 38);
tdsWriter.writeByte((byte) 4);
tdsWriter.writeSqlVariantInternalBigDecimal((BigDecimal) colValue, bulkJdbcType);
break;
case BIT1:
writeBulkCopySqlVariantHeader(3, TDSType.BIT1.byteValue(), (byte) 0, tdsWriter);
tdsWriter.writeByte((byte) (((Boolean) colValue).booleanValue() ? 1 : 0));
break;
case DATEN:
writeBulkCopySqlVariantHeader(5, TDSType.DATEN.byteValue(), (byte) 0, tdsWriter);
tdsWriter.writeDate(colValue.toString());
break;
case TIMEN:
int timeBulkScale = variantType.getScale();
int timeHeaderLength = 0x08; // default
if (2 >= timeBulkScale) {
timeHeaderLength = 0x06;
} else if (4 >= timeBulkScale) {
timeHeaderLength = 0x07;
} else {
timeHeaderLength = 0x08;
}
writeBulkCopySqlVariantHeader(timeHeaderLength, TDSType.TIMEN.byteValue(), (byte) 1, tdsWriter); // depending
// on
// scale,
// the
// header
// length
// defers
tdsWriter.writeByte((byte) timeBulkScale);
tdsWriter.writeTime((java.sql.Timestamp) colValue, timeBulkScale);
break;
case DATETIME8:
writeBulkCopySqlVariantHeader(10, TDSType.DATETIME8.byteValue(), (byte) 0, tdsWriter);
tdsWriter.writeDatetime(colValue.toString());
break;
case DATETIME4:
// when the type is ambiguous, we write to bigger type
writeBulkCopySqlVariantHeader(10, TDSType.DATETIME8.byteValue(), (byte) 0, tdsWriter);
tdsWriter.writeDatetime(colValue.toString());
break;
case DATETIME2N:
writeBulkCopySqlVariantHeader(10, TDSType.DATETIME2N.byteValue(), (byte) 1, tdsWriter); // 1 is
// probbytes for
// time
tdsWriter.writeByte((byte) 0x03);
String timeStampValue = colValue.toString();
tdsWriter.writeTime(java.sql.Timestamp.valueOf(timeStampValue), 0x03); // datetime2 in sql_variant has
// up to scale 3 support
// Send only the date part
tdsWriter.writeDate(timeStampValue.substring(0, timeStampValue.lastIndexOf(' ')));
break;
case BIGCHAR:
int length = colValue.toString().length();
writeBulkCopySqlVariantHeader(9 + length, TDSType.BIGCHAR.byteValue(), (byte) 7, tdsWriter);
tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID
tdsWriter.writeShort((short) (length));
SQLCollation destCollation = destColumnMetadata.get(destColOrdinal).collation;
if (null != destCollation) {
tdsWriter.writeBytes(colValue.toString()
.getBytes(destColumnMetadata.get(destColOrdinal).collation.getCharset()));
} else {
tdsWriter.writeBytes(colValue.toString().getBytes());
}
break;
case BIGVARCHAR:
length = colValue.toString().length();
writeBulkCopySqlVariantHeader(9 + length, TDSType.BIGVARCHAR.byteValue(), (byte) 7, tdsWriter);
tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID
tdsWriter.writeShort((short) (length));
destCollation = destColumnMetadata.get(destColOrdinal).collation;
if (null != destCollation) {
tdsWriter.writeBytes(colValue.toString()
.getBytes(destColumnMetadata.get(destColOrdinal).collation.getCharset()));
} else {
tdsWriter.writeBytes(colValue.toString().getBytes());
}
break;
case NCHAR:
length = colValue.toString().length() * 2;
writeBulkCopySqlVariantHeader(9 + length, TDSType.NCHAR.byteValue(), (byte) 7, tdsWriter);
tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID
int stringLength = colValue.toString().length();
byte[] typevarlen = new byte[2];
typevarlen[0] = (byte) (2 * stringLength & 0xFF);
typevarlen[1] = (byte) ((2 * stringLength >> 8) & 0xFF);
tdsWriter.writeBytes(typevarlen);
tdsWriter.writeString(colValue.toString());
break;
case NVARCHAR:
length = colValue.toString().length() * 2;
writeBulkCopySqlVariantHeader(9 + length, TDSType.NVARCHAR.byteValue(), (byte) 7, tdsWriter);
tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID
stringLength = colValue.toString().length();
typevarlen = new byte[2];
typevarlen[0] = (byte) (2 * stringLength & 0xFF);
typevarlen[1] = (byte) ((2 * stringLength >> 8) & 0xFF);
tdsWriter.writeBytes(typevarlen);
tdsWriter.writeString(colValue.toString());
break;
case GUID:
length = colValue.toString().length();
writeBulkCopySqlVariantHeader(9 + length, TDSType.BIGCHAR.byteValue(), (byte) 7, tdsWriter);
// since while reading collation from sourceMetaData in guid we don't read collation, cause we are
// reading binary
// but in writing it we are using char, we need to get the collation.
SQLCollation collation = (null != destColumnMetadata.get(srcColOrdinal).collation) ? destColumnMetadata
.get(srcColOrdinal).collation : connection.getDatabaseCollation();
variantType.setCollation(collation);
tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID
tdsWriter.writeShort((short) (length));
// converting string into destination collation using Charset
destCollation = destColumnMetadata.get(destColOrdinal).collation;
if (null != destCollation) {
tdsWriter.writeBytes(colValue.toString()
.getBytes(destColumnMetadata.get(destColOrdinal).collation.getCharset()));
} else {
tdsWriter.writeBytes(colValue.toString().getBytes());
}
break;
case BIGBINARY:
byte[] b = (byte[]) colValue;
length = b.length;
writeBulkCopySqlVariantHeader(4 + length, TDSType.BIGVARBINARY.byteValue(), (byte) 2, tdsWriter);
tdsWriter.writeShort((short) (variantType.getMaxLength())); // length
if (colValue instanceof byte[]) {
srcBytes = (byte[]) colValue;
} else {
try {
srcBytes = ParameterUtils.HexToBin(colValue.toString());
} catch (SQLServerException e) {
throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e);
}
}
tdsWriter.writeBytes(srcBytes);
break;
case BIGVARBINARY:
b = (byte[]) colValue;
length = b.length;
writeBulkCopySqlVariantHeader(4 + length, TDSType.BIGVARBINARY.byteValue(), (byte) 2, tdsWriter);
tdsWriter.writeShort((short) (variantType.getMaxLength())); // length
if (colValue instanceof byte[]) {
srcBytes = (byte[]) colValue;
} else {
try {
srcBytes = ParameterUtils.HexToBin(colValue.toString());
} catch (SQLServerException e) {
throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e);
}
}
tdsWriter.writeBytes(srcBytes);
break;
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);
break;
}
}