This is an automated email from the ASF dual-hosted git repository.
korlov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new a4d39fb194 IGNITE-22519: Sql. Numerics. Conversion produces incorrect
results (#4044)
a4d39fb194 is described below
commit a4d39fb1944204644b5f1aaf52ff67e2d1f5585a
Author: Max Zhuravkov <[email protected]>
AuthorDate: Wed Jul 10 15:05:49 2024 +0300
IGNITE-22519: Sql. Numerics. Conversion produces incorrect results (#4044)
---
.../internal/sql/engine/ItDataTypesTest.java | 156 +++++++++------------
.../aggregate/group/test_group_by_distinct.test | 10 +-
.../integrationTest/sql/cast/test_cast_bigint.test | 4 +-
.../sql/cast/test_cast_decimal.test | 2 -
.../integrationTest/sql/cast/test_cast_float.test | 8 +-
.../integrationTest/sql/cast/test_cast_real.test | 8 +-
.../integrationTest/sql/set/test_intersect.test | 2 +-
.../sql/types/decimal/test_decimal.test | 22 +++
.../sql/engine/exec/exp/ExpressionFactoryImpl.java | 91 +++++++++++-
.../sql/engine/exec/exp/RexToLixTranslator.java | 5 +-
.../internal/sql/engine/util/IgniteMath.java | 56 ++++++++
.../internal/sql/engine/util/Primitives.java | 27 ++++
.../ignite/internal/sql/engine/util/RexUtils.java | 6 +-
.../engine/exec/exp/ExpressionFactoryImplTest.java | 111 ++++++++++++++-
14 files changed, 381 insertions(+), 127 deletions(-)
diff --git
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
index e068db34c4..9e75263fe1 100644
---
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
+++
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
@@ -45,7 +45,6 @@ import
org.apache.ignite.internal.sql.engine.util.QueryChecker;
import org.apache.ignite.lang.ErrorGroups.Sql;
import org.apache.ignite.lang.IgniteException;
import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@@ -366,7 +365,7 @@ public class ItDataTypesTest extends BaseSqlIntegrationTest
{
.returns(new BigDecimal("1.00")).check();
assertQuery("SELECT CASE WHEN false THEN DECIMAL '1.00' ELSE DECIMAL
'0.0' END")
- .returns(new BigDecimal("0.0")).check();
+ .returns(new BigDecimal("0.00")).check();
assertQuery(
"SELECT DECIMAL '0.09' BETWEEN DECIMAL '0.06' AND DECIMAL
'0.07'")
@@ -386,15 +385,12 @@ public class ItDataTypesTest extends
BaseSqlIntegrationTest {
assertQuery("SELECT id FROM tbl WHERE val = DECIMAL
'10.20'").returns(1).check();
}
-
/** decimal casts - cast literal to decimal. */
@ParameterizedTest(name = "{2}:{1} AS {3} = {4}")
@MethodSource("decimalCastFromLiterals")
- public void testDecimalCastsNumericLiterals(CaseStatus status, RelDataType
inputType, Object input,
+ public void testDecimalCastsNumericLiterals(RelDataType inputType, Object
input,
RelDataType targetType, Result<BigDecimal> result) {
- Assumptions.assumeTrue(status == CaseStatus.RUN);
-
String literal = asLiteral(input, inputType);
String query = format("SELECT CAST({} AS {})", literal, targetType);
@@ -410,31 +406,28 @@ public class ItDataTypesTest extends
BaseSqlIntegrationTest {
// TODO Align test datasets
https://issues.apache.org/jira/browse/IGNITE-20130
return Stream.of(
// String
- arguments(CaseStatus.RUN, varcharType, "100", decimalType(3),
bigDecimalVal("100")),
- arguments(CaseStatus.RUN, varcharType, "100.12",
decimalType(5, 1), bigDecimalVal("100.1")),
- arguments(CaseStatus.RUN, varcharType, "lame", decimalType(5,
1), error(NUMERIC_FORMAT_ERROR)),
- arguments(CaseStatus.RUN, varcharType, "12345", decimalType(5,
1), error(NUMERIC_OVERFLOW_ERROR)),
- arguments(CaseStatus.RUN, varcharType, "1234", decimalType(5,
1), bigDecimalVal("1234.0")),
- // TODO Uncomment these test cases after
https://issues.apache.org/jira/browse/IGNITE-19822 is fixed.
- arguments(CaseStatus.SKIP, varcharType, "100.12",
decimalType(1, 0), error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(varcharType, "100", decimalType(3),
bigDecimalVal("100")),
+ arguments(varcharType, "100.12", decimalType(5, 1),
bigDecimalVal("100.1")),
+ arguments(varcharType, "lame", decimalType(5, 1),
error(NUMERIC_FORMAT_ERROR)),
+ arguments(varcharType, "12345", decimalType(5, 1),
error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(varcharType, "1234", decimalType(5, 1),
bigDecimalVal("1234.0")),
+ arguments(varcharType, "100.12", decimalType(1, 0),
error(NUMERIC_OVERFLOW_ERROR)),
// Numeric
- arguments(CaseStatus.RUN, numeric, "100", decimalType(3),
bigDecimalVal("100")),
- arguments(CaseStatus.RUN, numeric, "100", decimalType(3, 0),
bigDecimalVal("100")),
- // TODO Uncomment these test cases after
https://issues.apache.org/jira/browse/IGNITE-19822 is fixed.
- arguments(CaseStatus.SKIP, numeric, "100.12", decimalType(5,
1), bigDecimalVal("100.1")),
- arguments(CaseStatus.SKIP, numeric, "100.12", decimalType(5,
0), bigDecimalVal("100")),
- arguments(CaseStatus.SKIP, numeric, "100", decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
- arguments(CaseStatus.SKIP, numeric, "100.12", decimalType(5,
2), bigDecimalVal("100.12"))
+ arguments(numeric, "100", decimalType(3),
bigDecimalVal("100")),
+ arguments(numeric, "100", decimalType(3, 0),
bigDecimalVal("100")),
+ arguments(numeric, "100.12", decimalType(5, 1),
bigDecimalVal("100.1")),
+ arguments(numeric, "100.12", decimalType(5, 0),
bigDecimalVal("100")),
+ arguments(numeric, "100", decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(numeric, "100.12", decimalType(5, 2),
bigDecimalVal("100.12"))
);
}
/** decimal casts - cast dynamic param to decimal. */
@ParameterizedTest(name = "{2}:?{1} AS {3} = {4}")
@MethodSource("decimalCasts")
- public void testDecimalCastsDynamicParams(CaseStatus ignore, RelDataType
inputType, Object input,
+ public void testDecimalCastsDynamicParams(RelDataType inputType, Object
input,
RelDataType targetType, Result<BigDecimal> result) {
- // We ignore status because every case should work for dynamic
parameter.
String query = format("SELECT CAST(? AS {})", targetType);
@@ -445,11 +438,9 @@ public class ItDataTypesTest extends
BaseSqlIntegrationTest {
/** decimals casts - cast numeric literal to specific type then cast the
result to decimal. */
@ParameterizedTest(name = "{1}: {2}::{1} AS {3} = {4}")
@MethodSource("decimalCasts")
- public void testDecimalCastsFromNumeric(CaseStatus status, RelDataType
inputType, Object input,
+ public void testDecimalCastsFromNumeric(RelDataType inputType, Object
input,
RelDataType targetType, Result<BigDecimal> result) {
- Assumptions.assumeTrue(status == CaseStatus.RUN);
-
String literal = asLiteral(input, inputType);
String query = format("SELECT CAST({}::{} AS {})", literal, inputType,
targetType);
@@ -755,20 +746,6 @@ public class ItDataTypesTest extends
BaseSqlIntegrationTest {
}
}
- /**
- * Indicates whether a test case should run or should be skipped.
- * We need this because the set of test cases is the same for both dynamic
params
- * and numeric values.
- *
- * <p>TODO Should be removed after
https://issues.apache.org/jira/browse/IGNITE-19822 is fixed.
- */
- enum CaseStatus {
- /** Case should run. */
- RUN,
- /** Case should be skipped. */
- SKIP
- }
-
private static Stream<Arguments> decimalCasts() {
RelDataType varcharType = varcharType();
RelDataType tinyIntType = sqlType(SqlTypeName.TINYINT);
@@ -780,75 +757,68 @@ public class ItDataTypesTest extends
BaseSqlIntegrationTest {
return Stream.of(
// String
- arguments(CaseStatus.RUN, varcharType, "100", decimalType(3),
bigDecimalVal("100")),
- arguments(CaseStatus.RUN, varcharType, "100", decimalType(3),
bigDecimalVal("100")),
- arguments(CaseStatus.RUN, varcharType, "100", decimalType(3,
0), bigDecimalVal("100")),
- arguments(CaseStatus.RUN, varcharType, "100", decimalType(4,
1), bigDecimalVal("100.0")),
- arguments(CaseStatus.RUN, varcharType, "100", decimalType(2,
0), error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(varcharType, "100", decimalType(3),
bigDecimalVal("100")),
+ arguments(varcharType, "100", decimalType(3),
bigDecimalVal("100")),
+ arguments(varcharType, "100", decimalType(3, 0),
bigDecimalVal("100")),
+ arguments(varcharType, "100", decimalType(4, 1),
bigDecimalVal("100.0")),
+ arguments(varcharType, "100", decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
// Tinyint
- arguments(CaseStatus.RUN, tinyIntType, (byte) 100,
decimalType(3), bigDecimalVal("100")),
- arguments(CaseStatus.RUN, tinyIntType, (byte) 100,
decimalType(3, 0), bigDecimalVal("100")),
- // TODO Uncomment these test cases after
https://issues.apache.org/jira/browse/IGNITE-19822 is fixed.
- arguments(CaseStatus.SKIP, tinyIntType, (byte) 100,
decimalType(4, 1), bigDecimalVal("100.0")),
- arguments(CaseStatus.RUN, tinyIntType, (byte) 100,
decimalType(2, 0), error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(tinyIntType, (byte) 100, decimalType(3),
bigDecimalVal("100")),
+ arguments(tinyIntType, (byte) 100, decimalType(3, 0),
bigDecimalVal("100")),
+ arguments(tinyIntType, (byte) 100, decimalType(4, 1),
bigDecimalVal("100.0")),
+ arguments(tinyIntType, (byte) 100, decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
// Smallint
- arguments(CaseStatus.RUN, smallIntType, (short) 100,
decimalType(3), bigDecimalVal("100")),
- arguments(CaseStatus.RUN, smallIntType, (short) 100,
decimalType(3, 0), bigDecimalVal("100")),
- // TODO Uncomment these test cases after
https://issues.apache.org/jira/browse/IGNITE-19822 is fixed.
- arguments(CaseStatus.SKIP, smallIntType, (short) 100,
decimalType(4, 1), bigDecimalVal("100.0")),
- arguments(CaseStatus.RUN, smallIntType, (short) 100,
decimalType(2, 0), error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(smallIntType, (short) 100, decimalType(3),
bigDecimalVal("100")),
+ arguments(smallIntType, (short) 100, decimalType(3, 0),
bigDecimalVal("100")),
+ arguments(smallIntType, (short) 100, decimalType(4, 1),
bigDecimalVal("100.0")),
+ arguments(smallIntType, (short) 100, decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
// Integer
- arguments(CaseStatus.RUN, integerType, 100, decimalType(3),
bigDecimalVal("100")),
- arguments(CaseStatus.RUN, integerType, 100, decimalType(3, 0),
bigDecimalVal("100")),
- // TODO Uncomment these test cases after
https://issues.apache.org/jira/browse/IGNITE-19822 is fixed.
- arguments(CaseStatus.SKIP, integerType, 100, decimalType(4,
1), bigDecimalVal("100.0")),
- arguments(CaseStatus.RUN, integerType, 100, decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(integerType, 100, decimalType(3),
bigDecimalVal("100")),
+ arguments(integerType, 100, decimalType(3, 0),
bigDecimalVal("100")),
+ arguments(integerType, 100, decimalType(4, 1),
bigDecimalVal("100.0")),
+ arguments(integerType, 100, decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
// Bigint
- arguments(CaseStatus.RUN, bigintType, 100L, decimalType(3),
bigDecimalVal("100")),
- arguments(CaseStatus.RUN, bigintType, 100L, decimalType(3, 0),
bigDecimalVal("100")),
- // TODO Uncomment these test cases after
https://issues.apache.org/jira/browse/IGNITE-19822 is fixed.
- arguments(CaseStatus.SKIP, bigintType, 100L, decimalType(4,
1), bigDecimalVal("100.0")),
- arguments(CaseStatus.RUN, bigintType, 100L, decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(bigintType, 100L, decimalType(3),
bigDecimalVal("100")),
+ arguments(bigintType, 100L, decimalType(3, 0),
bigDecimalVal("100")),
+ arguments(bigintType, 100L, decimalType(4, 1),
bigDecimalVal("100.0")),
+ arguments(bigintType, 100L, decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
// Real
- // TODO Uncomment these test cases after
https://issues.apache.org/jira/browse/IGNITE-19822 is fixed.
- arguments(CaseStatus.SKIP, realType, 100.0f, decimalType(3),
bigDecimalVal("100")),
- arguments(CaseStatus.SKIP, realType, 100.0f, decimalType(3,
0), bigDecimalVal("100")),
- arguments(CaseStatus.SKIP, realType, 100.0f, decimalType(4,
1), bigDecimalVal("100.0")),
- arguments(CaseStatus.RUN, realType, 100.0f, decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
- arguments(CaseStatus.SKIP, realType, 0.1f, decimalType(1, 1),
bigDecimalVal("0.1")),
- arguments(CaseStatus.SKIP, realType, 0.1f, decimalType(2, 2),
bigDecimalVal("0.10")),
- arguments(CaseStatus.RUN, realType, 10.12f, decimalType(2, 1),
error(NUMERIC_OVERFLOW_ERROR)),
- arguments(CaseStatus.RUN, realType, 0.12f, decimalType(1, 2),
error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(realType, 100.0f, decimalType(3),
bigDecimalVal("100")),
+ arguments(realType, 100.0f, decimalType(3, 0),
bigDecimalVal("100")),
+ arguments(realType, 100.0f, decimalType(4, 1),
bigDecimalVal("100.0")),
+ arguments(realType, 100.0f, decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(realType, 0.1f, decimalType(1, 1),
bigDecimalVal("0.1")),
+ arguments(realType, 0.1f, decimalType(2, 2),
bigDecimalVal("0.10")),
+ arguments(realType, 10.12f, decimalType(2, 1),
error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(realType, 0.12f, decimalType(1, 2),
error(NUMERIC_OVERFLOW_ERROR)),
// Double
- // TODO Uncomment these test cases after
https://issues.apache.org/jira/browse/IGNITE-19822 is fixed.
- arguments(CaseStatus.SKIP, doubleType, 100.0d, decimalType(3),
bigDecimalVal("100")),
- arguments(CaseStatus.SKIP, doubleType, 100.0d, decimalType(3,
0), bigDecimalVal("100")),
- arguments(CaseStatus.SKIP, doubleType, 100.0d, decimalType(4,
1), bigDecimalVal("100.0")),
- arguments(CaseStatus.RUN, doubleType, 100.0d, decimalType(2,
0), error(NUMERIC_OVERFLOW_ERROR)),
- arguments(CaseStatus.SKIP, doubleType, 0.1d, decimalType(1,
1), bigDecimalVal("0.1")),
- arguments(CaseStatus.SKIP, doubleType, 0.1d, decimalType(2,
2), bigDecimalVal("0.10")),
- arguments(CaseStatus.RUN, doubleType, 10.12d, decimalType(2,
1), error(NUMERIC_OVERFLOW_ERROR)),
- arguments(CaseStatus.RUN, doubleType, 0.12d, decimalType(1,
2), error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(doubleType, 100.0d, decimalType(3),
bigDecimalVal("100")),
+ arguments(doubleType, 100.0d, decimalType(3, 0),
bigDecimalVal("100")),
+ arguments(doubleType, 100.0d, decimalType(4, 1),
bigDecimalVal("100.0")),
+ arguments(doubleType, 100.0d, decimalType(2, 0),
error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(doubleType, 0.1d, decimalType(1, 1),
bigDecimalVal("0.1")),
+ arguments(doubleType, 0.1d, decimalType(2, 2),
bigDecimalVal("0.10")),
+ arguments(doubleType, 10.12d, decimalType(2, 1),
error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(doubleType, 0.12d, decimalType(1, 2),
error(NUMERIC_OVERFLOW_ERROR)),
// Decimal
- arguments(CaseStatus.RUN, decimalType(1, 1), new
BigDecimal("0.1"), decimalType(1, 1), bigDecimalVal("0.1")),
- arguments(CaseStatus.RUN, decimalType(3), new
BigDecimal("100"), decimalType(3), bigDecimalVal("100")),
+ arguments(decimalType(1, 1), new BigDecimal("0.1"),
decimalType(1, 1), bigDecimalVal("0.1")),
+ arguments(decimalType(3), new BigDecimal("100"),
decimalType(3), bigDecimalVal("100")),
// passed with runtime call and failed with parsing
substitution
- arguments(CaseStatus.SKIP, decimalType(5, 2), new
BigDecimal("100.16"), decimalType(4, 1), bigDecimalVal("100.2")),
- arguments(CaseStatus.RUN, decimalType(3), new
BigDecimal("100"), decimalType(3, 0), bigDecimalVal("100")),
- // TODO Uncomment these test cases after
https://issues.apache.org/jira/browse/IGNITE-19822 is fixed.
- arguments(CaseStatus.SKIP, decimalType(3), new
BigDecimal("100"), decimalType(4, 1), bigDecimalVal("100.0")),
- arguments(CaseStatus.RUN, decimalType(3), new
BigDecimal("100"), decimalType(2, 0), error(NUMERIC_OVERFLOW_ERROR)),
- arguments(CaseStatus.SKIP, decimalType(1, 1), new
BigDecimal("0.1"), decimalType(2, 2), bigDecimalVal("0.10")),
- arguments(CaseStatus.RUN, decimalType(4, 2), new
BigDecimal("10.12"), decimalType(2, 1), error(NUMERIC_OVERFLOW_ERROR)),
- arguments(CaseStatus.RUN, decimalType(2, 2), new
BigDecimal("0.12"), decimalType(1, 2), error(NUMERIC_OVERFLOW_ERROR)),
- arguments(CaseStatus.SKIP, decimalType(1, 1), new
BigDecimal("0.1"), decimalType(1, 1), bigDecimalVal("0.1"))
+ arguments(decimalType(5, 2), new BigDecimal("100.16"),
decimalType(4, 1), bigDecimalVal("100.2")),
+ arguments(decimalType(3), new BigDecimal("100"),
decimalType(3, 0), bigDecimalVal("100")),
+ arguments(decimalType(3), new BigDecimal("100"),
decimalType(4, 1), bigDecimalVal("100.0")),
+ arguments(decimalType(3), new BigDecimal("100"),
decimalType(2, 0), error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(decimalType(1, 1), new BigDecimal("0.1"),
decimalType(2, 2), bigDecimalVal("0.10")),
+ arguments(decimalType(4, 2), new BigDecimal("10.12"),
decimalType(2, 1), error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(decimalType(2, 2), new BigDecimal("0.12"),
decimalType(1, 2), error(NUMERIC_OVERFLOW_ERROR)),
+ arguments(decimalType(1, 1), new BigDecimal("0.1"),
decimalType(1, 1), bigDecimalVal("0.1"))
);
}
diff --git
a/modules/sql-engine/src/integrationTest/sql/aggregate/group/test_group_by_distinct.test
b/modules/sql-engine/src/integrationTest/sql/aggregate/group/test_group_by_distinct.test
index 4d6a784996..caf5146ee3 100644
---
a/modules/sql-engine/src/integrationTest/sql/aggregate/group/test_group_by_distinct.test
+++
b/modules/sql-engine/src/integrationTest/sql/aggregate/group/test_group_by_distinct.test
@@ -29,20 +29,20 @@ SELECT val FROM integers GROUP BY ALL GROUPING SETS ((val),
(val))
4
query R rowsort
-SELECT val FROM ( VALUES (1), (1.0::REAL), (1.0::REAL), (2::DOUBLE),
(1.1::REAL), (2::DECIMAL(2)) ) t(val) GROUP BY ALL GROUPING SETS ((val), (val))
+SELECT val FROM ( VALUES (1), (1.0::REAL), (1.0::REAL), (2::DOUBLE),
(1.5::REAL), (2::DECIMAL(2)) ) t(val) GROUP BY ALL GROUPING SETS ((val), (val))
----
1.0
1.0
-1.1
-1.1
+1.5
+1.5
2.0
2.0
query R rowsort
-SELECT val FROM ( VALUES (1), (1.0::REAL), (2::DOUBLE), (1.1::REAL),
(2::DECIMAL(2)) ) t(val) GROUP BY DISTINCT GROUPING SETS ((val), (val))
+SELECT val FROM ( VALUES (1), (1.0::REAL), (2::DOUBLE), (1.5::REAL),
(2::DECIMAL(2)) ) t(val) GROUP BY DISTINCT GROUPING SETS ((val), (val))
----
1.0
-1.1
+1.5
2.0
# NOTE: Results include trailing whitespace
diff --git
a/modules/sql-engine/src/integrationTest/sql/cast/test_cast_bigint.test
b/modules/sql-engine/src/integrationTest/sql/cast/test_cast_bigint.test
index cb747047e4..b476fefd72 100644
--- a/modules/sql-engine/src/integrationTest/sql/cast/test_cast_bigint.test
+++ b/modules/sql-engine/src/integrationTest/sql/cast/test_cast_bigint.test
@@ -6,7 +6,7 @@
statement ok
SELECT CAST('100' AS BIGINT);
-# https://issues.apache.org/jira/browse/IGNITE-22519
+# https://issues.apache.org/jira/browse/IGNITE-20889
skipif ignite3
statement error
SELECT CAST('100.1' AS BIGINT);
@@ -16,7 +16,7 @@ SELECT CAST(1e1 AS BIGINT);
----
10
-# https://issues.apache.org/jira/browse/IGNITE-22519
+# https://issues.apache.org/jira/browse/IGNITE-20889
skipif ignite3
statement error: For input string: "1e2"
SELECT CAST('1e2' AS BIGINT);
diff --git
a/modules/sql-engine/src/integrationTest/sql/cast/test_cast_decimal.test
b/modules/sql-engine/src/integrationTest/sql/cast/test_cast_decimal.test
index af42b78d7c..f21021db7b 100644
--- a/modules/sql-engine/src/integrationTest/sql/cast/test_cast_decimal.test
+++ b/modules/sql-engine/src/integrationTest/sql/cast/test_cast_decimal.test
@@ -69,8 +69,6 @@ SELECT CAST(100.1::DOUBLE AS DECIMAL);
----
100.1
-# https://issues.apache.org/jira/browse/IGNITE-22519
-skipif ignite3
query T
SELECT CAST(100.1234::DOUBLE AS DECIMAL(7, 2));
----
diff --git
a/modules/sql-engine/src/integrationTest/sql/cast/test_cast_float.test
b/modules/sql-engine/src/integrationTest/sql/cast/test_cast_float.test
index 5f3bfbb7a9..c88e5c758f 100644
--- a/modules/sql-engine/src/integrationTest/sql/cast/test_cast_float.test
+++ b/modules/sql-engine/src/integrationTest/sql/cast/test_cast_float.test
@@ -11,16 +11,12 @@ SELECT CAST('100' AS FLOAT);
----
100.0
-# https://issues.apache.org/jira/browse/IGNITE-22519
# overflow
-skipif ignite3
-statement error
+statement error: REAL out of range
SELECT CAST(1e39 AS FLOAT);
-# https://issues.apache.org/jira/browse/IGNITE-22519
# overflow
-skipif ignite3
-statement error
+statement error: REAL out of range
SELECT CAST(-1e39 AS FLOAT);
query T
diff --git
a/modules/sql-engine/src/integrationTest/sql/cast/test_cast_real.test
b/modules/sql-engine/src/integrationTest/sql/cast/test_cast_real.test
index f402af5f19..1f6f5e391b 100644
--- a/modules/sql-engine/src/integrationTest/sql/cast/test_cast_real.test
+++ b/modules/sql-engine/src/integrationTest/sql/cast/test_cast_real.test
@@ -11,16 +11,12 @@ SELECT CAST('100' AS REAL);
----
100.0
-# https://issues.apache.org/jira/browse/IGNITE-22519
# overflow
-skipif ignite3
-statement error
+statement error: REAL out of range
SELECT CAST(1e39 AS REAL);
-# https://issues.apache.org/jira/browse/IGNITE-22519
# overflow
-skipif ignite3
-statement error
+statement error: REAL out of range
SELECT CAST(-1e39 AS REAL);
query T
diff --git a/modules/sql-engine/src/integrationTest/sql/set/test_intersect.test
b/modules/sql-engine/src/integrationTest/sql/set/test_intersect.test
index 375c1fc6cd..fda27d7f37 100644
--- a/modules/sql-engine/src/integrationTest/sql/set/test_intersect.test
+++ b/modules/sql-engine/src/integrationTest/sql/set/test_intersect.test
@@ -74,7 +74,7 @@ statement ok
CREATE TABLE t_float(f1 float);
statement ok
-INSERT INTO t_float(f1) VALUES (-1.2345678901234e+200), (-34.84), (123),
(456), (456.1), (-456);
+INSERT INTO t_float(f1) VALUES (-1.2345678901234e+10), (-34.84), (123),
(456), (456.1), (-456);
query I
(SELECT f1 FROM t_float INTERSECT SELECT q1 FROM t_int)
diff --git
a/modules/sql-engine/src/integrationTest/sql/types/decimal/test_decimal.test
b/modules/sql-engine/src/integrationTest/sql/types/decimal/test_decimal.test
index 0180161bb4..9d603b5eeb 100644
--- a/modules/sql-engine/src/integrationTest/sql/types/decimal/test_decimal.test
+++ b/modules/sql-engine/src/integrationTest/sql/types/decimal/test_decimal.test
@@ -153,3 +153,25 @@ SELECT '0.1'::DECIMAL(1, 2, 3);
statement error
SELECT '1'::INTEGER(1000);
+
+query T
+SELECT CASE WHEN true THEN DECIMAL '1.00' ELSE DECIMAL '0' END
+----
+1.00
+
+# Same as above but won't constant fold
+query T
+SELECT CASE WHEN true THEN a ELSE b END FROM (VALUES (DECIMAL '1.00', DECIMAL
'0.0')) t(a, b)
+----
+1.00
+
+query T
+SELECT CASE WHEN false THEN DECIMAL '1.00' ELSE DECIMAL '0.0' END
+----
+0.00
+
+# Same as above but won't constant fold
+query T
+SELECT CASE WHEN false THEN a ELSE b END FROM (VALUES (DECIMAL '1.00', DECIMAL
'0.0')) t(a, b)
+----
+0.00
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImpl.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImpl.java
index ed337b02a9..bb6a35ab12 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImpl.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImpl.java
@@ -22,6 +22,7 @@ import static
org.apache.ignite.internal.util.CollectionUtils.nullOrEmpty;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -47,6 +48,7 @@ import org.apache.calcite.linq4j.tree.Expression;
import org.apache.calcite.linq4j.tree.Expressions;
import org.apache.calcite.linq4j.tree.MethodDeclaration;
import org.apache.calcite.linq4j.tree.ParameterExpression;
+import org.apache.calcite.linq4j.tree.Primitive;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelFieldCollation;
@@ -65,6 +67,7 @@ import org.apache.calcite.rex.RexProgramBuilder;
import org.apache.calcite.rex.RexShuttle;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.type.SqlTypeUtil;
import org.apache.calcite.sql.validate.SqlConformance;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
@@ -83,6 +86,7 @@ import
org.apache.ignite.internal.sql.engine.prepare.bounds.SearchBounds;
import org.apache.ignite.internal.sql.engine.rex.IgniteRexBuilder;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
import org.apache.ignite.internal.sql.engine.util.Commons;
+import org.apache.ignite.internal.sql.engine.util.IgniteMath;
import org.apache.ignite.internal.sql.engine.util.IgniteMethod;
import org.apache.ignite.internal.sql.engine.util.Primitives;
import org.apache.ignite.internal.sql.engine.util.TypeUtils;
@@ -346,14 +350,25 @@ public class ExpressionFactoryImpl<RowT> implements
ExpressionFactory<RowT> {
}
private @Nullable Object literalValue(RexLiteral literal, Class<?> type) {
- Object val = literal.getValueAs(type);
+ RelDataType dataType = literal.getType();
- // Literal was parsed as UTC timestamp, now we need to adjust it to
the client's time zone.
- if (val != null && literal.getTypeName() ==
SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE) {
- return IgniteSqlFunctions.subtractTimeZoneOffset((long) val,
(TimeZone) ctx.get(Variable.TIME_ZONE.camelName));
- }
+ if (SqlTypeUtil.isNumeric(dataType)) {
+ BigDecimal value = (BigDecimal) literal.getValue();
+ if (value == null) {
+ return null;
+ }
+
+ return convertNumericLiteral(dataType, value, type);
+ } else {
+ Object val = literal.getValueAs(type);
+
+ // Literal was parsed as UTC timestamp, now we need to adjust it
to the client's time zone.
+ if (val != null && literal.getTypeName() ==
SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE) {
+ return IgniteSqlFunctions.subtractTimeZoneOffset((long) val,
(TimeZone) ctx.get(Variable.TIME_ZONE.camelName));
+ }
- return val;
+ return val;
+ }
}
/** {@inheritDoc} */
@@ -1207,4 +1222,68 @@ public class ExpressionFactoryImpl<RowT> implements
ExpressionFactory<RowT> {
return variable;
}
}
+
+ private static Object convertNumericLiteral(RelDataType dataType,
BigDecimal value, Class<?> type) {
+ Primitive primitive = Primitive.ofBoxOr(type);
+ assert primitive != null || type == BigDecimal.class : "Neither
primitive nor BigDecimal: " + type;
+
+ switch (dataType.getSqlTypeName()) {
+ case TINYINT:
+ byte b = IgniteMath.convertToByteExact(value);
+ if (primitive != null) {
+ return Primitives.convertPrimitiveExact(primitive, b);
+ } else {
+ return new BigDecimal(b);
+ }
+ case SMALLINT:
+ short s = IgniteMath.convertToShortExact(value);
+ if (primitive != null) {
+ return Primitives.convertPrimitiveExact(primitive, s);
+ } else {
+ return new BigDecimal(s);
+ }
+ case INTEGER:
+ int i = IgniteMath.convertToIntExact(value);
+ if (primitive != null) {
+ return Primitives.convertPrimitiveExact(primitive, i);
+ } else {
+ return new BigDecimal(i);
+ }
+ case BIGINT:
+ long l = IgniteMath.convertToLongExact(value);
+ if (primitive != null) {
+ return Primitives.convertPrimitiveExact(primitive, l);
+ } else {
+ return new BigDecimal(l);
+ }
+ case REAL:
+ case FLOAT:
+ float r = IgniteMath.convertToFloatExact(value);
+ if (primitive != null) {
+ return Primitives.convertPrimitiveExact(primitive, r);
+ } else {
+ // Preserve the exact form of a float value.
+ return new BigDecimal(Float.toString(r));
+ }
+ case DOUBLE:
+ double d = IgniteMath.convertToDoubleExact(value);
+ if (primitive != null) {
+ return Primitives.convertPrimitiveExact(primitive, d);
+ } else {
+ // Preserve the exact form of a double value.
+ return new BigDecimal(Double.toString(d));
+ }
+ case DECIMAL:
+ BigDecimal bd = IgniteSqlFunctions.toBigDecimal(value,
dataType.getPrecision(), dataType.getScale());
+ assert bd != null;
+
+ if (primitive != null) {
+ return Primitives.convertPrimitiveExact(primitive, bd);
+ } else {
+ return bd;
+ }
+ default:
+ throw new IllegalStateException("Unexpected numeric type: " +
dataType);
+ }
+ }
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
index 9dab3002b5..9af6157beb 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
@@ -93,6 +93,7 @@ import org.apache.calcite.util.ControlFlowException;
import org.apache.calcite.util.Pair;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
import org.apache.ignite.internal.sql.engine.util.IgniteMethod;
+import org.apache.ignite.internal.sql.engine.util.Primitives;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.locationtech.jts.geom.Geometry;
@@ -105,7 +106,7 @@ import org.locationtech.jts.geom.Geometry;
* 3. RexToLixTranslator#translateCast() BYTESTRING_TO_STRING,
STRING_TO_BYTESTRING special case converters.
* 4. RexToLixTranslator#translateCast() case INTERVAL_SECOND -> case
CHARACTER special case converters.
* 5. RexToLixTranslator#translateCast() case TIMESTAMP -> case CHAR special
case converters.
- * 6. RexToLixTranslator#translateLiteral() case DECIMAL special case
converters.
+ * 6. RexToLixTranslator#translateLiteral() case DECIMAL special case
converters. Primitive float/double conversion.
* 7. RexToLixTranslator#translateCast() ANY branch
* 8. EnumUtils.convert -> ConverterUtils.convert
*/
@@ -912,7 +913,7 @@ public class RexToLixTranslator implements
RexVisitor<RexToLixTranslator.Result>
final Primitive primitive = Primitive.ofBoxOr(javaClass);
final Comparable value = literal.getValueAs(Comparable.class);
if (primitive != null && value instanceof Number) {
- value2 = primitive.number((Number) value);
+ value2 = Primitives.convertPrimitiveExact(primitive,
(Number) value);
} else {
value2 = value;
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMath.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMath.java
index 88e612389a..21e9784679 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMath.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMath.java
@@ -41,6 +41,14 @@ public class IgniteMath {
private static final Float UPPER_LONG_FLOAT = (float) Long.MAX_VALUE;
private static final Float LOWER_LONG_FLOAT = (float) Long.MIN_VALUE;
+ private static final BigDecimal UPPER_DOUBLE_BIG_DECIMAL = new
BigDecimal(String.valueOf(Double.MAX_VALUE));
+ private static final BigDecimal LOWER_DOUBLE_BIG_DECIMAL =
UPPER_DOUBLE_BIG_DECIMAL.negate();
+ private static final BigDecimal UPPER_FLOAT_BIG_DECIMAL = new
BigDecimal(String.valueOf(Float.MAX_VALUE));
+ private static final BigDecimal LOWER_FLOAT_BIG_DECIMAL =
UPPER_FLOAT_BIG_DECIMAL.negate();
+
+ private static final double UPPER_FLOAT_DOUBLE = Float.MAX_VALUE;
+ private static final double LOWER_FLOAT_DOUBLE = -Float.MAX_VALUE;
+
/** Returns the sum of its arguments, throwing an exception if the result
overflows an {@code long}. */
public static long addExact(long x, long y) {
long r = x + y;
@@ -279,6 +287,13 @@ public class IgniteMath {
return x.longValue();
}
+ /** Cast value to {@code long}, throwing an exception if the result
overflows an {@code long}. */
+ public static long convertToLongExact(Number x) {
+ checkNumberLongBounds(BIGINT, x);
+
+ return x.longValue();
+ }
+
/** Cast value to {@code long}, throwing an exception if the result
overflows an {@code long}. */
public static long convertToLongExact(double x) {
if (x > Long.MAX_VALUE || x < Long.MIN_VALUE) {
@@ -410,6 +425,47 @@ public class IgniteMath {
}
}
+ /** Cast value to {@code float}, throwing an exception if the result
overflows. */
+ public static float convertToFloatExact(Number x) {
+ if (x instanceof BigDecimal) {
+ BigDecimal value = (BigDecimal) x;
+
+ if (value.compareTo(UPPER_FLOAT_BIG_DECIMAL) > 0) {
+ throw new SqlException(RUNTIME_ERR, "REAL out of range");
+ }
+ if (value.compareTo(LOWER_FLOAT_BIG_DECIMAL) < 0) {
+ throw new SqlException(RUNTIME_ERR, "REAL out of range");
+ }
+
+ return value.floatValue();
+ } else {
+ double v = x.doubleValue();
+ if (v > UPPER_FLOAT_DOUBLE || v < LOWER_FLOAT_DOUBLE) {
+ throw new SqlException(RUNTIME_ERR, "REAL out of range");
+ }
+
+ return x.floatValue();
+ }
+ }
+
+ /** Cast value to {@code double}, throwing an exception if the result
overflows. */
+ public static double convertToDoubleExact(Number x) {
+ if (x instanceof BigDecimal) {
+ BigDecimal value = (BigDecimal) x;
+ if (value.compareTo(UPPER_DOUBLE_BIG_DECIMAL) > 0) {
+ throw new SqlException(RUNTIME_ERR, "DOUBLE out of range");
+ }
+
+ if (value.compareTo(LOWER_DOUBLE_BIG_DECIMAL) < 0) {
+ throw new SqlException(RUNTIME_ERR, "DOUBLE out of range");
+ }
+
+ return value.doubleValue();
+ } else {
+ return x.doubleValue();
+ }
+ }
+
private static void checkNumberLongBounds(SqlTypeName type, Number x) {
if (x instanceof BigDecimal) {
if ((((BigDecimal) x).compareTo(UPPER_LONG_BIG_DECIMAL) < 0 &&
((BigDecimal) x).compareTo(LOWER_LONG_BIG_DECIMAL) > 0)) {
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Primitives.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Primitives.java
index a3da601dc7..b717a743b3 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Primitives.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Primitives.java
@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
+import org.apache.calcite.linq4j.tree.Primitive;
/**
* Primitives.
@@ -106,4 +107,30 @@ public final class Primitives {
return (unwrapped == null) ? type : unwrapped;
}
+
+ /**
+ * Converts the given numeric value into the given primitive type with
overflow checks.
+ *
+ * @param primitive Primitive type.
+ * @param value Numeric value.
+ * @return Number converted to the given primitive.
+ */
+ public static Number convertPrimitiveExact(Primitive primitive, Number
value) {
+ switch (primitive) {
+ case BYTE:
+ return IgniteMath.convertToByteExact(value);
+ case SHORT:
+ return IgniteMath.convertToShortExact(value);
+ case INT:
+ return IgniteMath.convertToIntExact(value);
+ case LONG:
+ return IgniteMath.convertToLongExact(value);
+ case FLOAT:
+ return IgniteMath.convertToFloatExact(value);
+ case DOUBLE:
+ return IgniteMath.convertToDoubleExact(value);
+ default:
+ throw new IllegalArgumentException("Unexpected primitive type:
" + primitive);
+ }
+ }
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
index 9070de185f..13f06e18f9 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
@@ -114,14 +114,14 @@ public class RexUtils {
/** Hash index permitted search operations. */
private static final EnumSet<SqlKind> HASH_SEARCH_OPS = EnumSet.of(EQUALS,
IS_NOT_DISTINCT_FROM);
- private static final BigDecimal MIN_DOUBLE_VALUE =
BigDecimal.valueOf(Double.MIN_VALUE);
-
private static final BigDecimal MAX_DOUBLE_VALUE =
BigDecimal.valueOf(Double.MAX_VALUE);
- private static final BigDecimal MIN_FLOAT_VALUE =
BigDecimal.valueOf(Float.MIN_VALUE);
+ private static final BigDecimal MIN_DOUBLE_VALUE =
MAX_DOUBLE_VALUE.negate();
private static final BigDecimal MAX_FLOAT_VALUE =
BigDecimal.valueOf(Float.MAX_VALUE);
+ private static final BigDecimal MIN_FLOAT_VALUE = MAX_FLOAT_VALUE.negate();
+
/**
* Builder.
* TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImplTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImplTest.java
index 739cf3d394..6bf85ca094 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImplTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImplTest.java
@@ -18,6 +18,7 @@
package org.apache.ignite.internal.sql.engine.exec.exp;
import static java.util.Collections.singletonList;
+import static
org.apache.ignite.internal.sql.engine.util.SqlTestUtils.assertThrowsSqlException;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -39,9 +40,12 @@ import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.UUID;
+import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
import org.apache.calcite.rel.RelCollations;
import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelFieldCollation.Direction;
@@ -61,6 +65,7 @@ import org.apache.calcite.rex.RexNode;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.type.BasicSqlType;
import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.type.SqlTypeName.Limit;
import org.apache.calcite.sql.validate.SqlConformanceEnum;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.ImmutableIntList;
@@ -79,6 +84,7 @@ import org.apache.ignite.internal.sql.engine.util.RexUtils;
import org.apache.ignite.internal.sql.engine.util.SqlTestUtils;
import org.apache.ignite.internal.sql.engine.util.TypeUtils;
import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
+import org.apache.ignite.lang.ErrorGroups.Sql;
import org.apache.ignite.network.NetworkAddress;
import org.apache.ignite.sql.ColumnType;
import org.jetbrains.annotations.Nullable;
@@ -629,7 +635,7 @@ public class ExpressionFactoryImplTest extends
BaseIgniteAbstractTest {
RexBuilder rexBuilder = Commons.rexBuilder();
IgniteTypeFactory tf = Commons.typeFactory();
- RelDataType intType = tf.createSqlType(SqlTypeName.INTEGER);
+ RelDataType intType =
tf.createTypeWithNullability(tf.createSqlType(SqlTypeName.INTEGER), true);
RelDataType rowType = new Builder(tf)
.add("c1", intType)
.build();
@@ -761,6 +767,109 @@ public class ExpressionFactoryImplTest extends
BaseIgniteAbstractTest {
assertEquals("42", actual);
}
+ @ParameterizedTest
+ @MethodSource("numericLiterals")
+ public void testConvertNumericExact(RexLiteral lit, RelDataType dataType,
@Nullable Object expected, boolean err) {
+ RelDataType rowType = new Builder(typeFactory).add("c1",
dataType).build();
+
+ if (!err) {
+ Object[] rowValues = expFactory.rowSource(List.of(lit)).get();
+ assertArrayEquals(new Object[]{expected}, rowValues, "rowSource");
+
+ Object[] litValues = expFactory.values(List.of(lit),
rowType).iterator().next();
+ assertArrayEquals(new Object[]{expected}, litValues, "values");
+ } else {
+ String errorMessage = "out of range";
+
+ Supplier<Object[]> rowExpr = expFactory.rowSource(List.of(lit));
+ assertThrowsSqlException(Sql.RUNTIME_ERR, errorMessage,
rowExpr::get);
+
+ assertThrowsSqlException(Sql.RUNTIME_ERR, errorMessage, () -> {
+ expFactory.values(List.of(lit), rowType).iterator().next();
+ });
+ }
+ }
+
+ private static Stream<Arguments> numericLiterals() {
+ RexBuilder rexBuilder = Commons.rexBuilder();
+ // Make literal function
+ BiFunction<Object, RelDataType, RexLiteral> makeLit = (v, t) ->
(RexLiteral) rexBuilder.makeLiteral(v, t, false, false);
+
+ RelDataType tinyInt =
Commons.typeFactory().createSqlType(SqlTypeName.TINYINT);
+ Object tinyIntMax = SqlTypeName.TINYINT.getLimit(true, Limit.OVERFLOW,
true, -1, -1);
+ Object tinyIntMin = SqlTypeName.TINYINT.getLimit(false,
Limit.OVERFLOW, true, -1, -1);
+
+ RelDataType shortType =
Commons.typeFactory().createSqlType(SqlTypeName.SMALLINT);
+ Object shortMax = SqlTypeName.SMALLINT.getLimit(true, Limit.OVERFLOW,
true, -1, -1);
+ Object shortMin = SqlTypeName.SMALLINT.getLimit(false, Limit.OVERFLOW,
true, -1, -1);
+
+ RelDataType intType =
Commons.typeFactory().createSqlType(SqlTypeName.INTEGER);
+ Object maxInt = SqlTypeName.INTEGER.getLimit(true, Limit.OVERFLOW,
true, -1, -1);
+ Object minInt = SqlTypeName.INTEGER.getLimit(false, Limit.OVERFLOW,
true, -1, -1);
+
+ RelDataType bigIntType =
Commons.typeFactory().createSqlType(SqlTypeName.BIGINT);
+ Object bigIntMax = SqlTypeName.BIGINT.getLimit(true, Limit.OVERFLOW,
true, -1, -1);
+ Object bigIntMin = SqlTypeName.BIGINT.getLimit(false, Limit.OVERFLOW,
true, -1, -1);
+
+ RelDataType realType =
Commons.typeFactory().createSqlType(SqlTypeName.REAL);
+ BigDecimal realMax = new
BigDecimal(String.valueOf(Float.MAX_VALUE)).add(BigDecimal.ONE);
+ Object realMin = realMax.negate();
+
+ RelDataType floatType =
Commons.typeFactory().createSqlType(SqlTypeName.FLOAT);
+ BigDecimal floatMax = new
BigDecimal(String.valueOf(Float.MAX_VALUE)).add(BigDecimal.ONE);
+ Object floatMin = realMax.negate();
+
+ RelDataType doubleType =
Commons.typeFactory().createSqlType(SqlTypeName.DOUBLE);
+ BigDecimal doubleMax = new
BigDecimal(String.valueOf(Double.MAX_VALUE)).add(BigDecimal.ONE);
+ Object doubleMin = doubleMax.negate();
+
+ // makeLiteral for decimal validates precision/scale, so it is not
possible to create a decimal literal
+ // that lies outside of the range
+ RelDataType decimal5 =
Commons.typeFactory().createSqlType(SqlTypeName.DECIMAL, 5);
+ RelDataType decimal52 =
Commons.typeFactory().createSqlType(SqlTypeName.DECIMAL, 5, 2);
+
+ return Stream.of(
+ // TINYINT
+ Arguments.of(makeLit.apply(BigDecimal.ONE, tinyInt), tinyInt,
(byte) 1, false),
+ Arguments.of(makeLit.apply(tinyIntMax, tinyInt), tinyInt,
null, true),
+ Arguments.of(makeLit.apply(tinyIntMin, tinyInt), tinyInt,
null, true),
+
+ // SMALLINT
+ Arguments.of(makeLit.apply(BigDecimal.ONE, shortType),
shortType, (short) 1, false),
+ Arguments.of(makeLit.apply(shortMax, shortType), shortType,
null, true),
+ Arguments.of(makeLit.apply(shortMin, shortType), shortType,
null, true),
+
+ // INT
+ Arguments.of(makeLit.apply(BigDecimal.ONE, intType), intType,
1, false),
+ Arguments.of(makeLit.apply(maxInt, intType), intType, null,
true),
+ Arguments.of(makeLit.apply(minInt, intType), intType, null,
true),
+
+ // BIGINT
+ Arguments.of(makeLit.apply(BigDecimal.ONE, bigIntType),
bigIntType, 1L, false),
+ Arguments.of(makeLit.apply(bigIntMax, bigIntType), bigIntType,
null, true),
+ Arguments.of(makeLit.apply(bigIntMin, bigIntType), bigIntType,
null, true),
+
+ // REAL
+ Arguments.of(makeLit.apply(BigDecimal.ONE, realType),
realType, 1.0f, false),
+ Arguments.of(makeLit.apply(realMax, realType), realType, null,
true),
+ Arguments.of(makeLit.apply(realMin, realType), realType, null,
true),
+
+ // FLOAT
+ Arguments.of(makeLit.apply(BigDecimal.ONE, floatType),
floatType, 1.0f, false),
+ Arguments.of(makeLit.apply(floatMax, floatType), floatType,
null, true),
+ Arguments.of(makeLit.apply(floatMin, floatType), floatType,
null, true),
+
+ // DOUBLE
+ Arguments.of(makeLit.apply(BigDecimal.ONE, doubleType),
doubleType, 1.0d, false),
+ Arguments.of(makeLit.apply(doubleMax, doubleType), doubleType,
null, true),
+ Arguments.of(makeLit.apply(doubleMin, doubleType), doubleType,
null, true),
+
+ // DECIMAL
+ Arguments.of(makeLit.apply(new BigDecimal("1"), decimal5),
decimal5, new BigDecimal("1"), false),
+ Arguments.of(makeLit.apply(new BigDecimal("1.0"), decimal52),
decimal52, new BigDecimal("1.00"), false)
+ );
+ }
+
private static List<Arguments> rowSourceTestArgs() {
EnumSet<ColumnType> ignoredTypes = EnumSet.of(
// Not supported.