This is an automated email from the ASF dual-hosted git repository.

alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new a6c0756bf82 IGNITE-23361 SQL Calcite: Fix loss of dynamic parameters 
precision - Fixes #11581.
a6c0756bf82 is described below

commit a6c0756bf82283bf34445ef21f31969c3f09f071
Author: Vladimir Steshin <[email protected]>
AuthorDate: Thu Oct 24 15:22:17 2024 +0300

    IGNITE-23361 SQL Calcite: Fix loss of dynamic parameters precision - Fixes 
#11581.
    
    Signed-off-by: Aleksey Plekhanov <[email protected]>
---
 .../query/calcite/exec/exp/IgniteSqlFunctions.java |  91 ++++++---
 .../query/calcite/prepare/IgniteSqlValidator.java  |  59 +++++-
 .../query/calcite/integration/DataTypesTest.java   | 220 ++++++++++++++++++++-
 .../DynamicParametersIntegrationTest.java          |   2 +-
 4 files changed, 327 insertions(+), 45 deletions(-)

diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteSqlFunctions.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteSqlFunctions.java
index 5c6130af64e..d7ecedf0f09 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteSqlFunctions.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteSqlFunctions.java
@@ -42,6 +42,15 @@ import org.checkerframework.checker.nullness.qual.Nullable;
  * Ignite SQL functions.
  */
 public class IgniteSqlFunctions {
+    /** */
+    public static final String NUMERIC_OVERFLOW_ERROR = "Numeric field 
overflow.";
+
+    /** */
+    private static final int DFLT_NUM_PRECISION = 
IgniteTypeSystem.INSTANCE.getDefaultPrecision(SqlTypeName.DECIMAL);
+
+    /** */
+    private static final RoundingMode NUMERIC_ROUNDING_MODE = 
RoundingMode.HALF_UP;
+
     /**
      * Default constructor.
      */
@@ -64,46 +73,44 @@ public class IgniteSqlFunctions {
         return x == null ? null : x.toPlainString();
     }
 
-    /** */
-    private static BigDecimal setScale(int precision, int scale, BigDecimal 
decimal) {
-        return precision == 
IgniteTypeSystem.INSTANCE.getDefaultPrecision(SqlTypeName.DECIMAL)
-            ? decimal : decimal.setScale(scale, RoundingMode.HALF_UP);
-    }
-
     /** CAST(DOUBLE AS DECIMAL). */
     public static BigDecimal toBigDecimal(double val, int precision, int 
scale) {
-        BigDecimal decimal = BigDecimal.valueOf(val);
-        return setScale(precision, scale, decimal);
+        return removeDefaultScale(precision, scale, 
toBigDecimal(BigDecimal.valueOf(val), precision, scale));
     }
 
     /** CAST(FLOAT AS DECIMAL). */
     public static BigDecimal toBigDecimal(float val, int precision, int scale) 
{
-        BigDecimal decimal = new BigDecimal(String.valueOf(val));
-        return setScale(precision, scale, decimal);
+        return removeDefaultScale(precision, scale, 
toBigDecimal(BigDecimal.valueOf(val), precision, scale));
+    }
+
+    /** Removes redundant scale in case of default DECIMAL (without passed 
precision and scale). */
+    private static BigDecimal removeDefaultScale(int precision, int scale, 
BigDecimal val) {
+        BigDecimal unscaled;
+
+        if (precision == DFLT_NUM_PRECISION && scale == 0 && 
val.compareTo(unscaled = val.setScale(0, NUMERIC_ROUNDING_MODE)) == 0)
+            return unscaled;
+
+        return val;
     }
 
     /** CAST(java long AS DECIMAL). */
     public static BigDecimal toBigDecimal(long val, int precision, int scale) {
-        BigDecimal decimal = BigDecimal.valueOf(val);
-        return setScale(precision, scale, decimal);
+        return toBigDecimal(BigDecimal.valueOf(val), precision, scale);
     }
 
     /** CAST(INT AS DECIMAL). */
     public static BigDecimal toBigDecimal(int val, int precision, int scale) {
-        BigDecimal decimal = new BigDecimal(val);
-        return setScale(precision, scale, decimal);
+        return toBigDecimal(BigDecimal.valueOf(val), precision, scale);
     }
 
     /** CAST(java short AS DECIMAL). */
     public static BigDecimal toBigDecimal(short val, int precision, int scale) 
{
-        BigDecimal decimal = new BigDecimal(String.valueOf(val));
-        return setScale(precision, scale, decimal);
+        return toBigDecimal(BigDecimal.valueOf(val), precision, scale);
     }
 
     /** CAST(java byte AS DECIMAL). */
     public static BigDecimal toBigDecimal(byte val, int precision, int scale) {
-        BigDecimal decimal = new BigDecimal(String.valueOf(val));
-        return setScale(precision, scale, decimal);
+        return toBigDecimal(BigDecimal.valueOf(val), precision, scale);
     }
 
     /** CAST(BOOL AS DECIMAL). */
@@ -115,21 +122,45 @@ public class IgniteSqlFunctions {
     public static BigDecimal toBigDecimal(String s, int precision, int scale) {
         if (s == null)
             return null;
-        BigDecimal decimal = new BigDecimal(s.trim());
-        return setScale(precision, scale, decimal);
+
+        return toBigDecimal(new BigDecimal(s.trim()), precision, scale);
     }
 
-    /** CAST(REAL AS DECIMAL). */
-    public static BigDecimal toBigDecimal(Number num, int precision, int 
scale) {
-        if (num == null)
+    /** Converts {@code val} to a {@link BigDecimal} with the given {@code 
precision} and {@code scale}. */
+    public static BigDecimal toBigDecimal(Number val, int precision, int 
scale) {
+        assert precision > 0 : "Invalid precision: " + precision;
+        assert scale >= 0 : "Invalid scale: " + scale;
+
+        if (val == null)
             return null;
-        // There are some values of "long" that cannot be represented as 
"double".
-        // Not so "int". If it isn't a long, go straight to double.
-        BigDecimal decimal = num instanceof BigDecimal ? ((BigDecimal)num)
-            : num instanceof BigInteger ? new BigDecimal((BigInteger)num)
-            : num instanceof Long ? new BigDecimal(num.longValue())
-            : BigDecimal.valueOf(num.doubleValue());
-        return setScale(precision, scale, decimal);
+
+        if (precision == DFLT_NUM_PRECISION)
+            return convertToBigDecimal(val);
+
+        BigDecimal dec = convertToBigDecimal(val);
+
+        if (scale > precision || (dec.precision() - dec.scale() > precision - 
scale && !dec.unscaledValue().equals(BigInteger.ZERO)))
+            throw new IllegalArgumentException(NUMERIC_OVERFLOW_ERROR);
+
+        return dec.setScale(scale, NUMERIC_ROUNDING_MODE);
+    }
+
+    /** */
+    private static BigDecimal convertToBigDecimal(Number value) {
+        BigDecimal dec;
+
+        if (value instanceof Float)
+            dec = BigDecimal.valueOf(value.floatValue());
+        else if (value instanceof Double)
+            dec = BigDecimal.valueOf(value.doubleValue());
+        else if (value instanceof BigDecimal)
+            dec = (BigDecimal)value;
+        else if (value instanceof BigInteger)
+            dec = new BigDecimal((BigInteger)value);
+        else
+            dec = new BigDecimal(value.longValue());
+
+        return dec;
     }
 
     /** Cast object depending on type to DECIMAL. */
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java
index 30674430cf3..131031364b8 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java
@@ -55,6 +55,7 @@ import org.apache.calcite.sql.type.SqlOperandTypeChecker;
 import org.apache.calcite.sql.type.SqlOperandTypeInference;
 import org.apache.calcite.sql.type.SqlTypeFamily;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SelectScope;
 import org.apache.calcite.sql.validate.SqlQualified;
 import org.apache.calcite.sql.validate.SqlValidator;
@@ -528,17 +529,10 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
 
     /** {@inheritDoc} */
     @Override protected void inferUnknownTypes(RelDataType inferredType, 
SqlValidatorScope scope, SqlNode node) {
-        if (node instanceof SqlDynamicParam && 
inferredType.equals(unknownType)) {
-            if (parameters.length > ((SqlDynamicParam)node).getIndex()) {
-                Object param = parameters[((SqlDynamicParam)node).getIndex()];
+        if (inferDynamicParamType(inferredType, node))
+            return;
 
-                setValidatedNodeType(node, (param == null) ? 
typeFactory().createSqlType(SqlTypeName.NULL) :
-                    
typeFactory().toSql(typeFactory().createType(param.getClass())));
-            }
-            else
-                setValidatedNodeType(node, 
typeFactory().createCustomType(Object.class));
-        }
-        else if (node instanceof SqlCall) {
+        if (node instanceof SqlCall) {
             final SqlValidatorScope newScope = scopes.get(node);
 
             if (newScope != null)
@@ -582,6 +576,51 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
             super.inferUnknownTypes(inferredType, scope, node);
     }
 
+    /**
+     * Tries to set actual type of dynamic parameter if {@code node} is a 
{@link SqlDynamicParam} and if its index
+     * is actual to {@link #parameters}.
+     *
+     * @return {@code True} if a new type was set. {@code False} otherwise.
+     */
+    private boolean inferDynamicParamType(RelDataType inferredType, SqlNode 
node) {
+        if (parameters == null || !(node instanceof SqlDynamicParam) || 
((SqlDynamicParam)node).getIndex() >= parameters.length)
+            return false;
+
+        Object val = parameters[((SqlDynamicParam)node).getIndex()];
+
+        if (val == null) {
+            if (inferredType.equals(unknownType)) {
+                setValidatedNodeType(node, 
typeFactory().createSqlType(SqlTypeName.NULL));
+
+                return true;
+            }
+
+            return false;
+        }
+
+        RelDataType valType = 
typeFactory().toSql(typeFactory().createType(val.getClass()));
+
+        if (SqlTypeUtil.equalSansNullability(valType, inferredType))
+            return false;
+
+        assert !unknownType.equals(valType);
+
+        if (valType.getFamily().equals(inferredType.getFamily())) {
+            RelDataType leastRestrictive = 
typeFactory().leastRestrictive(F.asList(inferredType, valType));
+
+            assert leastRestrictive != null;
+
+            if (inferredType == leastRestrictive)
+                return false;
+        }
+        else if (!unknownType.equals(inferredType) && 
SqlTypeUtil.canCastFrom(valType, inferredType, true))
+            return false;
+
+        setValidatedNodeType(node, valType);
+
+        return true;
+    }
+
     /** {@inheritDoc} */
     @Override public SqlLiteral resolveLiteral(SqlLiteral literal) {
         if (literal instanceof SqlNumericLiteral && 
literal.createSqlType(typeFactory).getSqlTypeName() == SqlTypeName.BIGINT) {
diff --git 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DataTypesTest.java
 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DataTypesTest.java
index d0a641afd7e..a577fa9f96e 100644
--- 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DataTypesTest.java
+++ 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DataTypesTest.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.internal.processors.query.calcite.integration;
 
 import java.math.BigDecimal;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
@@ -32,6 +31,7 @@ import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.cache.QueryEntity;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import 
org.apache.ignite.internal.processors.query.calcite.exec.exp.IgniteSqlFunctions;
 import org.apache.ignite.internal.processors.query.calcite.hint.HintDefinition;
 import org.apache.ignite.internal.util.typedef.F;
 import org.junit.Test;
@@ -466,7 +466,7 @@ public class DataTypesTest extends 
AbstractBasicIntegrationTransactionalTest {
             sql("INSERT INTO t1 VALUES (1, 1, null, '1'), (2, 2, 2, '22'), (3, 
33, 3, null), (4, null, 4, '4')");
             sql("INSERT INTO t2 VALUES (0, 0, 0, null, '0'), (11, null, 1, 1, 
'1'), (2, 2, 2, 2, '22'), (3, 3, null, 3, null)");
 
-            for (HintDefinition hint : 
Arrays.asList(HintDefinition.MERGE_JOIN, HintDefinition.NL_JOIN, 
HintDefinition.CNL_JOIN)) {
+            for (HintDefinition hint : F.asList(HintDefinition.MERGE_JOIN, 
HintDefinition.NL_JOIN, HintDefinition.CNL_JOIN)) {
                 String h = "/*+ " + hint.name() + " */ ";
 
                 // Primary keys, indexed.
@@ -574,10 +574,217 @@ public class DataTypesTest extends 
AbstractBasicIntegrationTransactionalTest {
             .check();
     }
 
+    /** */
+    @Test
+    public void testCoercionOfVarcharLiterals() {
+        assumeNoTransactions();
+
+        doTestCoercionOfVarchars(false);
+    }
+
+    /** */
+    @Test
+    public void testCoercionOfVarcharDynamicParameters() {
+        assumeNoTransactions();
+
+        doTestCoercionOfVarchars(true);
+    }
+
+    /** */
+    private void doTestCoercionOfVarchars(boolean dynamics) {
+        for (List<String> params : varcharsToCoerce()) {
+            String val = params.get(0);
+            String type = params.get(1);
+            String result = params.get(2);
+
+            if (dynamics)
+                assertQuery(String.format("SELECT CAST(? AS %s)", 
type)).withParams(val).returns(result).check();
+            else
+                assertQuery(String.format("SELECT CAST('%s' AS %s)", val, 
type)).returns(result).check();
+        }
+    }
+
+    /** */
+    private static List<List<String>> varcharsToCoerce() {
+        return F.asList(
+            F.asList("abcde", "VARCHAR(3)", "abc"),
+            F.asList("abcde", "VARCHAR(5)", "abcde"),
+            F.asList("abcde", "VARCHAR(6)", "abcde"),
+            F.asList("abcde", "VARCHAR", "abcde"),
+            F.asList("abcde", "CHAR", "a"),
+            F.asList("abcde", "CHAR(3)", "abc")
+        );
+    }
+
+    /** */
+    @Test
+    public void testCoercionOfNumericLiterals() {
+        assumeNoTransactions();
+
+        doTestCoercionOfNumerics(false, false);
+    }
+
+    /** */
+    @Test
+    public void testCoercionOfNumericLiteralsPrecasted() {
+        assumeNoTransactions();
+
+        doTestCoercionOfNumerics(false, true);
+    }
+
+    /** */
+    @Test
+    public void testCoercionOfNumericDynamicParameters() {
+        assumeNoTransactions();
+
+        doTestCoercionOfNumerics(true, false);
+    }
+
+    /** */
+    @Test
+    public void testCoercionOfNumericDynamicParametersPrecasted() {
+        assumeNoTransactions();
+
+        doTestCoercionOfNumerics(true, true);
+    }
+
+    /** */
+    private void doTestCoercionOfNumerics(boolean dynamic, boolean precasted) {
+        for (List<Object> params : numericsToCast()) {
+            assert params.size() == 4 : "Wrong params lenght: " + 
params.size();
+
+            String inputType = params.get(0).toString();
+            Object inputVal = params.get(1);
+            String targetType = params.get(2).toString();
+            Object expectedRes = params.get(3);
+
+            log.info("Params: inputType=" + inputType + ", inputValue=" + 
inputVal + ", targetType=" + targetType
+                + ", expectedResult=" + expectedRes);
+
+            if (dynamic) {
+                String qry = precasted
+                    ? String.format("SELECT CAST(?::%s AS %s)", inputType, 
targetType)
+                    : String.format("SELECT CAST(? AS %s)", targetType);
+
+                if (expectedRes instanceof Exception)
+                    assertThrows(qry, (Class<? extends 
Exception>)expectedRes.getClass(), ((Throwable)expectedRes).getMessage(), 
inputVal);
+                else
+                    
assertQuery(qry).withParams(inputVal).returns(expectedRes).check();
+            }
+            else {
+                String qry = precasted
+                    ? String.format("SELECT CAST(%s::%s AS %s)", 
asLiteral(inputVal, inputType), inputType, targetType)
+                    : String.format("SELECT CAST(%s AS %s)", 
asLiteral(inputVal, inputType), targetType);
+
+                if (expectedRes instanceof Exception)
+                    assertThrows(qry, (Class<? extends 
Exception>)expectedRes.getClass(), ((Throwable)expectedRes).getMessage());
+                else
+                    assertQuery(qry).returns(expectedRes).check();
+            }
+        }
+    }
+
+    /** */
+    private static String asLiteral(Object val, String type) {
+        return type.equalsIgnoreCase("VARCHAR") ? String.format("'%s'", val) : 
String.valueOf(val);
+    }
+
+    /** @return input type, input value, target type, expected result. */
+    private static List<List<Object>> numericsToCast() {
+        Exception overflowErr = new 
IllegalArgumentException(IgniteSqlFunctions.NUMERIC_OVERFLOW_ERROR);
+        Exception numFormatErr = new NumberFormatException("is neither a 
decimal digit number");
+
+        //noinspection RedundantTypeArguments (explicit type arguments speedup 
compilation and analysis time)
+        return F.<List<Object>>asList(
+            // String
+            F.asList("VARCHAR", "100", "DECIMAL(3)", new BigDecimal("100")),
+            F.asList("VARCHAR", "100", "DECIMAL(3, 0)", new BigDecimal("100")),
+            F.asList("VARCHAR", "100", "DECIMAL(4, 1)", new 
BigDecimal("100.0")),
+            F.asList("VARCHAR", "100.12", "DECIMAL(5, 1)", new 
BigDecimal("100.1")),
+            F.asList("VARCHAR", "100.16", "DECIMAL(5, 1)", new 
BigDecimal("100.2")),
+            F.asList("VARCHAR", "-100.16", "DECIMAL(5, 1)", new 
BigDecimal("-100.2")),
+            F.asList("VARCHAR", "lame", "DECIMAL(5, 1)", numFormatErr),
+            F.asList("VARCHAR", "12345", "DECIMAL(5, 1)", overflowErr),
+            F.asList("VARCHAR", "1234", "DECIMAL(5, 1)", new 
BigDecimal("1234.0")),
+            F.asList("VARCHAR", "100.12", "DECIMAL(1, 0)", overflowErr),
+            F.asList("VARCHAR", "100", "DECIMAL(2, 0)", overflowErr),
+
+            // Numeric
+            F.asList("DECIMAL(1, 1)", "0.1", "DECIMAL(1, 1)", new 
BigDecimal("0.1")),
+            F.asList("DECIMAL(3)", "100", "DECIMAL(3)", new BigDecimal("100")),
+            F.asList("DECIMAL(5, 2)", "100.16", "DECIMAL(4, 1)", new 
BigDecimal("100.2")),
+            F.asList("DECIMAL(5, 2)", "-100.16", "DECIMAL(4, 1)", new 
BigDecimal("-100.2")),
+            F.asList("DECIMAL(5, 2)", "100.16", "DECIMAL(5, 2)", new 
BigDecimal("100.16")),
+            F.asList("DECIMAL(5, 2)", "-100.16", "DECIMAL(5, 2)", new 
BigDecimal("-100.16")),
+            F.asList("DECIMAL(3)", "100", "DECIMAL(3, 0)", new 
BigDecimal("100")),
+            F.asList("DECIMAL(3)", "100", "DECIMAL(4, 1)", new 
BigDecimal("100.0")),
+            F.asList("DECIMAL(3)", "100", "DECIMAL(2, 0)", overflowErr),
+            F.asList("DECIMAL(1, 1)", "0.1", "DECIMAL(2, 2)", new 
BigDecimal("0.10")),
+            F.asList("DECIMAL(4, 2)", "10.12", "DECIMAL(2, 1)", overflowErr),
+            F.asList("DECIMAL(2, 2)", "0.12", "DECIMAL(1, 2)", overflowErr),
+            F.asList("DECIMAL(1, 1)", "0.1", "DECIMAL(1, 1)", new 
BigDecimal("0.1")),
+
+            // Tinyint
+            F.asList("TINYINT", (byte)100, "DECIMAL(3)", new 
BigDecimal("100")),
+            F.asList("TINYINT", (byte)100, "DECIMAL(3, 0)", new 
BigDecimal("100")),
+            F.asList("TINYINT", (byte)100, "DECIMAL(4, 1)", new 
BigDecimal("100.0")),
+            F.asList("TINYINT", (byte)100, "DECIMAL(2, 0)", overflowErr),
+
+            // Smallint
+            F.asList("SMALLINT", (short)100, "DECIMAL(3)", new 
BigDecimal("100")),
+            F.asList("SMALLINT", (short)100, "DECIMAL(3, 0)", new 
BigDecimal("100")),
+            F.asList("SMALLINT", (short)100, "DECIMAL(4, 1)", new 
BigDecimal("100.0")),
+            F.asList("SMALLINT", (short)100, "DECIMAL(2, 0)", overflowErr),
+
+            // Integer
+            F.asList("INTEGER", 100, "DECIMAL(3)", new BigDecimal("100")),
+            F.asList("INTEGER", 100, "DECIMAL(3, 0)", new BigDecimal("100")),
+            F.asList("INTEGER", 100, "DECIMAL(4, 1)", new BigDecimal("100.0")),
+            F.asList("INTEGER", 100, "DECIMAL(2, 0)", overflowErr),
+
+            // Bigint
+            F.asList("BIGINT", 100L, "DECIMAL(3)", new BigDecimal("100")),
+            F.asList("BIGINT", 100L, "DECIMAL(3, 0)", new BigDecimal("100")),
+            F.asList("BIGINT", 100L, "DECIMAL(4, 1)", new BigDecimal("100.0")),
+            F.asList("BIGINT", 100L, "DECIMAL(2, 0)", overflowErr),
+
+            // Real
+            F.asList("REAL", 100.0f, "DECIMAL(3)", new BigDecimal("100")),
+            F.asList("REAL", 100.0f, "DECIMAL(3, 0)", new BigDecimal("100")),
+            F.asList("REAL", 100.0f, "DECIMAL(4, 1)", new BigDecimal("100.0")),
+            F.asList("REAL", 100.0f, "DECIMAL(2, 0)", overflowErr),
+            F.asList("REAL", 0.1f, "DECIMAL(1, 1)", new BigDecimal("0.1")),
+            F.asList("REAL", 0.1f, "DECIMAL(2, 2)", new BigDecimal("0.10")),
+            F.asList("REAL", 10.12f, "DECIMAL(2, 1)", overflowErr),
+            F.asList("REAL", 0.12f, "DECIMAL(1, 2)", overflowErr),
+
+            // Double
+            F.asList("DOUBLE", 100.0d, "DECIMAL(3)", new BigDecimal("100")),
+            F.asList("DOUBLE", 100.0d, "DECIMAL(3, 0)", new BigDecimal("100")),
+            F.asList("DOUBLE", 100.0d, "DECIMAL(4, 1)", new 
BigDecimal("100.0")),
+            F.asList("DOUBLE", 100.0d, "DECIMAL(2, 0)", overflowErr),
+            F.asList("DOUBLE", 0.1d, "DECIMAL(1, 1)", new BigDecimal("0.1")),
+            F.asList("DOUBLE", 0.1d, "DECIMAL(2, 2)", new BigDecimal("0.10")),
+            F.asList("DOUBLE", 10.12d, "DECIMAL(2, 1)", overflowErr),
+            F.asList("DOUBLE", 0.12d, "DECIMAL(1, 2)", overflowErr),
+
+            // Decimal
+            F.asList("DECIMAL(1, 1)", new BigDecimal("0.1"), "DECIMAL(1, 1)", 
new BigDecimal("0.1")),
+            F.asList("DECIMAL(3)", new BigDecimal("100"), "DECIMAL(3)", new 
BigDecimal("100")),
+            F.asList("DECIMAL(3)", new BigDecimal("100"), "DECIMAL(3, 0)", new 
BigDecimal("100")),
+            F.asList("DECIMAL(3)", new BigDecimal("100"), "DECIMAL(4, 1)", new 
BigDecimal("100.0")),
+            F.asList("DECIMAL(3)", new BigDecimal("100"), "DECIMAL(2, 0)", 
overflowErr),
+            F.asList("DECIMAL(1, 1)", new BigDecimal("0.1"), "DECIMAL(2, 2)", 
new BigDecimal("0.10")),
+            F.asList("DECIMAL(4, 2)", new BigDecimal("10.12"), "DECIMAL(2, 
1)", overflowErr),
+            F.asList("DECIMAL(2, 2)", new BigDecimal("0.12"), "DECIMAL(1, 2)", 
overflowErr),
+            F.asList("DECIMAL(1, 1)", new BigDecimal("0.1"), "DECIMAL(1, 1)", 
new BigDecimal("0.1"))
+        );
+    }
+
     /** */
     @Test
     public void testFunctionArgsToNumericImplicitConversion() {
-        assumeTrue("Test use queries that doesn't touch any data. Skip for tx 
modes", sqlTxMode == SqlTransactionMode.NONE);
+        assumeNoTransactions();
 
         assertQuery("select decode(?, 0, 0, 1, 
1.0)").withParams(0).returns(new BigDecimal("0.0")).check();
         assertQuery("select decode(?, 0, 0, 1, 
1.0)").withParams(1).returns(new BigDecimal("1.0")).check();
@@ -652,7 +859,7 @@ public class DataTypesTest extends 
AbstractBasicIntegrationTransactionalTest {
     /** */
     @Test
     public void testCastDecimalOverflows() {
-        assumeTrue("Test use queries that doesn't touch any data. Skip for tx 
modes", sqlTxMode == SqlTransactionMode.NONE);
+        assumeNoTransactions();
 
         // BIGINT
         assertQuery("SELECT CAST(9223372036854775807.1 AS 
BIGINT)").returns(9223372036854775807L).check();
@@ -731,4 +938,9 @@ public class DataTypesTest extends 
AbstractBasicIntegrationTransactionalTest {
         assertQuery("SELECT CAST('-128.1' AS 
TINYINT)").returns((byte)-128).check();
         assertQuery("SELECT CAST('-128.9' AS 
TINYINT)").returns((byte)-128).check();
     }
+
+    /** */
+    private void assumeNoTransactions() {
+        assumeTrue("Test use queries that doesn't touch any data. Skip for tx 
modes", sqlTxMode == SqlTransactionMode.NONE);
+    }
 }
diff --git 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DynamicParametersIntegrationTest.java
 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DynamicParametersIntegrationTest.java
index 89fba933b5b..b3eea80c0f3 100644
--- 
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DynamicParametersIntegrationTest.java
+++ 
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/DynamicParametersIntegrationTest.java
@@ -71,7 +71,7 @@ public class DynamicParametersIntegrationTest extends 
AbstractBasicIntegrationTe
         assertQuery("SELECT LOWER(?), ? + ? ").withParams("TeSt", 2, 
2).returns("test", 4).check();
         assertQuery("SELECT POWER(?, ?)").withParams(2, 3).returns(8d).check();
         assertQuery("SELECT SQRT(?)").withParams(4d).returns(2d).check();
-        assertQuery("SELECT ? % ?").withParams(11, 
10).returns(BigDecimal.ONE).check();
+        assertQuery("SELECT ? % ?").withParams(11, 10).returns(1).check();
 
         assertQuery("SELECT 
LAST_DAY(?)").withParams(Date.valueOf("2022-01-01"))
             .returns(Date.valueOf("2022-01-31")).check();

Reply via email to