-
Notifications
You must be signed in to change notification settings - Fork 429
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
Arithmetic operations with decimals return incorrect results #2189
Comments
Hi @OS-veracardoso, For driver versions up until 12.2, and for version 12.4 onwards, This same information can be found in our docs here. Please let us know if you have any further questions or concerns. |
Hi @Jeffery-Wasty ,
|
What happens if you explicitly pass in precision and scale as below?
|
Hi @Jeffery-Wasty, |
I confused Even when precision and scale are correctly for the value, unless they are passed in with |
Hi @Jeffery-Wasty the application we use supports multiple drivers, so the prepared statement logic is kind of abstract and only uses the available signatures, so we cannot do the cast that you suggest. |
Even when the precision and scale are set correctly in the BigDecimal being passed in, we still require it to be explicitly passed in. Attempting to parse the BigDecimal to get precision/scale leads to major performance impact with the JDBC driver. If its not possible to use We're investigating whether there is another way to proceed with this situation. |
@OS-veracardoso The mssql-jdbc driver's behaviour regarding precision and scale closely mirrors JTDS. And, from when I last checked, JTDS behaves similarily if precision and scale isn't explictily supplied. If this is working for you with other JDBC drivers, likely the mssql-jdbc might be wrong or missing some logic. What are the other drivers you are using in your application? |
I've setup a MySQL DB + mysql-connector-j driver to compare, and it looks like MySQL is behaving correctly. The math operations come out correct despite not explicitly specifying the precision and scale for the prepared statement. We'll need to do more research and compare the mssql-jdbc driver to MySQL's mysql-connector-j driver. |
Yes, if you try with Oracle, it also returns the expected result. |
It works as expected using mysql and oracle JDBC drivers, for instance. This was also working with the previous version of mssql driver. We notice this regression while trying to upgrade to the latest version and our tests started to fail. |
apologies for the delay in response we've been busy with getting ready for a hotfix release. You are correct this had worked in a previous version of the driver however we backed out of the fix in #1928 when we discovered there was a performance issue with the fix. The issue is that there is no way for the driver to know what the underlying precision/scale is without contacting the server and that would impact performance. We will investigate further to see how this is accomplished by other drivers. |
@lilgreenbird Thank you. |
Hi @OS-veracardoso, In addition to the testing we did previously with our own driver, we looked into jTDS and the MySQL Java connector. For jTDS, it behaves the same as the JDBC driver, producing similar arithmetic errors. For the MySQL connector, they are using a similar approach to what we did in 12.2, being able to parse the BigDecimal to fetch precision and scale from there. We're not sure what kind of performance impact this introduces to the driver, but the same approach in the JDBC driver caused a noticeable performance impact. We tried to find a way that precision could be updated for the parameter type definition without recreating the whole execution plan (the reason for the performance impact) but were unable to do so. For the time being, we ask that you consider using the 12.2 version of the driver, as that version has the BigDecimal fixes you are interested in. A potential enhancement to the driver could include a connection property to restore previous BigDecimal behavior, at the cost of performance. We'll keep this issue open while that option is still in consideration/development. |
Hello, Example1:
Example 2:
Example 3:
Example 4:
We also realized that the precision with decimal division changed. For isntance, the query
|
@OS-veracardoso For the latest preview release |
Hi @OS-veracardoso, I will take another look, but the code is identical to 12.3.1 (with the added condition being that the connection property must be set). If you're able to confirm that the preview release, 12.5.0, is not working the same as the former version, 12.3.1, with the connection property enabled, that would be something we would need to resolve. |
Hi @Jeffery-Wasty, @tkyc, Adding the mentioned property to the connection string works as expected. Thank you for your help. |
Hello, this is now happening again in version |
Hi @OS-veracardoso, We changed the name to |
Hi @Jeffery-Wasty, thanks. It is working now. |
Driver version
12.4.0.jre11
SQL Server version
Client Operating System
Ubuntu on Windows version 2004.2022.1.0
JAVA/JVM version
1.17
Table schema
Problem description
This new version of the driver introduces some changes on how arithmetic operations with decimals work.
For a better understanding consider the follwing examples.
Sum of 3 big decimals with different precision rounds the value to the closest integer:
Query:
SELECT ? + ? + ? TABLE_EXAMPLE WHERE "ID" = 4
Dynamic Parameters:
new BigDecimal("4")
,new BigDecimal("5")
andnew BigDecimal("3.14")
Expected Result:
5.86
Actual Result:
6
Multiplication followed by a Subtraction of 3 big decimals with different precision returns a decimal without precision:
Query:
SELECT ? * ? - ? FROM TABLE_EXAMPLE WHERE "ID" = 4
Dynamic Parameters:
new BigDecimal("4")
,new BigDecimal("2")
andnew BigDecimal("1.00")
Expected Result:
7.00
Actual Result:
7
Subtraction of 2 big decimals rounds the result to the closest integer:
Query:
SELECT ? - ? FROM TABLE_EXAMPLE WHERE "ID" = 4
Dynamic Parameters:
new BigDecimal("4.0")
andnew BigDecimal("3.14")
Expected Result:
0.86
Actual Result:
1
Subtraction of 2 big decimals round the result to a decimal with the lowest precision:
Example 1
Query:
SELECT ? - ? TABLE_EXAMPLE WHERE "ID" = 4
Dynamic Parameters:
new BigDecimal("4.0")
andnew BigDecimal("3.14")
Expected Result:
0.86
Actual Result:
0.9
Example 2
Query:
SELECT ? - ? TABLE_EXAMPLE WHERE "ID" = 4]
Dynamic Parameters:
new BigDecimal("1.23")
andnew BigDecimal("1.2")
Expected Result:
0.03
Actual Result:
0.0
Incorrect precision when using CAST
Example 1
Query:
SELECT ? - CAST("COL_INT" AS DECIMAL(38, 2) FROM TABLE_EXAMPLE WHERE "ID" = 4
Dynamic Parameters:
new BigDecimal("0.00")
Expected Result:
0.00
Actual Result:
0
Example 2
Query:
SELECT ? - CAST("COL_BIGINT" AS DECIMAL(38, 2) FROM TABLE_EXAMPLE WHERE "ID" = 4
Dynamic Parameters:
new BigDecimal("-3996.00")
Expected Result:
-3996.00
Actual Result:
-3996
Example 3
Query:
SELECT ? - "COL_DECIMAL" FROM TABLE_EXAMPLE WHERE "ID" = 4
Dynamic Parameters:
new BigDecimal("-3996.00")
Expected Result:
-8.34000000
Actual Result:
-8
Error message/stack trace
Not applicable. The driver returns no error. The result though is no the expected one.
The text was updated successfully, but these errors were encountered: