All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.sqlserver.jdbc.StreamColumns Maven / Gradle / Ivy

Go to download

Microsoft JDBC Driver for SQL Server. The Azure Key Vault feature in Microsoft JDBC Driver for SQL Server depends on Azure SDK for JAVA and Azure Active Directory Library For Java.

There is a newer version: 12.7.0.jre11-preview
Show newest version
/*
 * Microsoft JDBC Driver for SQL Server
 * 
 * Copyright(c) Microsoft Corporation All rights reserved.
 * 
 * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information.
 */

package com.microsoft.sqlserver.jdbc;

/**
 * StreamColumns stores the column meta data for a result set. StreamColumns parses the inbound TDS packet stream to determine column meta data.
 */

final class StreamColumns extends StreamPacket {
    /** the set of columns */
    private Column[] columns;

    /* The CekTable. */
    private CekTable cekTable = null;

    private boolean shouldHonorAEForRead = false;

    /* Gets the CekTable */
    CekTable getCekTable() {
        return cekTable;
    }

    /**
     * Create a new stream columns
     */
    /* L0 */ StreamColumns() {
        super(TDS.TDS_COLMETADATA);
    }

    /**
     * Create a new stream columns with column encryption setting
     */
    StreamColumns(boolean honorAE) {
        super(TDS.TDS_COLMETADATA);
        shouldHonorAEForRead = honorAE;
    }

    /**
     * Parse a result set column meta data TDS stream for CEK table entry.
     *
     * @throws SQLServerException
     */
    CekTableEntry readCEKTableEntry(TDSReader tdsReader) throws SQLServerException {
        // Read the DB ID
        int databaseId = tdsReader.readInt();

        // Read the keyID
        int cekId = tdsReader.readInt();

        // Read the key version
        int cekVersion = tdsReader.readInt();

        // Read the key MD Version
        byte[] cekMdVersion = new byte[8];
        tdsReader.readBytes(cekMdVersion, 0, 8);

        // Read the value count
        int cekValueCount = tdsReader.readUnsignedByte();

        CekTableEntry cekTableEntry = new CekTableEntry(cekValueCount);

        for (int i = 0; i < cekValueCount; i++) {
            // Read individual CEK values
            short encryptedCEKlength = tdsReader.readShort();

            byte[] encryptedCek = new byte[encryptedCEKlength];

            // Read the actual encrypted CEK
            tdsReader.readBytes(encryptedCek, 0, encryptedCEKlength);

            // Read the length of key store name
            int keyStoreLength = tdsReader.readUnsignedByte();

            // And read the key store name now
            String keyStoreName = tdsReader.readUnicodeString(keyStoreLength);

            // Read the length of key Path
            int keyPathLength = tdsReader.readShort();

            // Read the key path string
            String keyPath = tdsReader.readUnicodeString(keyPathLength);

            // Read the length of the string carrying the encryption algo
            int algorithmLength = tdsReader.readUnsignedByte();

            // Read the string carrying the encryption algo (eg. RSA_PKCS_OAEP)
            String algorithmName = tdsReader.readUnicodeString(algorithmLength);

            // Add this encrypted CEK blob to our list of encrypted values for the CEK
            cekTableEntry.add(encryptedCek, databaseId, cekId, cekVersion, cekMdVersion, keyPath, keyStoreName, algorithmName);
        }
        return cekTableEntry;
    }

    /**
     * Parse a result set column meta data TDS stream for CEK table.
     *
     * @throws SQLServerException
     */
    void readCEKTable(TDSReader tdsReader) throws SQLServerException {
        // Read count
        int tableSize = tdsReader.readShort();

        // CEK table will be sent if AE is enabled. If none of the columns are encrypted, the CEK table
        // size would be zero.
        if (0 != tableSize) {
            cekTable = new CekTable(tableSize);

            // Read individual entries
            for (int i = 0; i < tableSize; i++) {
                // SqlTceCipherInfoEntry entry;
                cekTable.setCekTableEntry(i, readCEKTableEntry(tdsReader));
            }
        }
    }

