diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientMarshallingTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientMarshallingTest.java index 52c6a983b4ba..ffa74c5f19cf 100644 --- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientMarshallingTest.java +++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientMarshallingTest.java @@ -25,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import java.math.BigDecimal; +import java.util.Map; import org.apache.ignite.Ignite; import org.apache.ignite.lang.ErrorGroups.Marshalling; import org.apache.ignite.lang.MarshallerException; @@ -32,7 +33,6 @@ import org.apache.ignite.table.Table; import org.apache.ignite.table.Tuple; import org.apache.ignite.table.mapper.Mapper; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; @@ -352,7 +352,6 @@ public void testVarcharColumnOverflow() { } @Test - @Disabled("https://issues.apache.org/jira/browse/IGNITE-22965") public void testDecimalColumnOverflow() { var tableName = "testDecimalColumnOverflow"; @@ -366,6 +365,23 @@ public void testDecimalColumnOverflow() { "Numeric field overflow in column 'VAL'"); } + @Test + void testDecimalColumnOverflow2() { + var tableName = "testDecimalColumnOverflow2"; + + ignite().sql().execute("CREATE TABLE " + tableName + " (KEY INT PRIMARY KEY, STR VARCHAR(10), VAL DECIMAL(6,2))"); + + Table table = ignite().tables().table(tableName); + var view = table.keyValueView(); + + Tuple key = Tuple.create(Map.of("key", 1)); + Tuple value = Tuple.create(Map.of("val", new BigDecimal("89900.123456"))); + + assertThrowsMarshallerException( + () -> view.put(key, value), + "Numeric field overflow in column 'VAL'"); + } + @Test public void testUnsupportedObjectInTuple() { Table table = ignite().tables().table(TABLE_NAME); diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/Column.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/Column.java index 8b1fd49948a0..c717fca248ba 100644 --- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/Column.java +++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/Column.java @@ -19,11 +19,14 @@ import static org.apache.ignite.internal.lang.IgniteStringFormatter.format; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import org.apache.ignite.internal.tostring.IgniteToStringExclude; import org.apache.ignite.internal.tostring.S; +import org.apache.ignite.internal.type.DecimalNativeType; import org.apache.ignite.internal.type.NativeType; import org.apache.ignite.internal.type.NativeTypes; import org.apache.ignite.internal.type.VarlenNativeType; @@ -236,6 +239,8 @@ public void validate(@Nullable Object val) { checkBounds((LocalDateTime) val, SchemaUtils.DATETIME_MIN, SchemaUtils.DATETIME_MAX); } else if (type.spec() == ColumnType.TIMESTAMP) { checkBounds((Instant) val, SchemaUtils.TIMESTAMP_MIN, SchemaUtils.TIMESTAMP_MAX); + } else if (type.spec() == ColumnType.DECIMAL) { + checkPrecision((BigDecimal) val); } } @@ -246,6 +251,14 @@ private > void checkBounds(T value, T min, T max) { } } + private void checkPrecision(BigDecimal val) throws SchemaMismatchException { + DecimalNativeType dnt = (DecimalNativeType) type; + BigDecimal scaled = val.setScale(dnt.scale(), RoundingMode.HALF_UP); + if (scaled.precision() > dnt.precision()) { + throw new SchemaMismatchException(format("Numeric field overflow in column '{}'", name)); + } + } + /** * Creates copy of the column with assigned positions. * @@ -281,14 +294,4 @@ public String toString() { public static String nullConstraintViolationMessage(String columnName) { return format("Column '{}' does not allow NULLs", columnName); } - - /** - * Returns an error message for numeric field overflow error. - * - * @param columnName Column name. - * @return Error message. - */ - public static String numericFieldOverflow(String columnName) { - return format("Numeric field overflow in column '{}'", columnName); - } } diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowAssembler.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowAssembler.java index 5dbb941cd70c..cdf190ffdd80 100644 --- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowAssembler.java +++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowAssembler.java @@ -18,7 +18,6 @@ package org.apache.ignite.internal.schema.row; import java.math.BigDecimal; -import java.math.RoundingMode; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -361,11 +360,6 @@ public RowAssembler appendDecimalNotNull(BigDecimal val) throws SchemaMismatchEx DecimalNativeType type = (DecimalNativeType) col.type(); - BigDecimal scaled = val.setScale(type.scale(), RoundingMode.HALF_UP); - if (scaled.precision() > type.precision()) { - throw new SchemaMismatchException(Column.numericFieldOverflow(col.name())); - } - builder.appendDecimalNotNull(val, type.scale()); shiftColumn(); diff --git a/modules/table/src/test/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerStatisticsTest.java b/modules/table/src/test/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerStatisticsTest.java index 89d518580728..7a6dbaf7a099 100644 --- a/modules/table/src/test/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerStatisticsTest.java +++ b/modules/table/src/test/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerStatisticsTest.java @@ -53,7 +53,7 @@ public class TupleMarshallerStatisticsTest { @ValueSource(ints = {3, 1024, CatalogUtils.MAX_DECIMAL_SCALE - PRECISION}) public void testDecimalSizeEstimation(int columnScale) { SchemaDescriptor schema = new SchemaDescriptor(1, - new Column[]{new Column("KEY", NativeTypes.decimalOf(PRECISION, columnScale), false)}, + new Column[]{new Column("KEY", NativeTypes.decimalOf(PRECISION + columnScale, columnScale), false)}, new Column[]{new Column("UNUSED", NativeTypes.INT32, true)}); TupleMarshallerImpl marshaller = KeyValueTestUtils.createMarshaller(schema);