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();