private void writeColumn()

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