Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes issue with PreparedStatement.setBigDecimal() in the driver when no scale is passed #684

Merged
merged 9 commits into from
May 2, 2018
17 changes: 13 additions & 4 deletions src/main/java/com/microsoft/sqlserver/jdbc/dtv.java
Original file line number Diff line number Diff line change
Expand Up @@ -2212,11 +2212,20 @@ void execute(DTV dtv,
BigDecimal bigDecimalValue) throws SQLServerException {
// Rescale the value if necessary
if (null != bigDecimalValue) {
Integer inScale = dtv.getScale();
if (null != inScale && inScale != bigDecimalValue.scale())
bigDecimalValue = bigDecimalValue.setScale(inScale, RoundingMode.DOWN);
Integer dtvScale, biScale = bigDecimalValue.scale();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please apply the formatter, otherwise looks good!

if (null == dtv.getScale() && JDBCType.DECIMAL==dtv.getJdbcType()) {
dtvScale = bigDecimalValue.precision() > SQLServerConnection.maxDecimalPrecision ?
SQLServerConnection.maxDecimalPrecision - (bigDecimalValue.precision() - biScale) : biScale;
if(dtvScale > SQLServerConnection.maxDecimalPrecision) {
dtv.setScale(SQLServerConnection.maxDecimalPrecision);
dtvScale = SQLServerConnection.maxDecimalPrecision;
}else {
dtv.setScale(dtvScale);
}
}else dtvScale = dtv.getScale();
if (dtvScale!=null && dtvScale != biScale)
bigDecimalValue = bigDecimalValue.setScale(dtvScale, RoundingMode.DOWN);
}

dtv.setValue(bigDecimalValue, JavaType.BIGDECIMAL);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public void testJdbc41ResultSetMethods() throws SQLException {
+ "col12 time, "
+ "col13 datetime2, "
+ "col14 datetimeoffset, "
+ "col15 decimal(10,9), "
+ "col16 decimal(38,38), "
+ "order_column int identity(1,1) primary key)");
try {

Expand All @@ -80,7 +82,9 @@ public void testJdbc41ResultSetMethods() throws SQLException {
+ "'2017-05-19'," // col11
+ "'10:47:15.1234567'," // col12
+ "'2017-05-19T10:47:15.1234567'," // col13
+ "'2017-05-19T10:47:15.1234567+02:00'" // col14
+ "'2017-05-19T10:47:15.1234567+02:00'," // col14
+ "0.123456789, " // col15
+ "0.1234567890123456789012345678901234567" // col16
+ ")");

stmt.executeUpdate("Insert into " + tableName + " values("
Expand All @@ -97,6 +101,8 @@ public void testJdbc41ResultSetMethods() throws SQLException {
+ "null, "
+ "null, "
+ "null, "
+ "null, "
+ "null, "
+ "null)");

try (ResultSet rs = stmt.executeQuery("select * from " + tableName + " order by order_column")) {
Expand Down Expand Up @@ -176,7 +182,13 @@ public void testJdbc41ResultSetMethods() throws SQLException {

assertEquals("2017-05-19 10:47:15.1234567 +02:00", rs.getObject(14, microsoft.sql.DateTimeOffset.class).toString());
assertEquals("2017-05-19 10:47:15.1234567 +02:00", rs.getObject("col14", microsoft.sql.DateTimeOffset.class).toString());


// BigDecimal#equals considers the number of decimal places (ResultSet returns all digits after decimal unlike CallableStatement outparams)
assertEquals(0, rs.getObject(15, BigDecimal.class).compareTo(new BigDecimal("0.123456789")));
assertEquals(0, rs.getObject("col15", BigDecimal.class).compareTo(new BigDecimal("0.123456789")));

assertEquals(0, rs.getObject(16, BigDecimal.class).compareTo(new BigDecimal("0.12345678901234567890123456789012345670")));
assertEquals(0, rs.getObject("col16", BigDecimal.class).compareTo(new BigDecimal("0.12345678901234567890123456789012345670")));

// test null values, mostly to verify primitive wrappers do not return default values
assertTrue(rs.next());
Expand Down Expand Up @@ -232,6 +244,12 @@ public void testJdbc41ResultSetMethods() throws SQLException {
assertNull(rs.getObject(14, microsoft.sql.DateTimeOffset.class));
assertNull(rs.getObject("col14", microsoft.sql.DateTimeOffset.class));

assertNull(rs.getObject(15, BigDecimal.class));
assertNull(rs.getObject("col15", BigDecimal.class));

assertNull(rs.getObject(16, BigDecimal.class));
assertNull(rs.getObject("col16", BigDecimal.class));

assertFalse(rs.next());
}
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ private static void checkNumericMetaData() throws SQLException {

ParameterMetaData pmd = pstmt.getParameterMetaData();

assertEquals(pmd.getParameterCount(), 13, "Not all parameters are recognized by driver.");
assertEquals(pmd.getParameterCount(), 15, "Not all parameters are recognized by driver.");

compareParameterMetaData(pmd, 1, "java.math.BigDecimal", 3, "decimal", 18, 0);
compareParameterMetaData(pmd, 2, "java.math.BigDecimal", 3, "decimal", 10, 5);
Expand All @@ -242,6 +242,8 @@ private static void checkNumericMetaData() throws SQLException {
compareParameterMetaData(pmd, 11, "java.lang.Short", -6, "tinyint", 3, 0);
compareParameterMetaData(pmd, 12, "java.math.BigDecimal", 3, "money", 19, 4);
compareParameterMetaData(pmd, 13, "java.math.BigDecimal", 3, "smallmoney", 10, 4);
compareParameterMetaData(pmd, 14, "java.math.BigDecimal", 3, "decimal", 10, 9);
compareParameterMetaData(pmd, 15, "java.math.BigDecimal", 3, "decimal", 38, 37);
}

private static void checkCharMetaData(int expectedParameterCount) throws SQLException {
Expand Down Expand Up @@ -337,7 +339,7 @@ private static void compareParameterMetaData(ParameterMetaData pmd,

private static void populateNumericTable() throws SQLException {
stmt.execute("insert into " + numericTable + " values (" + "1.123," + "1.123," + "1.2345," + "1.2345," + "1.543," + "1.543," + "5.1234,"
+ "104935," + "34323," + "123," + "5," + "1.45," + "1.3" + ")");
+ "104935," + "34323," + "123," + "5," + "1.45," + "1.3," + "0.123456789," + "0.1234567890123456789012345678901234567" + ")");
}

private static void testBeforeExcute() throws SQLException {
Expand All @@ -346,7 +348,7 @@ private static void testBeforeExcute() throws SQLException {
}

String sql = "select * from " + numericTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + "c4 = ? and " + "c5 = ? and "
+ "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ? ";
+ "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ? and " + "c14 = ? and " + "c15 = ? ";

pstmt = connection.prepareStatement(sql);

Expand All @@ -359,11 +361,11 @@ private static void testBeforeExcute() throws SQLException {

private static void selectNumeric() throws SQLException {
String sql = "select * from " + numericTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + "c4 = ? and " + "c5 = ? and "
+ "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ? ";
+ "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ? and " + "c14 = ? and " + "c15 = ? ";

pstmt = connection.prepareStatement(sql);

for (int i = 1; i <= 13; i++) {
for (int i = 1; i <= 15; i++) {
pstmt.setString(i, "1");
}

Expand All @@ -372,12 +374,11 @@ private static void selectNumeric() throws SQLException {

private static void insertNumeric() throws SQLException {

String sql = "insert into " + numericTable + " values( " + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?,"
+ "?" + ")";
String sql = "insert into " + numericTable + " values( " + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?" + ")";

pstmt = connection.prepareStatement(sql);

for (int i = 1; i <= 13; i++) {
for (int i = 1; i <= 15; i++) {
pstmt.setString(i, "1");
}

Expand All @@ -387,11 +388,11 @@ private static void insertNumeric() throws SQLException {
private static void updateNumeric() throws SQLException {

String sql = "update " + numericTable + " set " + "c1 = ?," + "c2 = ?," + "c3 = ?," + "c4 = ?," + "c5 = ?," + "c6 = ?," + "c7 = ?,"
+ "c8 = ?," + "c9 = ?," + "c10 = ?," + "c11 = ?," + "c12 = ?," + "c13 = ?" + ";";
+ "c8 = ?," + "c9 = ?," + "c10 = ?," + "c11 = ?," + "c12 = ?," + "c13 = ?," + "c14 = ?," + "c15 = ?" + ";";

pstmt = connection.prepareStatement(sql);

for (int i = 1; i <= 13; i++) {
for (int i = 1; i <= 15; i++) {
pstmt.setString(i, "1");
}

Expand All @@ -401,11 +402,11 @@ private static void updateNumeric() throws SQLException {
private static void deleteNumeric() throws SQLException {

String sql = "delete from " + numericTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + "c4 = ? and " + "c5 = ? and "
+ "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ?" + ";";
+ "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ? and " + "c14 = ? and " + "c15 = ?" + ";";

pstmt = connection.prepareStatement(sql);

for (int i = 1; i <= 13; i++) {
for (int i = 1; i <= 15; i++) {
pstmt.setString(i, "1");
}

Expand All @@ -416,8 +417,8 @@ private static void createNumericTable() throws SQLException {

stmt.execute("Create table " + numericTable + " (" + "c1 decimal not null," + "c2 decimal(10,5) not null," + "c3 numeric not null,"
+ "c4 numeric(8,4) not null," + "c5 float not null," + "c6 float(10) not null," + "c7 real not null," + "c8 int not null,"
+ "c9 bigint not null," + "c10 smallint not null," + "c11 tinyint not null," + "c12 money not null," + "c13 smallmoney not null"
+ ")");
+ "c9 bigint not null," + "c10 smallint not null," + "c11 tinyint not null," + "c12 money not null," + "c13 smallmoney not null,"
+ "c14 decimal(10,9) not null," + "c15 decimal(38,37) not null" + ")");
}

private static void createCharTable() throws SQLException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1206,17 +1206,19 @@ public void testJdbc41CallableStatementMethods() throws Exception {
+ " @col3Value float OUTPUT," + " @col4Value decimal(10,5) OUTPUT," + " @col5Value uniqueidentifier OUTPUT,"
+ " @col6Value xml OUTPUT," + " @col7Value varbinary(max) OUTPUT," + " @col8Value text OUTPUT," + " @col9Value ntext OUTPUT,"
+ " @col10Value varbinary(max) OUTPUT," + " @col11Value date OUTPUT," + " @col12Value time OUTPUT,"
+ " @col13Value datetime2 OUTPUT," + " @col14Value datetimeoffset OUTPUT" + " AS BEGIN " + " SET @col1Value = 'hello'"
+ " @col13Value datetime2 OUTPUT," + " @col14Value datetimeoffset OUTPUT," + " @col15Value decimal(10,10) OUTPUT," + " @col16Value decimal(38,38) OUTPUT"
+ " AS BEGIN " + " SET @col1Value = 'hello'"
+ " SET @col2Value = 1" + " SET @col3Value = 2.0" + " SET @col4Value = 123.45"
+ " SET @col5Value = '6F9619FF-8B86-D011-B42D-00C04FC964FF'" + " SET @col6Value = '<test/>'"
+ " SET @col7Value = 0x63C34D6BCAD555EB64BF7E848D02C376" + " SET @col8Value = 'text'" + " SET @col9Value = 'ntext'"
+ " SET @col10Value = 0x63C34D6BCAD555EB64BF7E848D02C376" + " SET @col11Value = '2017-05-19'"
+ " SET @col12Value = '10:47:15.1234567'" + " SET @col13Value = '2017-05-19T10:47:15.1234567'"
+ " SET @col14Value = '2017-05-19T10:47:15.1234567+02:00'" + " END";
+ " SET @col14Value = '2017-05-19T10:47:15.1234567+02:00'" + " SET @col15Value = 0.123456789"
+ " SET @col16Value = 0.1234567890123456789012345678901234567" + " END";
stmt.execute(query);

// Test JDBC 4.1 methods for CallableStatement
try (CallableStatement cstmt = conn.prepareCall("{call " + procName + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}")) {
try (CallableStatement cstmt = conn.prepareCall("{call " + procName + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}")) {
cstmt.registerOutParameter(1, java.sql.Types.VARCHAR);
cstmt.registerOutParameter(2, java.sql.Types.INTEGER);
cstmt.registerOutParameter(3, java.sql.Types.FLOAT);
Expand All @@ -1231,6 +1233,8 @@ public void testJdbc41CallableStatementMethods() throws Exception {
cstmt.registerOutParameter(12, java.sql.Types.TIME);
cstmt.registerOutParameter(13, java.sql.Types.TIMESTAMP);
cstmt.registerOutParameter(14, java.sql.Types.TIMESTAMP_WITH_TIMEZONE);
cstmt.registerOutParameter(15, java.sql.Types.DECIMAL);
cstmt.registerOutParameter(16, java.sql.Types.DECIMAL);
cstmt.execute();

assertEquals("hello", cstmt.getObject(1, String.class));
Expand Down Expand Up @@ -1302,6 +1306,13 @@ public void testJdbc41CallableStatementMethods() throws Exception {

assertEquals("2017-05-19 10:47:15.1234567 +02:00", cstmt.getObject(14, microsoft.sql.DateTimeOffset.class).toString());
assertEquals("2017-05-19 10:47:15.1234567 +02:00", cstmt.getObject("col14Value", microsoft.sql.DateTimeOffset.class).toString());

// BigDecimal#equals considers the number of decimal places (OutParams always return 4 decimal digits rounded up)
assertEquals(0, cstmt.getObject(15, BigDecimal.class).compareTo(new BigDecimal("0.1235")));
assertEquals(0, cstmt.getObject("col15Value", BigDecimal.class).compareTo(new BigDecimal("0.1235")));

assertEquals(0, cstmt.getObject(16, BigDecimal.class).compareTo(new BigDecimal("0.1235")));
assertEquals(0, cstmt.getObject("col16Value", BigDecimal.class).compareTo(new BigDecimal("0.1235")));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public SqlDecimal() {
// called for decimal and numeric type
SqlDecimal(String name,
JDBCType jdbctype) {
this(name, jdbctype, 38, 0, SqlTypeValue.DECIMAL.minValue, SqlTypeValue.DECIMAL.maxValue, VariableLengthType.Scale);
this(name, jdbctype, SqlTypeValue.MAX_DECIMAL_PRECISION, 0, SqlTypeValue.DECIMAL.minValue, SqlTypeValue.DECIMAL.maxValue, VariableLengthType.Scale);
}

// called from money/smallmoney
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ enum SqlTypeValue {
Object minValue;
Object maxValue;
Object nullValue;


static final int MAX_DECIMAL_PRECISION = 38;

SqlTypeValue(Object minValue, Object maxValue, Object nullValue) {
this.minValue = minValue;
this.maxValue = maxValue;
Expand Down