Skip to content

Commit

Permalink
Revert #2051 (Big decimal precision) / #2116 (Fix for bigDecimal valu…
Browse files Browse the repository at this point in the history
…es between 0 and 1 having too high of a precision) (#2176)

* Revert big decimal changes

* Delete TestClass.java

* Delete RetryLogicProvider.java

* Update Parameter.java
  • Loading branch information
Jeffery-Wasty authored Jul 26, 2023
1 parent ee172ab commit 46a0fb0
Show file tree
Hide file tree
Showing 2 changed files with 2 additions and 251 deletions.
31 changes: 2 additions & 29 deletions src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -531,36 +531,9 @@ private void setTypeDefinition(DTV dtv) {
param.typeDefinition = SSType.DECIMAL.toString() + "(" + valueLength + "," + scale + ")";
}
} else {
if (dtv.getJavaType() == JavaType.BIGDECIMAL && null != dtv.getSetterValue()) {
String[] plainValueArray
= ((BigDecimal) dtv.getSetterValue()).abs().toPlainString().split("\\.");

// Precision is computed as opposed to using BigDecimal.precision(). This is because the
// BigDecimal method can lead to inaccurate results.
int calculatedPrecision;

// If the string array has two parts, e.g .the input was a decimal, check if the first
// part is a 0. For BigDecimals with leading zeroes, the leading zero does not count towards
// precision. For all other decimals, we include the integer portion as part of the precision
// When the string array has just one part, we only look at that part to compute precision.
if (plainValueArray.length == 2) {
if (plainValueArray[0].length() == 1 && (Integer.parseInt(plainValueArray[0]) == 0)) {
calculatedPrecision = plainValueArray[1].length();
} else {
calculatedPrecision = plainValueArray[0].length() + plainValueArray[1].length();
}
} else {
calculatedPrecision = plainValueArray[0].length();
}

param.typeDefinition = SSType.DECIMAL.toString() + "(" + calculatedPrecision + "," +
(plainValueArray.length == 2 ? plainValueArray[1].length() : 0) + ")";
} else {
param.typeDefinition = SSType.DECIMAL.toString() + "("
+ SQLServerConnection.MAX_DECIMAL_PRECISION + "," + scale + ")";
}
param.typeDefinition = SSType.DECIMAL.toString() + "("
+ SQLServerConnection.MAX_DECIMAL_PRECISION + "," + scale + ")";
}

break;

case MONEY:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1426,228 +1426,6 @@ public void testFailedToResumeTransaction() throws Exception {
}
}

/**
* Tests that big decimal values with a precision less than 38 hold their precision. Tests cases where scale is
* 38 (integer part is a 0) and less than 38 (integer part is a non-zero).
*
* @throws SQLException
* when an error occurs
*/
@Test
public void testSmallBigDecimalValuesForLossOfPrecision() throws SQLException {
try (Connection con = getConnection();
Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE)) {
double bigDecimalLessThanOne = 0.1235;
double bigDecimalGreaterThanOne = 1.1235;
String query = "CREATE PROCEDURE " + procName
+ " @col1Value decimal(4,4) OUTPUT, @col2Value decimal(5,4) OUTPUT AS BEGIN SET @col1Value = "
+ bigDecimalLessThanOne + " SET @col2Value = " + bigDecimalGreaterThanOne + " END";
stmt.execute(query);

try (CallableStatement cstmt = con.prepareCall("{CALL " + procName + "(?, ?)}")) {
cstmt.registerOutParameter("col1Value", java.sql.Types.DECIMAL, "DECIMAL");
cstmt.registerOutParameter("col2Value", java.sql.Types.DECIMAL, "DECIMAL");
cstmt.execute();

// Previously, the leading 0 would be counted as part of the precision. This would lead to the actual
// value being stored as 0.123.
assertEquals(0,
cstmt.getObject("col1Value", BigDecimal.class).compareTo(BigDecimal.valueOf(bigDecimalLessThanOne)));
assertEquals(0,
cstmt.getObject("col2Value", BigDecimal.class).compareTo(BigDecimal.valueOf(bigDecimalGreaterThanOne)));
}
}
}

