Skip to content

Commit 729520d

Browse files
Check for maximum scale in IOBuffer before array copy (#2239)
* Simple check to see if the input exceeds scale of 38. * Added test * Update failing tests * Cleanup * More cleanup * Move to TVPTypesTest * The scale check was somehow failing coco, instead moved to just catch the IndexOutOfBoundsException * ArrayIndexOutOfBoundsException not IndexOutOfBoundsException * More general * Revert * This should have been rolled back in the retry PR * This test will be removed in a separate PR * ... * Changed the error message * Forgot to change the test as well * Better error
1 parent a762d7c commit 729520d

File tree

3 files changed

+42
-3
lines changed

3 files changed

+42
-3
lines changed

src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5028,7 +5028,8 @@ void writeTVPRows(TVP value) throws SQLServerException {
50285028
}
50295029

50305030
private void writeInternalTVPRowValues(JDBCType jdbcType, String currentColumnStringValue, Object currentObject,
5031-
Map.Entry<Integer, SQLServerMetaData> columnPair, boolean isSqlVariant) throws SQLServerException {
5031+
Map.Entry<Integer, SQLServerMetaData> columnPair, boolean isSqlVariant)
5032+
throws SQLServerException, IllegalArgumentException {
50325033
boolean isShortValue, isNull;
50335034
int dataLength;
50345035
switch (jdbcType) {
@@ -5100,9 +5101,18 @@ private void writeInternalTVPRowValues(JDBCType jdbcType, String currentColumnSt
51005101

51015102
/*
51025103
* setScale of all BigDecimal value based on metadata as scale is not sent separately for individual
5103-
* value. Use the rounding used in Server. Say, for BigDecimal("0.1"), if scale in metdadata is 0,
5104+
* value. Use the rounding used in Server. Say, for BigDecimal("0.1"), if scale in metadata is 0,
51045105
* then ArithmeticException would be thrown if RoundingMode is not set
5106+
*
5107+
* Additionally, we should check here if the scale is within the bounds of SQLServer as it is
5108+
* possible for a number with a scale larger than 38 to be passed in.
51055109
*/
5110+
if (columnPair.getValue().scale > SQLServerConnection.MAX_DECIMAL_PRECISION) {
5111+
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidScale"));
5112+
Object[] msgArgs = {columnPair.getValue().scale};
5113+
throw new IllegalArgumentException(form.format(msgArgs));
5114+
}
5115+
51065116
bdValue = bdValue.setScale(columnPair.getValue().scale, RoundingMode.HALF_UP);
51075117

51085118
byte[] val = DDC.convertBigDecimalToBytes(bdValue, bdValue.scale());

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,8 @@ protected Object[][] getContents() {
540540
{"R_serverError", "An error occurred during the current command (Done status {0}). {1}"},
541541
{"R_ManagedIdentityTokenAcquisitionFail", "Failed to acquire managed identity token. Request for the token succeeded, but no token was returned. The token is null."},
542542
{"R_AmbiguousRowUpdate", "Failed to execute updateRow(). The update is attempting an ambiguous update on tables \"{0}\" and \"{1}\". Ensure all columns being updated prior to the updateRow() call belong to the same table."},
543-
{"R_InvalidSqlQuery", "Invalid SQL Query: {0}"}
543+
{"R_InvalidSqlQuery", "Invalid SQL Query: {0}"},
544+
{"R_InvalidScale", "Scale of input value is larger than the maximum allowed by SQL Server."}
544545
};
545546
}
546547
// @formatter:on

src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPTypesTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static org.junit.jupiter.api.Assertions.assertEquals;
99
import static org.junit.jupiter.api.Assertions.assertTrue;
1010

11+
import java.math.BigDecimal;
1112
import java.sql.Connection;
1213
import java.sql.ResultSet;
1314
import java.sql.SQLException;
@@ -573,6 +574,33 @@ public String toString() {
573574
}
574575
}
575576

577+
/**
578+
* Numeric (bigdecimal) with StoredProcedure
579+
*
580+
* @throws SQLException
581+
*/
582+
@Test
583+
public void testTVPNumericStoredProcedure() throws SQLException {
584+
createTables("numeric(10,2)");
585+
createTVPS("numeric(38,10)");
586+
createProcedure();
587+
588+
tvp = new SQLServerDataTable();
589+
tvp.addColumnMetadata("c1", java.sql.Types.NUMERIC);
590+
tvp.addRow(new BigDecimal(0.222));
591+
592+
final String sql = "{call " + AbstractSQLGenerator.escapeIdentifier(procedureName) + "(?)}";
593+
594+
try (SQLServerCallableStatement callableStmt = (SQLServerCallableStatement) connection.prepareCall(sql)) {
595+
callableStmt.setStructured(1, tvpName, tvp);
596+
callableStmt.execute();
597+
598+
fail(TestResource.getResource("R_expectedExceptionNotThrown"));
599+
} catch (IllegalArgumentException e) {
600+
assertTrue(e.getMessage().matches(TestUtils.formatErrorMsg("R_InvalidScale")), e.getMessage());
601+
}
602+
}
603+
576604
/**
577605
* Negative test cases for testing Boolean with TVP
578606
*

0 commit comments

Comments
 (0)