You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by al...@apache.org on 2022/10/19 10:17:24 UTC

[ignite] branch master updated: IGNITE-13024 SQL Calcite: Support complex expressions in index search bounds - Fixes #10317.

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 99bcc7daa2f IGNITE-13024 SQL Calcite: Support complex expressions in index search bounds - Fixes #10317.
99bcc7daa2f is described below

commit 99bcc7daa2f7f69166a4a8a3dcef52005b54be3d
Author: Aleksey Plekhanov <pl...@gmail.com>
AuthorDate: Wed Oct 19 13:15:16 2022 +0300

    IGNITE-13024 SQL Calcite: Support complex expressions in index search bounds - Fixes #10317.
    
    Signed-off-by: Aleksey Plekhanov <pl...@gmail.com>
---
 .../processors/query/calcite/util/RexUtils.java    | 25 +++++++++++++++++++-
 .../CalciteBasicSecondaryIndexIntegrationTest.java | 25 ++++++++++++++++++++
 .../planner/IndexSearchBoundsPlannerTest.java      | 27 ++++++++++++++++++++++
 3 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/RexUtils.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/RexUtils.java
index 3bfeb4d2839..d32b89e254f 100644
--- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/RexUtils.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/RexUtils.java
@@ -653,7 +653,8 @@ public class RexUtils {
     private static boolean idxOpSupports(RexNode op) {
         return op instanceof RexLiteral
             || op instanceof RexDynamicParam
-            || op instanceof RexFieldAccess;
+            || op instanceof RexFieldAccess
+            || !containsRef(op);
     }
 
     /** */
@@ -776,6 +777,28 @@ public class RexUtils {
         return cors;
     }
 
+    /** */
+    private static Boolean containsRef(RexNode node) {
+        RexVisitor<Void> v = new RexVisitorImpl<Void>(true) {
+            @Override public Void visitInputRef(RexInputRef inputRef) {
+                throw Util.FoundOne.NULL;
+            }
+
+            @Override public Void visitLocalRef(RexLocalRef locRef) {
+                throw Util.FoundOne.NULL;
+            }
+        };
+
+        try {
+            node.accept(v);
+
+            return false;
+        }
+        catch (Util.FoundOne e) {
+            return true;
+        }
+    }
+
     /** Visitor for replacing scan local refs to input refs. */
     private static class LocalRefReplacer extends RexShuttle {
         /** */
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/CalciteBasicSecondaryIndexIntegrationTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/CalciteBasicSecondaryIndexIntegrationTest.java
index 54a62ddec35..31c9e77f404 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/CalciteBasicSecondaryIndexIntegrationTest.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/CalciteBasicSecondaryIndexIntegrationTest.java
@@ -1158,6 +1158,31 @@ public class CalciteBasicSecondaryIndexIntegrationTest extends AbstractBasicInte
             .check();
     }
 
+    /**
+     * Test index search bounds on complex index expression.
+     */
+    @Test
+    public void testComplexIndexExpression() {
+        assertQuery("SELECT id FROM Developer WHERE depId BETWEEN ? - 1 AND ? + 1")
+            .withParams(20, 20)
+            .matches(containsIndexScan("PUBLIC", "DEVELOPER", DEPID_IDX))
+            .returns(20)
+            .returns(21)
+            .returns(22)
+            .check();
+
+        assertQuery("SELECT id FROM Birthday WHERE name = SUBSTRING(?::VARCHAR, 1, 4)")
+            .withParams("BachBach")
+            .matches(containsIndexScan("PUBLIC", "BIRTHDAY", NAME_DATE_IDX))
+            .returns(3)
+            .check();
+
+        assertQuery("SELECT id FROM Birthday WHERE name = SUBSTRING(name, 1, 4)")
+            .matches(containsTableScan("PUBLIC", "BIRTHDAY"))
+            .returns(3)
+            .check();
+    }
+
     /** */
     private static class Developer {
         /** */
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/IndexSearchBoundsPlannerTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/IndexSearchBoundsPlannerTest.java
index 6849e3c393a..528565e71c7 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/IndexSearchBoundsPlannerTest.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/IndexSearchBoundsPlannerTest.java
@@ -423,6 +423,33 @@ public class IndexSearchBoundsPlannerTest extends AbstractPlannerTest {
         );
     }
 
+    /** Tests complex bounds expressions. */
+    @Test
+    public void testBoundsComplex() throws Exception {
+        assertBounds("SELECT * FROM TEST WHERE C1 = ? + 10",
+            exact("+(?0, 10)")
+        );
+
+        assertBounds("SELECT * FROM TEST WHERE C1 = 1 AND C2 > SUBSTRING(?::VARCHAR, 1, 2) || '3'",
+            exact(1),
+            range("||(SUBSTRING(?0, 1, 2), _UTF-8'3')", null, false, true)
+        );
+
+        assertBounds("SELECT * FROM TEST WHERE C1 = 1 AND C2 > SUBSTRING(C3::VARCHAR, 1, 2) || '3'",
+            exact(1),
+            empty()
+        );
+
+        assertBounds("SELECT (SELECT C1 FROM TEST t2 WHERE t2.C1 = t1.C1 + t1.C3 * ?) FROM TEST t1",
+            exact("+($cor0.C1, *($cor0.C3, ?0))")
+        );
+
+        assertPlan("SELECT * FROM TEST WHERE C1 = ? + C3", publicSchema, isTableScan("TEST"));
+
+        assertPlan("SELECT (SELECT C1 FROM TEST t2 WHERE t2.C1 < t1.C1 + t2.C1) FROM TEST t1", publicSchema,
+            nodeOrAnyChild(isIndexScan("TEST", "C1C2C3")).negate());
+    }
+
     /** String representation of LEAST or CREATEST operator converted to CASE. */
     private String leastOrGreatest(boolean least, String val0, String val1, String type) {
         return "CASE(OR(IS NULL(" + val0 + "), IS NULL(" + val1 + ")), null:" + type + ", " + (least ? '<' : '>') +