/**
* Tests that big decimal values with a precision equal to 38 hold their precision. Tests cases where scale is
* 38 (integer part is a 0) and less than 38 (integer part is a non-zero).
*
* @throws SQLException
* when an error occurs
*/
@Test
public void testLongBigDecimalValuesForLossOfPrecision() throws SQLException {
try (Connection con = getConnection(); Statement stmt = con.createStatement()) {
stmt.executeUpdate("CREATE TABLE " + tableName + " (col1 decimal(38,38), col2 decimal(38,37))");

// col1 has maximum scale (38) with a leading zero, for a precision of 38. col2 has maximum scale (37) when
// using a lead integer other than zero, also resulting in a precision of 38.
stmt.executeUpdate("INSERT INTO " + tableName + " VALUES(0.98432319763138435186412316842316874322, 1.9843231976313843518641231684231687432)");

try (PreparedStatement pstmt = con.prepareStatement("SELECT * FROM " + tableName)) {

try (ResultSet rs = pstmt.executeQuery()) {
rs.next();
assertEquals(new BigDecimal("0.98432319763138435186412316842316874322"), rs.getObject(1));
assertEquals(new BigDecimal("1.9843231976313843518641231684231687432"), rs.getObject(2));
}
}
}
}

/**
* Tests result of math operation in prepared statement using subtraction
*
* @throws SQLException
* when an error occurs
*/
@Test
public void testMathBigDecimalSubtraction() throws SQLException {
try (Connection con = getConnection(); Statement stmt = con.createStatement()) {
stmt.executeUpdate("CREATE TABLE " + tableName + " (test_column decimal(10,5))");
stmt.executeUpdate("INSERT INTO " + tableName + " VALUES(99999.12345)");
try (PreparedStatement pstmt = con.prepareStatement("SELECT (test_column - ?), "
+ "(test_column - ?), (test_column - ?), (test_column - ?) FROM " + tableName)) {
BigDecimal value1 = new BigDecimal("1.5");
pstmt.setObject(1, value1);
BigDecimal value2 = new BigDecimal("0");
pstmt.setObject(2, value2);
BigDecimal value3 = new BigDecimal("99999.12345");
pstmt.setObject(3, value3);
BigDecimal value4 = new BigDecimal("99999.2");
pstmt.setObject(4, value4);

BigDecimal base = new BigDecimal("99999.12345");
BigDecimal expected1 = base.subtract(value1);
BigDecimal expected2 = base.subtract(value2);
BigDecimal expected3 = base.subtract(value3);
BigDecimal expected4 = base.subtract(value4);

try (ResultSet rs = pstmt.executeQuery()) {
rs.next();
assertEquals(expected1, rs.getObject(1));
assertEquals(expected2, rs.getObject(2));
assertEquals(expected3, rs.getObject(3));
assertEquals(expected4, rs.getObject(4));
}
}
}
}

/**
* Tests result of math operation in prepared statement using addition
*
* @throws SQLException
* when an error occurs
*/
@Test
public void testMathBigDecimalAddition() throws SQLException {
try (Connection con = getConnection(); Statement stmt = con.createStatement()) {
stmt.executeUpdate("CREATE TABLE " + tableName + " (test_column decimal(10,5))");
stmt.executeUpdate("INSERT INTO " + tableName + " VALUES(99999.12345)");
try (PreparedStatement pstmt = con.prepareStatement("SELECT (test_column + ?), "
+ "(test_column + ?), (test_column + ?), (test_column + ?) FROM " + tableName)) {
BigDecimal value1 = new BigDecimal("1.5");
pstmt.setObject(1, value1);
BigDecimal value2 = new BigDecimal("0");
pstmt.setObject(2, value2);
BigDecimal value3 = new BigDecimal("99999.12345");
pstmt.setObject(3, value3);
BigDecimal value4 = new BigDecimal("99999.2");
pstmt.setObject(4, value4);

BigDecimal base = new BigDecimal("99999.12345");
BigDecimal expected1 = base.add(value1);
BigDecimal expected2 = base.add(value2);
BigDecimal expected3 = base.add(value3);
BigDecimal expected4 = base.add(value4);

try (ResultSet rs = pstmt.executeQuery()) {
rs.next();
assertEquals(expected1, rs.getObject(1));
assertEquals(expected2, rs.getObject(2));
assertEquals(expected3, rs.getObject(3));
assertEquals(expected4, rs.getObject(4));
}
}
}
}

/**
* Tests result of math operation in prepared statement using multiplication
*
* @throws SQLException
* when an error occurs
*/
@Test
public void testMathBigDecimalMultiplication() throws SQLException {
try (Connection con = getConnection(); Statement stmt = con.createStatement()) {
stmt.executeUpdate("CREATE TABLE " + tableName + " (test_column decimal(10,5))");
stmt.executeUpdate("INSERT INTO " + tableName + " VALUES(99999.12345)");
try (PreparedStatement pstmt = con.prepareStatement("SELECT (test_column * ?), "
+ "(test_column * ?), (test_column * ?), (test_column * ?) FROM " + tableName)) {
BigDecimal value1 = new BigDecimal("1.5");
pstmt.setObject(1, value1);
BigDecimal value2 = new BigDecimal("0");
pstmt.setObject(2, value2);
BigDecimal value3 = new BigDecimal("99999.12345");
pstmt.setObject(3, value3);
BigDecimal value4 = new BigDecimal("99999.2");
pstmt.setObject(4, value4);

BigDecimal base = new BigDecimal("99999.12345");
BigDecimal expected1 = base.multiply(value1);
BigDecimal expected2 = base.multiply(value2);
BigDecimal expected3 = base.multiply(value3);
BigDecimal expected4 = base.multiply(value4);

try (ResultSet rs = pstmt.executeQuery()) {
rs.next();
assertEquals(expected1, rs.getObject(1));
assertEquals(expected2, rs.getObject(2));
assertEquals(expected3, rs.getObject(3));
assertEquals(expected4, rs.getObject(4));
}
}
}
}

/**
* Tests result of math operation in prepared statement using division
*
* @throws SQLException
* when an error occurs
*/
@Test
public void testMathBigDecimalDivision() throws SQLException {
try (Connection con = getConnection(); Statement stmt = con.createStatement()) {
stmt.executeUpdate("CREATE TABLE " + tableName + " (test_column decimal(10,5))");
stmt.executeUpdate("INSERT INTO " + tableName + " VALUES(99999.12345)");
try (PreparedStatement pstmt = con.prepareStatement("select (test_column / ?), "
+ "(test_column / ?), (test_column / ?), (test_column / ?) FROM " + tableName)) {

/*
* Division has some unique properties in sql server math operations.
* Notably in this case we cannot compare a result with an infinite trailing decimal
* and the returned value has an expanded precision.
*/
BigDecimal value1 = new BigDecimal("1.5");
pstmt.setObject(1, value1);
BigDecimal value2 = new BigDecimal("0.1");
pstmt.setObject(2, value2);
BigDecimal value3 = new BigDecimal("99999.12345");
pstmt.setObject(3, value3);
BigDecimal value4 = new BigDecimal("1");
pstmt.setObject(4, value4);

BigDecimal base = new BigDecimal("99999.12345");
BigDecimal expected1 = base.divide(value1, RoundingMode.HALF_UP);
BigDecimal expected2 = base.divide(value2, RoundingMode.HALF_UP);
BigDecimal expected3 = base.divide(value3, RoundingMode.HALF_UP);
BigDecimal expected4 = base.divide(value4, RoundingMode.HALF_UP);

try (ResultSet rs = pstmt.executeQuery()) {
rs.next();
assertEquals(0, expected1.compareTo((BigDecimal) rs.getObject(1)));
assertEquals(0, expected2.compareTo((BigDecimal) rs.getObject(2)));
assertEquals(0, expected3.compareTo((BigDecimal) rs.getObject(3)));
assertEquals(0, expected4.compareTo((BigDecimal) rs.getObject(4)));
}
}
}
}

/**
*
* @throws Exception
Expand Down

0 comments on commit 46a0fb0

Please sign in to comment.