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

zstan 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 65fd2caf88 IGNITE-19976: Sql. ClassCastException when trying to select 
from indexed smallint column (#3377)
65fd2caf88 is described below

commit 65fd2caf88e486bc53e9d01aaf3b2a74c1ec134b
Author: Max Zhuravkov <[email protected]>
AuthorDate: Thu Mar 14 09:26:53 2024 +0200

    IGNITE-19976: Sql. ClassCastException when trying to select from indexed 
smallint column (#3377)
---
 .../internal/sql/engine/ItSecondaryIndexTest.java  |  41 ++++
 .../ignite/internal/sql/engine/util/RexUtils.java  |  34 ++--
 .../planner/IndexSearchBoundsPlannerTest.java      | 223 ++++++++++++++++-----
 3 files changed, 240 insertions(+), 58 deletions(-)

diff --git 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
index 1e40ffc988..2a69a53ab1 100644
--- 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
+++ 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItSecondaryIndexTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.sql.engine;
 
+import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
 import static 
org.apache.ignite.internal.sql.engine.util.QueryChecker.containsAnyProject;
 import static 
org.apache.ignite.internal.sql.engine.util.QueryChecker.containsAnyScan;
 import static 
org.apache.ignite.internal.sql.engine.util.QueryChecker.containsIndexScan;
@@ -28,12 +29,15 @@ import static org.hamcrest.Matchers.not;
 
 import java.time.LocalDate;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.ignite.internal.sql.BaseSqlIntegrationTest;
 import org.apache.ignite.internal.sql.engine.rel.IgniteKeyValueGet;
 import org.apache.ignite.internal.sql.engine.util.QueryChecker;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
 
 /**
  * Basic index tests.
@@ -47,6 +51,8 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
 
     private static final String NAME_DATE_IDX = "NAME_DATE_IDX";
 
+    private static final AtomicInteger TABLE_IDX = new AtomicInteger();
+
     /**
      * Before all.
      */
@@ -1113,4 +1119,39 @@ public class ItSecondaryIndexTest extends 
BaseSqlIntegrationTest {
                 .returns(1)
                 .check();
     }
+
+    @ParameterizedTest
+    @CsvSource(value = {
+            // type, literal
+            "TINYINT;50",
+            "TINYINT;50::BIGINT",
+            "TINYINT;50::DECIMAL(10)",
+            "TINYINT;50::REAL",
+
+            "REAL;50.00",
+            "REAL;50.00::REAL",
+            "REAL;50.00::DOUBLE",
+            "REAL;50",
+
+            "DOUBLE;50.00",
+            "DOUBLE;50.00::REAL",
+            "DOUBLE;50.00::DECIMAL(10,2)",
+            "DOUBLE;50",
+
+            "DECIMAL(10, 2);50.00", // DECIMAL(10,2)
+            "DECIMAL(10, 2);50.00::REAL",
+            "DECIMAL(10, 2);50.00::DOUBLE",
+            "DECIMAL(10, 2);50",
+    }, delimiter = ';')
+    public void testTypeCastsIndexBounds(String type, String val) {
+        int id = TABLE_IDX.getAndIncrement();
+
+        sql(format("create table tt_{}(id INTEGER PRIMARY KEY, field_1 {})", 
id, type, val));
+
+        sql(format("SELECT * FROM tt_{} WHERE field_1 = {}", id, val));
+
+        sql(format("CREATE INDEX tt_idx_{} ON tt_{} (field_1)", id, id));
+
+        sql(format("SELECT * FROM tt_{} WHERE field_1 = {}", id, val));
+    }
 }
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 d54920f62a..6dffd47ec0 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
@@ -947,9 +947,13 @@ public class RexUtils {
     }
 
     /**
-     * If the given node is a numeric literal, checks whether it the cast to 
{@code type} overflows
-     * and in that case performs {@code saturated cast}, converting a value of 
that literal to the largest value of that type.
-     * If overflow does can not occur, returns the same node.
+     * If the given node is a numeric literal, checks whether its cast to 
{@code type} overflows and in that case
+     * performs {@code saturated cast}, converting a value of that literal to 
the largest value of that type.
+     *
+     * <p>If overflow does can not occur, returns a literal wrapped in a cast 
to {@code type}, because values search bounds
+     * in index lookups/scans should exactly match to types of database 
columns.
+     *
+     * <p>Otherwise returns {@code null}.
      */
     @Nullable
     private static RexLiteral toSaturatedValue(RexBuilder builder, RexNode 
node, RelDataType type) {
@@ -982,21 +986,25 @@ public class RexUtils {
             exact = true;
         }
 
+        BigDecimal newVal;
+
         if (lower.compareTo(val) > 0) {
-            if (exact) {
-                return builder.makeExactLiteral(lower, type);
-            } else {
-                return builder.makeApproxLiteral(lower, type);
-            }
+            newVal = lower;
         } else if (val.compareTo(upper) > 0) {
-            if (exact) {
-                return builder.makeExactLiteral(upper, type);
-            } else {
-                return builder.makeApproxLiteral(upper, type);
-            }
+            newVal = upper;
+        } else if (!SqlTypeUtil.equalSansNullability(node.getType(), type)) {
+            newVal = val;
         } else {
+            // If literal types and required type, match ignoring nullability,
+            // then return a literal as is.
             return lit;
         }
+
+        if (exact) {
+            return builder.makeExactLiteral(newVal, type);
+        } else {
+            return builder.makeApproxLiteral(newVal, type);
+        }
     }
 
     /** Visitor for replacing scan local refs to input refs. */
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java
index 5d35473d5f..ed3349185b 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java
@@ -18,11 +18,13 @@
 package org.apache.ignite.internal.sql.engine.planner;
 
 import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
@@ -33,8 +35,10 @@ import java.util.stream.Stream;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.type.SqlTypeUtil;
+import org.apache.ignite.internal.logger.IgniteLogger;
+import org.apache.ignite.internal.logger.Loggers;
 import 
org.apache.ignite.internal.sql.engine.framework.TestBuilders.TableBuilder;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.ExactBounds;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.MultiBounds;
@@ -42,6 +46,7 @@ import 
org.apache.ignite.internal.sql.engine.prepare.bounds.RangeBounds;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.SearchBounds;
 import org.apache.ignite.internal.sql.engine.rel.IgniteIndexScan;
 import org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Collation;
+import org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Type;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
 import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
 import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
@@ -59,6 +64,8 @@ import org.junit.jupiter.params.provider.MethodSource;
  * Index bounds check tests.
  */
 public class IndexSearchBoundsPlannerTest extends AbstractPlannerTest {
+    private static final IgniteLogger LOG = 
Loggers.forClass(IndexSearchBoundsPlannerTest.class);
+
     private static List<String> NODES = new ArrayList<>(4);
 
     private IgniteSchema publicSchema;
@@ -452,62 +459,177 @@ public class IndexSearchBoundsPlannerTest extends 
AbstractPlannerTest {
         assertBounds("SELECT * FROM test2 WHERE C2 = " + value, List.of(), 
schema, bounds);
     }
 
-    private static Stream<Arguments> boundsTypeLimits() {
-        RelDataType tinyintType = 
TYPE_FACTORY.createSqlType(SqlTypeName.TINYINT);
-        byte[] tinyIntTypeLimits = {Byte.MIN_VALUE, Byte.MAX_VALUE};
+    @ParameterizedTest
+    @MethodSource("indexTypeAndNumericsInBounds")
+    public void testCorrectNumericIndexInBounds(
+            Type indexType,
+            RelDataType columnType,
+            String valueExpr,
+            String boundExpr,
+            RelDataType boundExprType) throws Exception {
+
+        UnaryOperator<TableBuilder> tableB = tableB("TEST2", "C2", columnType);
+
+        IgniteSchema schema;
+        if (indexType == Type.HASH) {
+            schema = createSchemaFrom(tableB.andThen(addHashIndex("C2")));
+        } else {
+            schema = createSchemaFrom(tableB.andThen(addSortIndex("C2")));
+        }
 
-        RelDataType smallIntType = 
TYPE_FACTORY.createSqlType(SqlTypeName.SMALLINT);
-        short[] smallIntLimits = {Short.MIN_VALUE, Short.MAX_VALUE};
+        assertBounds("SELECT * FROM test2 WHERE C2 = " + valueExpr, List.of(), 
schema, searchBounds -> {
+            if (!(searchBounds instanceof ExactBounds)) {
+                log.info("SearchBound type does not match. Expected {} but got 
{}", ExactBounds.class, searchBounds);
+                return false;
+            }
 
-        RelDataType intType = TYPE_FACTORY.createSqlType(SqlTypeName.INTEGER);
-        int[] intLimits = {Integer.MIN_VALUE, Integer.MAX_VALUE};
+            ExactBounds exactBounds = (ExactBounds) searchBounds;
+            RexNode rexNode = exactBounds.bound();
 
-        RelDataType bigIntType = 
TYPE_FACTORY.createSqlType(SqlTypeName.BIGINT);
-        BigDecimal[] bigIntTypeLimits = {BigDecimal.valueOf(Long.MIN_VALUE), 
BigDecimal.valueOf(Long.MAX_VALUE)};
+            if (!SqlTypeUtil.equalSansNullability(boundExprType, 
rexNode.getType())) {
+                log.info("Bound type does not match. Expected {} but got {}", 
boundExprType, rexNode.getType());
+                return false;
+            }
 
-        RelDataType decimal3Type = 
TYPE_FACTORY.createSqlType(SqlTypeName.DECIMAL, 3);
-        BigDecimal[] decimal3TypeLimits = {BigDecimal.valueOf(-999), 
BigDecimal.valueOf(999)};
-        RelDataType decimal53Type = 
TYPE_FACTORY.createSqlType(SqlTypeName.DECIMAL, 5, 3);
-        BigDecimal[] decimal53TypeLimits = {new BigDecimal("-99.999"), new 
BigDecimal("99.999")};
+            if (!boundExpr.equals(rexNode.toString())) {
+                log.info("Bound expr does not match. Expected {} but got {}", 
boundExpr, rexNode);
+                return false;
+            }
+
+            return true;
+        });
+    }
+
+    private static Stream<Arguments> indexTypeAndNumericsInBounds() {
+        Stream<Arguments> result = Stream.of();
+
+        for (Type type : Type.values()) {
+            Stream<Arguments> idx = numericsInBounds().map(a -> {
+                Object[] v = a.get();
+
+                Object[] newArgs = new Object[v.length + 1];
+                newArgs[0] = type;
+                System.arraycopy(v, 0, newArgs, 1, v.length);
+
+                return arguments(newArgs);
+            });
+            result = Stream.concat(result, idx);
+        }
+
+        return result;
+    }
 
+    private static Stream<Arguments> numericsInBounds() {
         return Stream.of(
-                Arguments.arguments(tinyintType, -129, 
exact(tinyIntTypeLimits[0])),
-                Arguments.arguments(tinyintType, -128, 
exact(tinyIntTypeLimits[0])),
-                Arguments.arguments(tinyintType, 127, 
exact(tinyIntTypeLimits[1])),
-                Arguments.arguments(tinyintType, 128, 
exact(tinyIntTypeLimits[1])),
+            // Column type, expr to use in search condition, expected 
expression in search bounds as RexNode::toString, its type.
+
+            arguments(sqlType(SqlTypeName.TINYINT), "42", "42:TINYINT", 
sqlType(SqlTypeName.TINYINT)),
+            arguments(sqlType(SqlTypeName.TINYINT), "CAST(42 AS TINYINT)", 
"42:TINYINT", sqlType(SqlTypeName.TINYINT)),
+            arguments(sqlType(SqlTypeName.TINYINT), "CAST(42 AS SMALLINT)", 
"42:TINYINT", sqlType(SqlTypeName.TINYINT)),
+            arguments(sqlType(SqlTypeName.TINYINT), "CAST(42 AS INTEGER)", 
"42:TINYINT", sqlType(SqlTypeName.TINYINT)),
+            arguments(sqlType(SqlTypeName.TINYINT), "CAST(42 AS BIGINT)", 
"42:TINYINT", sqlType(SqlTypeName.TINYINT)),
+
+            arguments(sqlType(SqlTypeName.SMALLINT), "42", "42:SMALLINT", 
sqlType(SqlTypeName.SMALLINT)),
+            arguments(sqlType(SqlTypeName.SMALLINT), "CAST(42 AS TINYINT)", 
"42:SMALLINT", sqlType(SqlTypeName.SMALLINT)),
+            arguments(sqlType(SqlTypeName.SMALLINT), "CAST(42 AS SMALLINT)", 
"42:SMALLINT", sqlType(SqlTypeName.SMALLINT)),
+            arguments(sqlType(SqlTypeName.SMALLINT), "CAST(42 AS INTEGER)", 
"42:SMALLINT", sqlType(SqlTypeName.SMALLINT)),
+            arguments(sqlType(SqlTypeName.SMALLINT), "CAST(42 AS BIGINT)", 
"42:SMALLINT", sqlType(SqlTypeName.SMALLINT)),
+
+            arguments(sqlType(SqlTypeName.INTEGER), "42", "42", 
sqlType(SqlTypeName.INTEGER)),
+            arguments(sqlType(SqlTypeName.INTEGER), "CAST(42 AS TINYINT)", 
"42", sqlType(SqlTypeName.INTEGER)),
+            arguments(sqlType(SqlTypeName.INTEGER), "CAST(42 AS SMALLINT)", 
"42", sqlType(SqlTypeName.INTEGER)),
+            arguments(sqlType(SqlTypeName.INTEGER), "CAST(42 AS INTEGER)", 
"42", sqlType(SqlTypeName.INTEGER)),
+            arguments(sqlType(SqlTypeName.INTEGER), "CAST(42 AS BIGINT)", 
"42", sqlType(SqlTypeName.INTEGER)),
+
+            arguments(sqlType(SqlTypeName.BIGINT), "42", "42:BIGINT", 
sqlType(SqlTypeName.BIGINT)),
+            arguments(sqlType(SqlTypeName.BIGINT), "CAST(42 AS TINYINT)", 
"42:BIGINT", sqlType(SqlTypeName.BIGINT)),
+            arguments(sqlType(SqlTypeName.BIGINT), "CAST(42 AS SMALLINT)", 
"42:BIGINT", sqlType(SqlTypeName.BIGINT)),
+            arguments(sqlType(SqlTypeName.BIGINT), "CAST(42 AS INTEGER)", 
"42:BIGINT", sqlType(SqlTypeName.BIGINT)),
+            arguments(sqlType(SqlTypeName.BIGINT), "CAST(42 AS BIGINT)", 
"42:BIGINT", sqlType(SqlTypeName.BIGINT)),
+
+            arguments(sqlType(SqlTypeName.REAL), "42", "42:REAL", 
sqlType(SqlTypeName.REAL)),
+            arguments(sqlType(SqlTypeName.DOUBLE), "42", "42:DOUBLE", 
sqlType(SqlTypeName.DOUBLE))
+
+        // TODO https://issues.apache.org/jira/browse/IGNITE-19881 uncomment 
after this issue is fixed
+        //  The optimizer selects TableScan instead of a IndexScan 
(Real/double columns)
+        // arguments(sqlType(SqlTypeName.REAL), "CAST(42 AS DOUBLE)", 
"42:REAL", sqlType(SqlTypeName.REAL)),
+        // arguments(sqlType(SqlTypeName.DOUBLE), "CAST(42 AS REAL)", 
"42:DOUBLE", sqlType(SqlTypeName.DOUBLE)),
+        // TODO https://issues.apache.org/jira/browse/IGNITE-19882 uncomment 
after this issue is fixed
+        //  The optimizer selects TableScan instead of a IndexScan (Decimal 
columns)
+        // arguments(sqlType(SqlTypeName.DECIMAL, 5), "42", "42:DECIMAL(10, 
0)", sqlType(SqlTypeName.DECIMAL, 5, 0)),
+        // arguments(sqlType(SqlTypeName.DECIMAL, 10, 2), "42", 
"42:DECIMAL(10, 2)", sqlType(SqlTypeName.DECIMAL, 10, 2)),
+        // arguments(sqlType(SqlTypeName.INTEGER), "CAST(42 AS DECIMAL(10))", 
"42", sqlType(SqlTypeName.INTEGER)),
+        );
+    }
 