    /**
     * Parse a result set column meta data TDS stream for crypto metadata for AE.
     *
     * @throws SQLServerException
     */
    CryptoMetadata readCryptoMetadata(TDSReader tdsReader) throws SQLServerException {
        short ordinal = 0;
        // Read the ordinal into cipher table. For return values there is not cipher table and no ordinal.
        if (null != cekTable) {
            ordinal = tdsReader.readShort();
        }

        TypeInfo typeInfo = TypeInfo.getInstance(tdsReader, false);

        // Read the cipher algorithm Id
        byte algorithmId = (byte) tdsReader.readUnsignedByte();

        String algorithmName = null;
        if ((byte) TDS.CUSTOM_CIPHER_ALGORITHM_ID == algorithmId) {
            // Custom encryption algorithm, read the name
            int nameSize = tdsReader.readUnsignedByte();
            algorithmName = tdsReader.readUnicodeString(nameSize);
        }

        // Read Encryption Type.
        byte encryptionType = (byte) tdsReader.readUnsignedByte();

        // Read Normalization Rule Version.
        byte normalizationRuleVersion = (byte) tdsReader.readUnsignedByte();

        CryptoMetadata cryptoMeta = new CryptoMetadata((cekTable == null) ? null : cekTable.getCekTableEntry(ordinal), ordinal, algorithmId,
                algorithmName, encryptionType, normalizationRuleVersion);
        cryptoMeta.setBaseTypeInfo(typeInfo);

        return cryptoMeta;
    }

    /**
     * Parse a result set column meta data TDS stream.
     *
     * @throws SQLServerException
     */
    void setFromTDS(TDSReader tdsReader) throws SQLServerException {
        if (TDS.TDS_COLMETADATA != tdsReader.readUnsignedByte())
            assert false;

        int nTotColumns = tdsReader.readUnsignedShort();

        // Handle the magic NoMetaData value
        if (0xFFFF == nTotColumns)
            return;

        if (tdsReader.getServerSupportsColumnEncryption()) {
            readCEKTable(tdsReader);
        }

        this.columns = new Column[nTotColumns];

        for (int numColumns = 0; numColumns < nTotColumns; numColumns++) {
            // Column type info
            TypeInfo typeInfo = TypeInfo.getInstance(tdsReader, true);

            // Table name
            //
            // Table name is set at this point for TEXT/NTEXT/IMAGE columns only.
            // For other columns, table name may be set via COLUMNINFO and TABNAME tokens.
            SQLIdentifier tableName = new SQLIdentifier();
            if (SSType.TEXT == typeInfo.getSSType() || SSType.NTEXT == typeInfo.getSSType() || SSType.IMAGE == typeInfo.getSSType()) {
                // Yukon and later, table names are returned as multi-part SQL identifiers.
                tableName = tdsReader.readSQLIdentifier();
            }

            CryptoMetadata cryptoMeta = null;
            if (tdsReader.getServerSupportsColumnEncryption() && typeInfo.isEncrypted()) {
                cryptoMeta = readCryptoMetadata(tdsReader);
                cryptoMeta.baseTypeInfo.setFlags(typeInfo.getFlagsAsShort());
                typeInfo.setSQLCollation(cryptoMeta.baseTypeInfo.getSQLCollation());
            }

            // Column name
            String columnName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte());

            if (shouldHonorAEForRead) {
                this.columns[numColumns] = new Column(typeInfo, columnName, tableName, cryptoMeta);
            }
            else {
                // Set null for crypto metadata if column encryption setting is off at the connection or at the statement level.
                this.columns[numColumns] = new Column(typeInfo, columnName, tableName, null);
            }
        }
    }

    /**
     * Applies per-column table information derived from COLINFO and TABNAME tokens to the set of columns defined by this COLMETADATA token to produce
     * the complete set of column information.
     */
    Column[] buildColumns(StreamColInfo colInfoToken,
            StreamTabName tabNameToken) throws SQLServerException {
        if (null != colInfoToken && null != tabNameToken)
            tabNameToken.applyTo(columns, colInfoToken.applyTo(columns));

        return columns;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy