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

Stored procedure call returns wrong BigDecimal scale. #2559

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
88f389c
Stored procedure call returns wrong BigDecimal scale.
Ananya2 Dec 6, 2024
1afdc01
Removed try block
Ananya2 Dec 6, 2024
7edfbb5
Added try-catch block
Ananya2 Dec 6, 2024
95a8c7c
Updated testJdbc41CallableStatementMethods test case for BigDecimal c…
Ananya2 Dec 6, 2024
cfac904
Added test case to validate the BigDecimal precision.
Ananya2 Dec 9, 2024
547fbdb
Updated stored procedure statement test.
Ananya2 Dec 9, 2024
5ab3a87
Fixed pipeline failure
Ananya2 Dec 9, 2024
74cb96b
Added 'warning' level log in case of failure while fetching scale for…
Ananya2 Dec 9, 2024
3108729
throws SQLServerException
Ananya2 Dec 9, 2024
c5bd4f7
Throw SQLServerException on failure.
Ananya2 Dec 9, 2024
e8cb028
Added test case testRegisterOutParameterWithDecimalException
Ananya2 Dec 9, 2024
9474346
Fixed pipeline failure
Ananya2 Dec 9, 2024
a963b3a
Updated SQLServerCallableStatement.java
Ananya2 Dec 9, 2024
54cb79a
removed test case.
Ananya2 Dec 10, 2024
8522231
Removed unused import.
Ananya2 Dec 10, 2024
54b68c3
Created BigDecimalPrecisionTest.java file
Ananya2 Dec 10, 2024
f87ad13
Fix: Throw SQLServerException with detailed message for metadata retr…
Ananya2 Dec 11, 2024
e83f163
Add test for BigDecimal precision failure when fetching scale metadata.
Ananya2 Dec 11, 2024
63d0de2
Update SQLServerCallableStatement.java
Ananya2 Dec 11, 2024
075e11b
Update BigDecimalPrecisionTest.java
Ananya2 Dec 11, 2024
78bd95b
Drop stored procedure if it exists in init()
Ananya2 Dec 16, 2024
4f3c020
Update BigDecimalPrecisionTest.java
Ananya2 Dec 16, 2024
ebf5093
Added detailed comments to the `registerOutParameter` method to expla…
Ananya2 Dec 20, 2024
bf9df80
updated as per review comments
Ananya2 Jan 7, 2025
b2d7c07
fixed build failure
Ananya2 Jan 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.ParameterMetaData;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.util.Calendar;
Expand Down Expand Up @@ -150,6 +151,22 @@ public void registerOutParameter(int index, int sqlType) throws SQLServerExcepti
case microsoft.sql.Types.DATETIMEOFFSET:
param.setOutScale(7);
break;
case java.sql.Types.DECIMAL:
// Dynamically handle the scale for DECIMAL output parameters.
// The scale for the DECIMAL type is fetched from the ParameterMetaData.
// This provides flexibility to automatically apply the correct scale as per the database metadata.
ParameterMetaData parameterMetaData = this.getParameterMetaData();
if (parameterMetaData != null) {
try {
// Fetch scale from metadata for DECIMAL type
int scale = parameterMetaData.getScale(index);
param.setOutScale(scale);
} catch (SQLException e) {
loggerExternal.warning("Failed to fetch scale for DECIMAL type parameter at index " + index + ": " + e.getMessage());
Ananya2 marked this conversation as resolved.
Show resolved Hide resolved
throw new SQLServerException(SQLServerException.getErrString("R_InvalidScale"), null, 0, e);
}
}
break;
default:
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1195,15 +1195,14 @@ public void testJdbc41CallableStatementMethods() throws Exception {
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")));
// BigDecimal#equals considers the number of decimal places (OutParams always return full precision as specified in the DB schema)
assertEquals(0, cstmt.getObject(15, BigDecimal.class).compareTo(new BigDecimal("0.123456789")));
assertEquals(0,
cstmt.getObject("col15Value", BigDecimal.class).compareTo(new BigDecimal("0.1235")));
cstmt.getObject("col15Value", BigDecimal.class).compareTo(new BigDecimal("0.123456789")));

assertEquals(0, cstmt.getObject(16, BigDecimal.class).compareTo(new BigDecimal("0.1235")));
assertEquals(0, cstmt.getObject(16, BigDecimal.class).compareTo(new BigDecimal("0.1234567890123456789012345678901234567")));
assertEquals(0,
cstmt.getObject("col16Value", BigDecimal.class).compareTo(new BigDecimal("0.1235")));
cstmt.getObject("col16Value", BigDecimal.class).compareTo(new BigDecimal("0.1234567890123456789012345678901234567")));
}
}
}
Expand Down Expand Up @@ -2692,4 +2691,110 @@ public void terminate() throws Exception {
}
}
}

@Nested
@Tag(Constants.xAzureSQLDW)
public class BigDecimalPrecisionTest {

private final String procName1 = AbstractSQLGenerator
.escapeIdentifier(RandomUtil.getIdentifier("test_bigdecimal_3"));
private final String procName2 = AbstractSQLGenerator
.escapeIdentifier(RandomUtil.getIdentifier("test_bigdecimal_5"));
private final String procNameMaxScale = AbstractSQLGenerator
.escapeIdentifier(RandomUtil.getIdentifier("test_bigdecimal_max_scale"));
private final String procNameMaxPrecision = AbstractSQLGenerator
.escapeIdentifier(RandomUtil.getIdentifier("test_bigdecimal_max_precision"));

@BeforeEach
public void init() throws SQLException {
try (Connection connection = getConnection()) {
String dropProcedureSQL = "DROP PROCEDURE IF EXISTS " + procName1 + ", " + procName2 + ", "
+ procNameMaxScale + ", " + procNameMaxPrecision;
try (Statement stmt = connection.createStatement()) {
stmt.execute(dropProcedureSQL);
}

String createProcedureSQL1 = "CREATE PROCEDURE " + procName1 + "\n"
+ " @big_decimal_type decimal(15, 3),\n"
+ " @big_decimal_type_o decimal(15, 3) OUTPUT\n" + "AS\n" + "BEGIN\n"
+ " SET @big_decimal_type_o = @big_decimal_type;\n" + "END;";
String createProcedureSQL2 = "CREATE PROCEDURE " + procName2 + "\n"
+ " @big_decimal_type decimal(15, 5),\n"
+ " @big_decimal_type_o decimal(15, 5) OUTPUT\n" + "AS\n" + "BEGIN\n"
+ " SET @big_decimal_type_o = @big_decimal_type;\n" + "END;";
String createProcedureMaxScale = "CREATE PROCEDURE " + procNameMaxScale + "\n"
+ " @big_decimal_type decimal(38, 38),\n"
+ " @big_decimal_type_o decimal(38, 38) OUTPUT\n" + "AS\n" + "BEGIN\n"
+ " SET @big_decimal_type_o = @big_decimal_type;\n" + "END;";
String createProcedureMaxPrecision = "CREATE PROCEDURE " + procNameMaxPrecision + "\n"
+ " @big_decimal_type decimal(38, 0),\n"
+ " @big_decimal_type_o decimal(38, 0) OUTPUT\n" + "AS\n" + "BEGIN\n"
+ " SET @big_decimal_type_o = @big_decimal_type;\n" + "END;";

try (Statement stmt = connection.createStatement()) {
stmt.execute(createProcedureSQL1);
stmt.execute(createProcedureSQL2);
stmt.execute(createProcedureMaxScale);
stmt.execute(createProcedureMaxPrecision);
}
}
}

@AfterEach
public void terminate() throws SQLException {
try (Connection connection = getConnection()) {
try (Statement stmt = connection.createStatement()) {
String dropProcedureSQL = "DROP PROCEDURE IF EXISTS " + procName1 + ", " + procName2 + ", "
+ procNameMaxScale + ", " + procNameMaxPrecision;
stmt.execute(dropProcedureSQL);
}
}
}

@Test
@Tag("BigDecimal")
public void testBigDecimalPrecision() throws SQLException {
try (Connection connection = getConnection()) {
// Test for DECIMAL(15, 3)
String callSQL1 = "{call " + procName1 + "(100.241, ?)}";
try (CallableStatement call = connection.prepareCall(callSQL1)) {
call.registerOutParameter(1, Types.DECIMAL);
call.execute();
BigDecimal actual1 = call.getBigDecimal(1);
assertEquals(new BigDecimal("100.241"), actual1);
}

// Test for DECIMAL(15, 5)
String callSQL2 = "{call " + procName2 + "(100.24112, ?)}";
try (CallableStatement call = connection.prepareCall(callSQL2)) {
call.registerOutParameter(1, Types.DECIMAL);
call.execute();
BigDecimal actual2 = call.getBigDecimal(1);
assertEquals(new BigDecimal("100.24112"), actual2);
}

// Test for DECIMAL(38, 38)
String callSQLMaxScale = "{call " + procNameMaxScale + "(?, ?)}";
try (CallableStatement call = connection.prepareCall(callSQLMaxScale)) {
BigDecimal maxScaleValue = new BigDecimal("0." + "1".repeat(38));
call.setBigDecimal(1, maxScaleValue);
call.registerOutParameter(2, Types.DECIMAL);
call.execute();
BigDecimal actualMaxScale = call.getBigDecimal(2);
assertEquals(maxScaleValue, actualMaxScale, "DECIMAL(38, 38) max scale test failed");
}

// Test for DECIMAL(38, 0)
String callSQLMaxPrecision = "{call " + procNameMaxPrecision + "(?, ?)}";
try (CallableStatement call = connection.prepareCall(callSQLMaxPrecision)) {
BigDecimal maxPrecisionValue = new BigDecimal("9".repeat(38));
call.setBigDecimal(1, maxPrecisionValue);
call.registerOutParameter(2, Types.DECIMAL);
call.execute();
BigDecimal actualMaxPrecision = call.getBigDecimal(2);
assertEquals(maxPrecisionValue, actualMaxPrecision, "DECIMAL(38, 0) max precision test failed");
}
}
}
}
}
Loading