in src/main/java/com/microsoft/sqlserver/jdbc/dtv.java [3662:3901]
Object getValue(DTV dtv, JDBCType jdbcType, int scale, InputStreamGetterArgs streamGetterArgs, Calendar cal,
TypeInfo typeInfo, CryptoMetadata cryptoMetadata, TDSReader tdsReader, SQLServerStatement statement) throws SQLServerException {
SQLServerConnection con = tdsReader.getConnection();
Object convertedValue = null;
byte[] decryptedValue;
boolean encrypted = false;
SSType baseSSType = typeInfo.getSSType();
// If column encryption is not enabled on connection or on statement, cryptoMeta will be null.
if (null != cryptoMetadata) {
assert (SSType.VARBINARY == typeInfo.getSSType()) || (SSType.VARBINARYMAX == typeInfo.getSSType());
baseSSType = cryptoMetadata.baseTypeInfo.getSSType();
encrypted = true;
if (aeLogger.isLoggable(java.util.logging.Level.FINE)) {
aeLogger.fine("Data is encrypted, SQL Server Data Type: " + baseSSType + ", Encryption Type: "
+ cryptoMetadata.getEncryptionType());
}
}
// Note that the value should be prepped
// only for columns whose values can be read of the wire.
// If valueMark == null and isNull, it implies that
// the column is null according to NBCROW and that
// there is nothing to be read from the wire.
if (null == valueMark && (!isNull))
getValuePrep(typeInfo, tdsReader);
// either there should be a valueMark
// or valueMark should be null and isNull should be set to true(NBCROW case)
assert ((valueMark != null) || (valueMark == null && isNull));
if (null != streamGetterArgs) {
if (!streamGetterArgs.streamType.convertsFrom(typeInfo))
DataTypes.throwConversionError(typeInfo.getSSType().toString(), streamGetterArgs.streamType.toString());
} else {
if (!baseSSType.convertsTo(jdbcType) && !isNull) {
// if the baseSSType is Character or NCharacter and jdbcType is Longvarbinary,
// does not throw type conversion error, which allows getObject() on Long Character types.
if (encrypted) {
if (!Util.isBinaryType(jdbcType.getIntValue())) {
DataTypes.throwConversionError(baseSSType.toString(), jdbcType.toString());
}
} else {
DataTypes.throwConversionError(baseSSType.toString(), jdbcType.toString());
}
}
streamGetterArgs = InputStreamGetterArgs.getDefaultArgs();
}
if (STREAMCONSUMED == valueLength) {
throw new SQLServerException(null, SQLServerException.getErrString("R_dataAlreadyAccessed"), null, 0,
false);
}
if (!isNull) {
tdsReader.reset(valueMark);
if (encrypted) {
if (DataTypes.UNKNOWN_STREAM_LENGTH == valueLength) {
convertedValue = DDC.convertStreamToObject(
PLPInputStream.makeStream(tdsReader, streamGetterArgs, this), typeInfo, JDBCType.VARBINARY,
streamGetterArgs);
} else {
convertedValue = DDC.convertStreamToObject(
new SimpleInputStream(tdsReader, valueLength, streamGetterArgs, this), typeInfo,
JDBCType.VARBINARY, streamGetterArgs);
}
aeLogger.fine("Encrypted data is retrieved.");
// AE does not support streaming types
if ((convertedValue instanceof SimpleInputStream) || (convertedValue instanceof PLPInputStream)) {
throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), null);
}
decryptedValue = SQLServerSecurityUtility.decryptWithKey((byte[]) convertedValue, cryptoMetadata, con, statement);
return denormalizedValue(decryptedValue, jdbcType, cryptoMetadata.baseTypeInfo, con, streamGetterArgs,
cryptoMetadata.normalizationRuleVersion, cal);
}
switch (baseSSType) {
// Process all PLP types here.
case VARBINARYMAX:
case VARCHARMAX:
case NVARCHARMAX:
case UDT: {
convertedValue = DDC.convertStreamToObject(
PLPInputStream.makeStream(tdsReader, streamGetterArgs, this), typeInfo, jdbcType,
streamGetterArgs);
break;
}
case XML: {
convertedValue = DDC.convertStreamToObject(
((jdbcType.isBinary() || jdbcType == JDBCType.SQLXML) ? PLPXMLInputStream
.makeXMLStream(tdsReader, streamGetterArgs, this)
: PLPInputStream.makeStream(tdsReader,
streamGetterArgs, this)),
typeInfo, jdbcType, streamGetterArgs);
break;
}
// Convert other variable length native types
// (CHAR/VARCHAR/TEXT/NCHAR/NVARCHAR/NTEXT/BINARY/VARBINARY/IMAGE) -> ANY jdbcType.
case CHAR:
case VARCHAR:
case TEXT:
case NCHAR:
case NVARCHAR:
case NTEXT:
case IMAGE:
case BINARY:
case VARBINARY:
case TIMESTAMP: // A special BINARY(8)
{
convertedValue = DDC.convertStreamToObject(
new SimpleInputStream(tdsReader, valueLength, streamGetterArgs, this), typeInfo, jdbcType,
streamGetterArgs);
break;
}
// Convert BIT/TINYINT/SMALLINT/INTEGER/BIGINT native type -> ANY jdbcType.
case BIT:
case TINYINT:
case SMALLINT:
case INTEGER:
case BIGINT: {
switch (valueLength) {
case 8:
convertedValue = DDC.convertLongToObject(tdsReader.readLong(), jdbcType, baseSSType,
streamGetterArgs.streamType);
break;
case 4:
convertedValue = DDC.convertIntegerToObject(tdsReader.readInt(), valueLength, jdbcType,
streamGetterArgs.streamType);
break;
case 2:
convertedValue = DDC.convertIntegerToObject(tdsReader.readShort(), valueLength, jdbcType,
streamGetterArgs.streamType);
break;
case 1:
convertedValue = DDC.convertIntegerToObject(tdsReader.readUnsignedByte(), valueLength,
jdbcType, streamGetterArgs.streamType);
break;
default:
assert false : "Unexpected valueLength" + valueLength;
break;
}
break;
}
// Convert DECIMAL|NUMERIC native types -> ANY jdbcType.
case DECIMAL:
case NUMERIC:
convertedValue = tdsReader.readDecimal(valueLength, typeInfo, jdbcType,
streamGetterArgs.streamType);
break;
// Convert MONEY|SMALLMONEY native types -> ANY jdbcType.
case MONEY:
case SMALLMONEY:
convertedValue = tdsReader.readMoney(valueLength, jdbcType, streamGetterArgs.streamType);
break;
// Convert FLOAT native type -> ANY jdbcType.
case FLOAT:
convertedValue = tdsReader.readFloat(valueLength, jdbcType, streamGetterArgs.streamType);
break;
// Convert REAL native type -> ANY jdbcType.
case REAL:
convertedValue = tdsReader.readReal(valueLength, jdbcType, streamGetterArgs.streamType);
break;
// Convert DATETIME|SMALLDATETIME native types -> ANY jdbcType.
case DATETIME:
case SMALLDATETIME:
convertedValue = tdsReader.readDateTime(valueLength, cal, jdbcType, streamGetterArgs.streamType);
break;
// Convert DATE native type -> ANY jdbcType.
case DATE:
convertedValue = tdsReader.readDate(valueLength, cal, jdbcType);
break;
// Convert TIME native type -> ANY jdbcType.
case TIME:
convertedValue = tdsReader.readTime(valueLength, typeInfo, cal, jdbcType);
break;
// Convert DATETIME2 native type -> ANY jdbcType.
case DATETIME2:
convertedValue = tdsReader.readDateTime2(valueLength, typeInfo, cal, jdbcType);
break;
// Convert DATETIMEOFFSET native type -> ANY jdbcType.
case DATETIMEOFFSET:
convertedValue = tdsReader.readDateTimeOffset(valueLength, typeInfo, jdbcType);
break;
// Convert GUID native type -> ANY jdbcType.
case GUID:
convertedValue = tdsReader.readGUID(valueLength, jdbcType, streamGetterArgs.streamType);
break;
case SQL_VARIANT:
/**
* SQL_Variant has the following structure: 1- basetype: the underlying type 2- probByte: holds
* count of property bytes expected for a sql_variant structure 3- properties: For example VARCHAR
* type has 5 byte collation and 2 byte max length 4- dataValue: the data value
*/
int baseType = tdsReader.readUnsignedByte();
int cbPropsActual = tdsReader.readUnsignedByte();
// don't create new one, if we have already created an internalVariant object. For example, in
// bulkcopy
// when we are reading time column, we update the same internalvarianttype's JDBC to be timestamp
if (null == internalVariant) {
internalVariant = new SqlVariant(baseType);
}
convertedValue = readSqlVariant(baseType, cbPropsActual, valueLength, tdsReader, baseSSType,
typeInfo, jdbcType, streamGetterArgs, cal);
break;
// Unknown SSType should have already been rejected by TypeInfo.setFromTDS()
default:
assert false : "Unexpected SSType " + typeInfo.getSSType();
break;
}
} // !isNull
// Postcondition: returned object is null only if value was null.
assert isNull || null != convertedValue;
return convertedValue;
}