Object getValue()

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;
    }