private void setTypeDefinition()

in src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java [435:903]


        private void setTypeDefinition(DTV dtv) {
            switch (dtv.getJdbcType()) {
                case TINYINT:
                    param.typeDefinition = SSType.TINYINT.toString();
                    break;

                case SMALLINT:
                    param.typeDefinition = SSType.SMALLINT.toString();
                    break;

                case INTEGER:
                    param.typeDefinition = SSType.INTEGER.toString();
                    break;

                case BIGINT:
                    param.typeDefinition = SSType.BIGINT.toString();
                    break;

                case REAL:
                    // sp_describe_parameter_encryption must be queried as real for AE
                    if (param.shouldHonorAEForParameter && (null != jdbcTypeSetByUser)
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {
                        /*
                         * This means AE is ON in the connection, and (1) this is either the first round to SQL Server
                         * to get encryption meta data, or (2) this is the second round of renewing meta data and
                         * parameter is encrypted In both of these cases we need to send specific type info, otherwise
                         * generic type info can be used as before.
                         */
                        param.typeDefinition = SSType.REAL.toString();
                    } else {
                        // use FLOAT if column is not encrypted
                        param.typeDefinition = SSType.FLOAT.toString();
                    }
                    break;

                case FLOAT:
                case DOUBLE:
                    param.typeDefinition = SSType.FLOAT.toString();
                    break;

                case DECIMAL:
                case NUMERIC:
                    // First, bound the scale by the maximum allowed by SQL Server
                    if (scale > SQLServerConnection.maxDecimalPrecision)
                        scale = SQLServerConnection.maxDecimalPrecision;

                    // Next, prepare with the largest of:
                    // - the value's scale (initial value, as limited above)
                    // - the specified input scale (if any)
                    // - the registered output scale
                    Integer inScale = dtv.getScale();
                    if (null != inScale && scale < inScale)
                        scale = inScale;

                    if (param.isOutput() && scale < param.getOutScale())
                        scale = param.getOutScale();

                    if (param.shouldHonorAEForParameter && (null != jdbcTypeSetByUser)
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {
                        /*
                         * This means AE is ON in the connection, and (1) this is either the first round to SQL Server
                         * to get encryption meta data, or (2) this is the second round of renewing meta data and
                         * parameter is encrypted In both of these cases we need to send specific type info, otherwise
                         * generic type info can be used as before.
                         */
                        if (0 == valueLength) {
                            // for prepared statement and callable statement, There are only two cases where valueLength
                            // is 0:
                            // 1. when the parameter is output parameter
                            // 2. for input parameter, the value is null
                            // so, here, if the decimal parameter is encrypted and it is null and it is not outparameter
                            // then we set precision as the default precision instead of max precision
                            if (!isOutput()) {
                                param.typeDefinition = "decimal(" + SQLServerConnection.defaultDecimalPrecision + ", "
                                        + scale + ")";
                            }
                        } else {
                            if (SQLServerConnection.defaultDecimalPrecision >= valueLength) {
                                param.typeDefinition = "decimal(" + SQLServerConnection.defaultDecimalPrecision + ","
                                        + scale + ")";

                                if (SQLServerConnection.defaultDecimalPrecision < (valueLength + scale)) {
                                    param.typeDefinition = "decimal("
                                            + (SQLServerConnection.defaultDecimalPrecision + scale) + "," + scale + ")";
                                }
                            } else {
                                param.typeDefinition = "decimal(" + SQLServerConnection.maxDecimalPrecision + ","
                                        + scale + ")";
                            }
                        }

                        if (isOutput()) {
                            param.typeDefinition = "decimal(" + SQLServerConnection.maxDecimalPrecision + ", " + scale
                                    + ")";
                        }

                        if (userProvidesPrecision) {
                            param.typeDefinition = "decimal(" + valueLength + "," + scale + ")";
                        }
                    } else
                        param.typeDefinition = "decimal(" + SQLServerConnection.maxDecimalPrecision + "," + scale + ")";

                    break;

                case MONEY:
                    param.typeDefinition = SSType.MONEY.toString();
                    break;
                case SMALLMONEY:
                    param.typeDefinition = SSType.MONEY.toString();

                    if (param.shouldHonorAEForParameter
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {
                        param.typeDefinition = SSType.SMALLMONEY.toString();
                    }

                    break;
                case BIT:
                case BOOLEAN:
                    param.typeDefinition = SSType.BIT.toString();
                    break;

                case LONGVARBINARY:
                case BLOB:
                    param.typeDefinition = VARBINARY_MAX;
                    break;

                case BINARY:
                case VARBINARY:
                    // To avoid the server side cost of re-preparing, once a "long" type, always a "long" type...
                    if (VARBINARY_MAX.equals(param.typeDefinition) || IMAGE.equals(param.typeDefinition))
                        break;
                    if (param.shouldHonorAEForParameter && (null != jdbcTypeSetByUser)
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {
                        /*
                         * This means AE is ON in the connection, and (1) this is either the first round to SQL Server
                         * to get encryption meta data, or (2) this is the second round of renewing meta data and
                         * parameter is encrypted In both of these cases we need to send specific type info, otherwise
                         * generic type info can be used as before.
                         */
                        if (0 == valueLength) {
                            // Workaround for the issue when inserting empty string and null into encrypted columns
                            param.typeDefinition = "varbinary(1)";
                            valueLength++;
                        } else {
                            param.typeDefinition = "varbinary(" + valueLength + ")";
                        }

                        if (JDBCType.LONGVARBINARY == jdbcTypeSetByUser) {
                            param.typeDefinition = VARBINARY_MAX;
                        }
                    } else
                        param.typeDefinition = VARBINARY_8K;
                    break;

                case DATE:
                    // Bind DATE values to pre-Katmai servers as DATETIME (which has no DATE-only type).
                    param.typeDefinition = con.isKatmaiOrLater() ? SSType.DATE.toString() : SSType.DATETIME.toString();
                    break;

                case TIME:
                    if (param.shouldHonorAEForParameter
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {

                        /*
                         * This means AE is ON in the connection, and (1) this is either the first round to SQL Server
                         * to get encryption meta data, or (2) this is the second round of renewing meta data and
                         * parameter is encrypted In both of these cases we need to send specific type info, otherwise
                         * generic type info can be used as before.
                         */

                        if (userProvidesScale) {
                            param.typeDefinition = SSType.TIME.toString() + "(" + outScale + ")";
                        } else {
                            param.typeDefinition = SSType.TIME.toString() + "(" + valueLength + ")";
                        }
                    } else {
                        param.typeDefinition = con.getSendTimeAsDatetime() ? SSType.DATETIME.toString()
                                                                           : SSType.TIME.toString();
                    }
                    break;

                case TIMESTAMP:
                    // Bind TIMESTAMP values to pre-Katmai servers as DATETIME. Bind TIMESTAMP values to
                    // Katmai and later servers as DATETIME2 to take advantage of increased precision.
                    if (param.shouldHonorAEForParameter
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {
                        /*
                         * This means AE is ON in the connection, and (1) this is either the first round to SQL Server
                         * to get encryption meta data, or (2) this is the second round of renewing meta data and
                         * parameter is encrypted In both of these cases we need to send specific type info, otherwise
                         * generic type info can be used as before.
                         */
                        if (userProvidesScale) {
                            param.typeDefinition = con
                                    .isKatmaiOrLater() ? (SSType.DATETIME2.toString() + "(" + outScale + ")")
                                                       : (SSType.DATETIME.toString());
                        } else {
                            param.typeDefinition = con.isKatmaiOrLater()
                                                                         ? (SSType.DATETIME2.toString() + "("
                                                                                 + valueLength + ")")
                                                                         : SSType.DATETIME.toString();
                        }
                    } else {
                        param.typeDefinition = con.isKatmaiOrLater() ? SSType.DATETIME2.toString()
                                                                     : SSType.DATETIME.toString();
                    }
                    break;

                case DATETIME:
                    // send as Datetime by default
                    param.typeDefinition = SSType.DATETIME2.toString();

                    if (param.shouldHonorAEForParameter
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {
                        param.typeDefinition = SSType.DATETIME.toString();
                    }

                    if (!param.shouldHonorAEForParameter) {
                        // if AE is off and it is output parameter of stored procedure, sent it as datetime2(3)
                        // otherwise it returns incorrect milliseconds.
                        if (param.isOutput()) {
                            param.typeDefinition = SSType.DATETIME2.toString() + "(" + outScale + ")";
                        }
                    } else {
                        // when AE is on, set it to Datetime by default,
                        // However, if column is not encrypted and it is output parameter of stored procedure,
                        // renew it to datetime2(3)
                        if (null == param.getCryptoMetadata() && param.renewDefinition) {
                            if (param.isOutput()) {
                                param.typeDefinition = SSType.DATETIME2.toString() + "(" + outScale + ")";
                            }
                            break;
                        }
                    }
                    break;

                case SMALLDATETIME:
                    param.typeDefinition = SSType.DATETIME2.toString();

                    if (param.shouldHonorAEForParameter
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {
                        param.typeDefinition = SSType.SMALLDATETIME.toString();
                    }

                    break;

                case TIME_WITH_TIMEZONE:
                case TIMESTAMP_WITH_TIMEZONE:
                case DATETIMEOFFSET:
                    if (param.shouldHonorAEForParameter
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {
                        /*
                         * This means AE is ON in the connection, and (1) this is either the first round to SQL Server
                         * to get encryption meta data, or (2) this is the second round of renewing meta data and
                         * parameter is encrypted In both of these cases we need to send specific type info, otherwise
                         * generic type info can be used as before.
                         */
                        if (userProvidesScale) {
                            param.typeDefinition = SSType.DATETIMEOFFSET.toString() + "(" + outScale + ")";
                        } else {
                            param.typeDefinition = SSType.DATETIMEOFFSET.toString() + "(" + valueLength + ")";
                        }
                    } else {
                        param.typeDefinition = SSType.DATETIMEOFFSET.toString();
                    }
                    break;

                case LONGVARCHAR:
                case CLOB:
                    param.typeDefinition = VARCHAR_MAX;
                    break;

                case CHAR:
                case VARCHAR:
                    // To avoid the server side cost of re-preparing, once a "long" type, always a "long" type...
                    if (VARCHAR_MAX.equals(param.typeDefinition) || TEXT.equals(param.typeDefinition))
                        break;

                    // Adding for case useColumnEncryption=true & sendStringParametersAsUnicode=false
                    if (param.shouldHonorAEForParameter && (null != jdbcTypeSetByUser)
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {
                        /*
                         * This means AE is ON in the connection, and (1) this is either the first round to SQL Server
                         * to get encryption meta data, or (2) this is the second round of renewing meta data and
                         * parameter is encrypted In both of these cases we need to send specific type info, otherwise
                         * generic type info can be used as before.
                         */
                        if (0 == valueLength) {
                            // Workaround for the issue when inserting empty string and null into encrypted columns
                            param.typeDefinition = "varchar(1)";
                            valueLength++;
                        } else {
                            param.typeDefinition = "varchar(" + valueLength + ")";

                            if (DataTypes.SHORT_VARTYPE_MAX_BYTES <= valueLength) {
                                param.typeDefinition = VARCHAR_MAX;
                            }
                        }
                    } else
                        param.typeDefinition = VARCHAR_8K;
                    break;

                case LONGNVARCHAR:
                    if (param.shouldHonorAEForParameter
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {
                        /*
                         * This means AE is ON in the connection, and (1) this is either the first round to SQL Server
                         * to get encryption meta data, or (2) this is the second round of renewing meta data and
                         * parameter is encrypted In both of these cases we need to send specific type info, otherwise
                         * generic type info can be used as before.
                         */
                        if ((null != jdbcTypeSetByUser)
                                && ((jdbcTypeSetByUser == JDBCType.VARCHAR) || (jdbcTypeSetByUser == JDBCType.CHAR)
                                        || (jdbcTypeSetByUser == JDBCType.LONGVARCHAR))) {
                            if (0 == valueLength) {
                                // Workaround for the issue when inserting empty string and null into encrypted columns
                                param.typeDefinition = "varchar(1)";
                                valueLength++;
                            } else if (DataTypes.SHORT_VARTYPE_MAX_BYTES < valueLength) {
                                param.typeDefinition = VARCHAR_MAX;
                            } else {
                                param.typeDefinition = "varchar(" + valueLength + ")";
                            }

                            if (jdbcTypeSetByUser == JDBCType.LONGVARCHAR) {
                                param.typeDefinition = VARCHAR_MAX;
                            }
                        } else if ((null != jdbcTypeSetByUser) && (jdbcTypeSetByUser == JDBCType.NVARCHAR
                                || jdbcTypeSetByUser == JDBCType.LONGNVARCHAR)) {
                            if (0 == valueLength) {
                                // Workaround for the issue when inserting empty string and null into encrypted columns
                                param.typeDefinition = "nvarchar(1)";
                                valueLength++;
                            } else if (DataTypes.SHORT_VARTYPE_MAX_CHARS < valueLength) {
                                param.typeDefinition = NVARCHAR_MAX;
                            } else {
                                param.typeDefinition = "nvarchar(" + valueLength + ")";
                            }

                            if (jdbcTypeSetByUser == JDBCType.LONGNVARCHAR) {
                                param.typeDefinition = NVARCHAR_MAX;
                            }
                        } else { // used if setNull() is called with java.sql.Types.NCHAR
                            if (0 == valueLength) {
                                // Workaround for the issue when inserting empty string and null into encrypted columns
                                param.typeDefinition = "nvarchar(1)";
                                valueLength++;
                            } else {
                                param.typeDefinition = "nvarchar(" + valueLength + ")";

                                if (DataTypes.SHORT_VARTYPE_MAX_BYTES <= valueLength) {
                                    param.typeDefinition = NVARCHAR_MAX;
                                }
                            }
                        }
                        break;
                    } else
                        param.typeDefinition = NVARCHAR_MAX;
                    break;

                case NCLOB:
                    // do not need to check if AE is enabled or not,
                    // because NCLOB does not work with it
                    param.typeDefinition = NVARCHAR_MAX;
                    break;

                case NCHAR:
                case NVARCHAR:
                    // To avoid the server side cost of re-preparing, once a "long" type, always a "long" type...
                    if (NVARCHAR_MAX.equals(param.typeDefinition) || NTEXT.equals(param.typeDefinition))
                        break;

                    if (param.shouldHonorAEForParameter
                            && !(null == param.getCryptoMetadata() && param.renewDefinition)) {
                        /*
                         * This means AE is ON in the connection, and (1) this is either the first round to SQL Server
                         * to get encryption meta data, or (2) this is the second round of renewing meta data and
                         * parameter is encrypted In both of these cases we need to send specific type info, otherwise
                         * generic type info can be used as before.
                         */
                        if ((null != jdbcTypeSetByUser)
                                && ((jdbcTypeSetByUser == JDBCType.VARCHAR) || (jdbcTypeSetByUser == JDBCType.CHAR)
                                        || (JDBCType.LONGVARCHAR == jdbcTypeSetByUser))) {
                            if (0 == valueLength) {
                                // Workaround for the issue when inserting empty string and null into encrypted columns
                                param.typeDefinition = "varchar(1)";
                                valueLength++;
                            } else {
                                param.typeDefinition = "varchar(" + valueLength + ")";

                                if (DataTypes.SHORT_VARTYPE_MAX_BYTES < valueLength) {
                                    param.typeDefinition = VARCHAR_MAX;
                                }
                            }

                            if (JDBCType.LONGVARCHAR == jdbcTypeSetByUser) {
                                param.typeDefinition = VARCHAR_MAX;
                            }
                        } else if ((null != jdbcTypeSetByUser)
                                && ((jdbcTypeSetByUser == JDBCType.NVARCHAR) || (jdbcTypeSetByUser == JDBCType.NCHAR)
                                        || (JDBCType.LONGNVARCHAR == jdbcTypeSetByUser))) {
                            if (0 == valueLength) {
                                // Workaround for the issue when inserting empty string and null into encrypted columns
                                param.typeDefinition = "nvarchar(1)";
                                valueLength++;
                            } else {
                                param.typeDefinition = "nvarchar(" + valueLength + ")";

                                if (DataTypes.SHORT_VARTYPE_MAX_BYTES <= valueLength) {
                                    param.typeDefinition = NVARCHAR_MAX;
                                }
                            }

                            if (JDBCType.LONGNVARCHAR == jdbcTypeSetByUser) {
                                param.typeDefinition = NVARCHAR_MAX;
                            }
                        } else { // used if setNull() is called with java.sql.Types.NCHAR
                            if (0 == valueLength) {
                                // Workaround for the issue when inserting empty string and null into encrypted columns
                                param.typeDefinition = "nvarchar(1)";
                                valueLength++;
                            } else {
                                param.typeDefinition = "nvarchar(" + valueLength + ")";

                                if (DataTypes.SHORT_VARTYPE_MAX_BYTES <= valueLength) {
                                    param.typeDefinition = NVARCHAR_MAX;
                                }
                            }
                        }
                        break;
                    } else
                        param.typeDefinition = NVARCHAR_4K;
                    break;
                case SQLXML:
                    param.typeDefinition = SSType.XML.toString();
                    break;

                case TVP:
                    // definition should contain the TVP name and the keyword READONLY
                    String schema = param.schemaName;

                    if (null != schema) {
                        param.typeDefinition = "[" + schema + "].[" + param.name + "] READONLY";
                    } else {
                        param.typeDefinition = "[" + param.name + "] READONLY";
                    }

                    break;

                case GUID:
                    param.typeDefinition = SSType.GUID.toString();
                    break;

                case SQL_VARIANT:
                    param.typeDefinition = SSType.SQL_VARIANT.toString();
                    break;

                case GEOMETRY:
                    param.typeDefinition = SSType.GEOMETRY.toString();
                    break;

                case GEOGRAPHY:
                    param.typeDefinition = SSType.GEOGRAPHY.toString();
                    break;
                default:
                    assert false : "Unexpected JDBC type " + dtv.getJdbcType();
                    break;
            }
        }