private void writeInternalTVPRowValues()

in src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java [5098:5374]


    private void writeInternalTVPRowValues(JDBCType jdbcType, String currentColumnStringValue, Object currentObject,
            Map.Entry<Integer, SQLServerMetaData> columnPair, boolean isSqlVariant) throws SQLServerException {
        boolean isShortValue, isNull;
        int dataLength;
        switch (jdbcType) {
            case BIGINT:
                if (null == currentColumnStringValue)
                    writeByte((byte) 0);
                else {
                    if (isSqlVariant) {
                        writeTVPSqlVariantHeader(10, TDSType.INT8.byteValue(), (byte) 0);
                    } else {
                        writeByte((byte) 8);
                    }
                    writeLong(Long.valueOf(currentColumnStringValue).longValue());
                }
                break;

            case BIT:
                if (null == currentColumnStringValue)
                    writeByte((byte) 0);
                else {
                    if (isSqlVariant)
                        writeTVPSqlVariantHeader(3, TDSType.BIT1.byteValue(), (byte) 0);
                    else
                        writeByte((byte) 1);
                    writeByte((byte) (Boolean.valueOf(currentColumnStringValue).booleanValue() ? 1 : 0));
                }
                break;

            case INTEGER:
                if (null == currentColumnStringValue)
                    writeByte((byte) 0);
                else {
                    if (!isSqlVariant)
                        writeByte((byte) 4);
                    else
                        writeTVPSqlVariantHeader(6, TDSType.INT4.byteValue(), (byte) 0);
                    writeInt(Integer.valueOf(currentColumnStringValue).intValue());
                }
                break;

            case SMALLINT:
            case TINYINT:
                if (null == currentColumnStringValue)
                    writeByte((byte) 0);
                else {
                    if (isSqlVariant) {
                        writeTVPSqlVariantHeader(6, TDSType.INT4.byteValue(), (byte) 0);
                        writeInt(Integer.valueOf(currentColumnStringValue));
                    } else {
                        writeByte((byte) 2); // length of datatype
                        writeShort(Short.valueOf(currentColumnStringValue).shortValue());
                    }
                }
                break;

            case DECIMAL:
            case NUMERIC:
                if (null == currentColumnStringValue)
                    writeByte((byte) 0);
                else {
                    if (isSqlVariant) {
                        writeTVPSqlVariantHeader(21, TDSType.DECIMALN.byteValue(), (byte) 2);
                        writeByte((byte) 38); // scale (byte)variantType.getScale()
                        writeByte((byte) 4); // scale (byte)variantType.getScale()
                    } else {
                        writeByte((byte) TDSWriter.BIGDECIMAL_MAX_LENGTH); // maximum length
                    }
                    BigDecimal bdValue = new BigDecimal(currentColumnStringValue);

                    /*
                     * setScale of all BigDecimal value based on metadata as scale is not sent separately for individual
                     * value. Use the rounding used in Server. Say, for BigDecimal("0.1"), if scale in metdadata is 0,
                     * then ArithmeticException would be thrown if RoundingMode is not set
                     */
                    bdValue = bdValue.setScale(columnPair.getValue().scale, RoundingMode.HALF_UP);

                    byte[] valueBytes = DDC.convertBigDecimalToBytes(bdValue, bdValue.scale());

                    // 1-byte for sign and 16-byte for integer
                    byte[] byteValue = new byte[17];

                    // removing the precision and scale information from the valueBytes array
                    System.arraycopy(valueBytes, 2, byteValue, 0, valueBytes.length - 2);
                    writeBytes(byteValue);
                }
                break;

            case DOUBLE:
                if (null == currentColumnStringValue)
                    writeByte((byte) 0); // len of data bytes
                else {
                    if (isSqlVariant) {
                        writeTVPSqlVariantHeader(10, TDSType.FLOAT8.byteValue(), (byte) 0);
                        writeDouble(Double.valueOf(currentColumnStringValue));
                        break;
                    }
                    writeByte((byte) 8); // len of data bytes
                    long bits = Double.doubleToLongBits(Double.valueOf(currentColumnStringValue).doubleValue());
                    long mask = 0xFF;
                    int nShift = 0;
                    for (int i = 0; i < 8; i++) {
                        writeByte((byte) ((bits & mask) >> nShift));
                        nShift += 8;
                        mask = mask << 8;
                    }
                }
                break;

            case FLOAT:
            case REAL:
                if (null == currentColumnStringValue)
                    writeByte((byte) 0);
                else {
                    if (isSqlVariant) {
                        writeTVPSqlVariantHeader(6, TDSType.FLOAT4.byteValue(), (byte) 0);
                        writeInt(Float.floatToRawIntBits(Float.valueOf(currentColumnStringValue).floatValue()));
                    } else {
                        writeByte((byte) 4);
                        writeInt(Float.floatToRawIntBits(Float.valueOf(currentColumnStringValue).floatValue()));
                    }
                }
                break;

            case DATE:
            case TIME:
            case TIMESTAMP:
            case DATETIMEOFFSET:
            case DATETIME:
            case SMALLDATETIME:
            case TIMESTAMP_WITH_TIMEZONE:
            case TIME_WITH_TIMEZONE:
            case CHAR:
            case VARCHAR:
            case NCHAR:
            case NVARCHAR:
            case LONGVARCHAR:
            case LONGNVARCHAR:
            case SQLXML:
                isShortValue = (2L * columnPair.getValue().precision) <= DataTypes.SHORT_VARTYPE_MAX_BYTES;
                isNull = (null == currentColumnStringValue);
                dataLength = isNull ? 0 : currentColumnStringValue.length() * 2;
                if (!isShortValue) {
                    // check null
                    if (isNull) {
                        // Null header for v*max types is 0xFFFFFFFFFFFFFFFF.
                        writeLong(0xFFFFFFFFFFFFFFFFL);
                    } else if (isSqlVariant) {
                        // for now we send as bigger type, but is sendStringParameterAsUnicode is set to false we can't
                        // send nvarchar
                        // since we are writing as nvarchar we need to write as tdstype.bigvarchar value because if we
                        // want to supprot varchar(8000) it becomes as nvarchar, 8000*2 therefore we should send as
                        // longvarchar,
                        // but we cannot send more than 8000 cause sql_variant datatype in sql server does not support
                        // it.
                        // then throw exception if user is sending more than that
                        if (dataLength > 2 * DataTypes.SHORT_VARTYPE_MAX_BYTES) {
                            MessageFormat form = new MessageFormat(
                                    SQLServerException.getErrString("R_invalidStringValue"));
                            throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false);
                        }
                        int length = currentColumnStringValue.length();
                        writeTVPSqlVariantHeader(9 + length, TDSType.BIGVARCHAR.byteValue(), (byte) 0x07);
                        SQLCollation col = con.getDatabaseCollation();
                        // write collation for sql variant
                        writeInt(col.getCollationInfo());
                        writeByte((byte) col.getCollationSortID());
                        writeShort((short) (length));
                        writeBytes(currentColumnStringValue.getBytes());
                        break;
                    }

                    else if (DataTypes.UNKNOWN_STREAM_LENGTH == dataLength)
                        // Append v*max length.
                        // UNKNOWN_PLP_LEN is 0xFFFFFFFFFFFFFFFE
                        writeLong(0xFFFFFFFFFFFFFFFEL);
                    else
                        // For v*max types with known length, length is <totallength8><chunklength4>
                        writeLong(dataLength);
                    if (!isNull) {
                        if (dataLength > 0) {
                            writeInt(dataLength);
                            writeString(currentColumnStringValue);
                        }
                        // Send the terminator PLP chunk.
                        writeInt(0);
                    }
                } else {
                    if (isNull)
                        writeShort((short) -1); // actual len
                    else {
                        if (isSqlVariant) {
                            // for now we send as bigger type, but is sendStringParameterAsUnicoe is set to false we
                            // can't send nvarchar
                            // check for this
                            int length = currentColumnStringValue.length() * 2;
                            writeTVPSqlVariantHeader(9 + length, TDSType.NVARCHAR.byteValue(), (byte) 7);
                            SQLCollation col = con.getDatabaseCollation();
                            // write collation for sql variant
                            writeInt(col.getCollationInfo());
                            writeByte((byte) col.getCollationSortID());
                            int stringLength = currentColumnStringValue.length();
                            byte[] typevarlen = new byte[2];
                            typevarlen[0] = (byte) (2 * stringLength & 0xFF);
                            typevarlen[1] = (byte) ((2 * stringLength >> 8) & 0xFF);
                            writeBytes(typevarlen);
                            writeString(currentColumnStringValue);
                            break;
                        } else {
                            writeShort((short) dataLength);
                            writeString(currentColumnStringValue);
                        }
                    }
                }
                break;

            case BINARY:
            case VARBINARY:
            case LONGVARBINARY:
                // Handle conversions as done in other types.
                isShortValue = columnPair.getValue().precision <= DataTypes.SHORT_VARTYPE_MAX_BYTES;
                isNull = (null == currentObject);
                if (currentObject instanceof String)
                    dataLength = ParameterUtils.HexToBin(currentObject.toString()).length;
                else
                    dataLength = isNull ? 0 : ((byte[]) currentObject).length;
                if (!isShortValue) {
                    // check null
                    if (isNull)
                        // Null header for v*max types is 0xFFFFFFFFFFFFFFFF.
                        writeLong(0xFFFFFFFFFFFFFFFFL);
                    else if (DataTypes.UNKNOWN_STREAM_LENGTH == dataLength)
                        // Append v*max length.
                        // UNKNOWN_PLP_LEN is 0xFFFFFFFFFFFFFFFE
                        writeLong(0xFFFFFFFFFFFFFFFEL);
                    else
                        // For v*max types with known length, length is <totallength8><chunklength4>
                        writeLong(dataLength);
                    if (!isNull) {
                        if (dataLength > 0) {
                            writeInt(dataLength);
                            if (currentObject instanceof String)
                                writeBytes(ParameterUtils.HexToBin(currentObject.toString()));
                            else
                                writeBytes((byte[]) currentObject);
                        }
                        // Send the terminator PLP chunk.
                        writeInt(0);
                    }
                } else {
                    if (isNull)
                        writeShort((short) -1); // actual len
                    else {
                        writeShort((short) dataLength);
                        if (currentObject instanceof String)
                            writeBytes(ParameterUtils.HexToBin(currentObject.toString()));
                        else
                            writeBytes((byte[]) currentObject);
                    }
                }
                break;
            case SQL_VARIANT:
                boolean isShiloh = (8 >= con.getServerMajorVersion());
                if (isShiloh) {
                    MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_SQLVariantSupport"));
                    throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false);
                }
                JDBCType internalJDBCType;
                JavaType javaType = JavaType.of(currentObject);
                internalJDBCType = javaType.getJDBCType(SSType.UNKNOWN, jdbcType);
                writeInternalTVPRowValues(internalJDBCType, currentColumnStringValue, currentObject, columnPair, true);
                break;
            default:
                assert false : "Unexpected JDBC type " + jdbcType.toString();
        }
    }