Skip to content

Commit

Permalink
Merge pull request #684 from cheenamalhotra/bigdecimal-issue
Browse files Browse the repository at this point in the history
Fixes issue with PreparedStatement.setBigDecimal() in the driver when no scale is passed
  • Loading branch information
cheenamalhotra authored May 2, 2018
2 parents 4a9c840 + b9062ba commit 55bc4a0
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 25 deletions.
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();
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

0 comments on commit 55bc4a0

Please sign in to comment.