-                Arguments.arguments(smallIntType, (-(int) Math.pow(2, 15) - 
1), exact(smallIntLimits[0])),
-                Arguments.arguments(smallIntType, (-(int) Math.pow(2, 15)), 
exact(smallIntLimits[0])),
-                Arguments.arguments(smallIntType, ((int) Math.pow(2, 15)), 
exact(smallIntLimits[1])),
-                Arguments.arguments(smallIntType, ((int) Math.pow(2, 15) + 1), 
exact(smallIntLimits[1])),
+    private static Stream<Arguments> boundsTypeLimits() {
+        RelDataType tinyintType = sqlType(SqlTypeName.TINYINT);
+        byte[] tinyIntTypeLimits = {Byte.MIN_VALUE, Byte.MAX_VALUE};
+        List<Arguments> tinyInts = List.of(
+                arguments(tinyintType, -129, exact(tinyIntTypeLimits[0])),
+                arguments(tinyintType, -128, exact(tinyIntTypeLimits[0])),
+                arguments(tinyintType, 127, exact(tinyIntTypeLimits[1])),
+                arguments(tinyintType, 128, exact(tinyIntTypeLimits[1]))
+        );
 
-                Arguments.arguments(intType, (-(long) Math.pow(2, 31) - 1), 
exact(intLimits[0])),
-                Arguments.arguments(intType, (-(long) Math.pow(2, 31)), 
exact(intLimits[0])),
-                Arguments.arguments(intType, ((long) Math.pow(2, 31)), 
exact(intLimits[1])),
-                Arguments.arguments(intType, ((long) Math.pow(2, 31) + 1), 
exact(intLimits[1])),
+        RelDataType smallIntType = sqlType(SqlTypeName.SMALLINT);
+        short[] smallIntLimits = {Short.MIN_VALUE, Short.MAX_VALUE};
+        List<Arguments> smallInts = List.of(
+                arguments(smallIntType, (-(int) Math.pow(2, 15) - 1), 
exact(smallIntLimits[0])),
+                arguments(smallIntType, (-(int) Math.pow(2, 15)), 
exact(smallIntLimits[0])),
+                arguments(smallIntType, ((int) Math.pow(2, 15)), 
exact(smallIntLimits[1])),
+                arguments(smallIntType, ((int) Math.pow(2, 15) + 1), 
exact(smallIntLimits[1]))
+        );
 
-                Arguments.arguments(decimal3Type, "(-1000)::DECIMAL(3)", 
exact(decimal3TypeLimits[0])),
-                Arguments.arguments(decimal3Type, "(-999)::DECIMAL(3)", 
exact(decimal3TypeLimits[0])),
-                Arguments.arguments(decimal3Type, "999::DECIMAL(3)", 
exact(decimal3TypeLimits[1])),
-                Arguments.arguments(decimal3Type, "1000::DECIMAL(3)", 
exact(decimal3TypeLimits[1])),
+        RelDataType intType = sqlType(SqlTypeName.INTEGER);
+        int[] intLimits = {Integer.MIN_VALUE, Integer.MAX_VALUE};
+        List<Arguments> ints = List.of(
+                arguments(intType, (-(long) Math.pow(2, 31) - 1), 
exact(intLimits[0])),
+                arguments(intType, (-(long) Math.pow(2, 31)), 
exact(intLimits[0])),
+                arguments(intType, ((long) Math.pow(2, 31)), 
exact(intLimits[1])),
+                arguments(intType, ((long) Math.pow(2, 31) + 1), 
exact(intLimits[1]))
+        );
 
-                Arguments.arguments(decimal53Type, "(-100.000)::DECIMAL(5, 
3)", exact(decimal53TypeLimits[0])),
-                Arguments.arguments(decimal53Type, "(100.000)::DECIMAL(5, 3)", 
exact(decimal53TypeLimits[1])),
+        RelDataType bigIntType = sqlType(SqlTypeName.BIGINT);
+        BigDecimal[] bigIntTypeLimits = {BigDecimal.valueOf(Long.MIN_VALUE), 
BigDecimal.valueOf(Long.MAX_VALUE)};
+        List<Arguments> bigints = List.of(
+                arguments(bigIntType, BigInteger.TWO.pow(63).negate(), 
exact(bigIntTypeLimits[0]))
+        );
 
-                // TODO https://issues.apache.org/jira/browse/IGNITE-19858
-                //  Cause serialization/deserialization mismatch in 
AbstractPlannerTest::checkSplitAndSerialization
-                // Arguments.arguments(bigIntType, 
BigInteger.TWO.pow(63).add(BigInteger.ONE).negate(),
-                //        exact(bigIntTypeLimits[0])),
-                // Arguments.arguments(bigIntType, BigInteger.TWO.pow(63), 
exact(bigIntTypeLimits[1])),
-                // Arguments.arguments(bigIntType, 
BigInteger.TWO.pow(63).add(BigInteger.ONE), exact(bigIntTypeLimits[1])),
+        RelDataType decimal3Type = sqlType(SqlTypeName.DECIMAL, 3);
+        BigDecimal[] decimal3TypeLimits = {BigDecimal.valueOf(-999), 
BigDecimal.valueOf(999)};
+        List<Arguments> decimal3s = List.of(
+                arguments(decimal3Type, "(-1000)::DECIMAL(3)", 
exact(decimal3TypeLimits[0])),
+                arguments(decimal3Type, "(-999)::DECIMAL(3)", 
exact(decimal3TypeLimits[0])),
+                arguments(decimal3Type, "999::DECIMAL(3)", 
exact(decimal3TypeLimits[1])),
+                arguments(decimal3Type, "1000::DECIMAL(3)", 
exact(decimal3TypeLimits[1]))
+        );
 
-                // Arguments.arguments(realType, 
BigDecimal.valueOf(Float.MAX_VALUE).add(BigDecimal.ONE) + "::REAL",
-                //        exact(Float.MAX_VALUE)),
+        RelDataType decimal53Type = sqlType(SqlTypeName.DECIMAL, 5, 3);
+        BigDecimal[] decimal53TypeLimits = {new BigDecimal("-99.999"), new 
BigDecimal("99.999")};
 
-                // Arguments.arguments(realType, 
BigDecimal.valueOf(Double.MAX_VALUE).add(BigDecimal.ONE),
-                //        exact(Double.MAX_VALUE)),
-                Arguments.arguments(bigIntType, 
BigInteger.TWO.pow(63).negate(), exact(bigIntTypeLimits[0]))
+        List<Arguments> decimal35s = List.of(
+                arguments(decimal53Type, "(-100.000)::DECIMAL(5, 3)", 
exact(decimal53TypeLimits[0])),
+                arguments(decimal53Type, "(100.000)::DECIMAL(5, 3)", 
exact(decimal53TypeLimits[1]))
         );
+
+        // TODO https://issues.apache.org/jira/browse/IGNITE-19858
+        //  Cause serialization/deserialization mismatch in 
AbstractPlannerTest::checkSplitAndSerialization
+        //
+        //  RelDataType realType = 
TYPE_FACTORY.createSqlType(SqlTypeName.REAL);
+        //  List<Arguments> reals = List.of(
+        //          arguments(realType, 
BigDecimal.valueOf(Float.MAX_VALUE).add(BigDecimal.ONE) + "::REAL", 
exact(Float.MAX_VALUE)),
+        //          arguments(realType, 
BigDecimal.valueOf(Double.MAX_VALUE).add(BigDecimal.ONE), 
exact(Double.MAX_VALUE))
+        //  );
+
+        return Stream.of(
+                tinyInts,
+                smallInts,
+                ints,
+                bigints,
+                decimal3s,
+                decimal35s
+        ).flatMap(Collection::stream);
     }
 
     private static Predicate<SearchBounds> exact(Object val) {
@@ -540,6 +662,7 @@ public class IndexSearchBoundsPlannerTest extends 
AbstractPlannerTest {
     private static boolean matchBounds(List<SearchBounds> searchBounds, 
Predicate<SearchBounds>... predicates) {
         for (int i = 0; i < predicates.length; i++) {
             if (!predicates[i].test(searchBounds.get(i))) {
+                LOG.info("{} bounds do not not match: {}", 
searchBounds.get(i), predicates[i]);
                 return false;
             }
         }
@@ -565,13 +688,23 @@ public class IndexSearchBoundsPlannerTest extends 
AbstractPlannerTest {
         return named(range, format("{}{}, {}{}", lc, lower, upper, uc));
     }
 
+    private static RelDataType sqlType(SqlTypeName typeName) {
+        return TYPE_FACTORY.createSqlType(typeName);
+    }
+
+    private static RelDataType sqlType(SqlTypeName typeName, int precision) {
+        return TYPE_FACTORY.createSqlType(typeName, precision);
+    }
+
+    private static RelDataType sqlType(SqlTypeName typeName, int precision, 
int scale) {
+        return TYPE_FACTORY.createSqlType(typeName, precision, scale);
+    }
+
     private static boolean matchValue(@Nullable Object val, RexNode bound) {
         if (val == null || bound == null) {
             return val == bound;
         }
 
-        bound = RexUtil.removeCast(bound);
-
         String actual = Objects.toString(bound instanceof RexLiteral ? 
((RexLiteral) bound).getValueAs(val.getClass()) : bound);
         String expected = Objects.toString(val);
         return expected.equals(actual);

Reply via email to