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

amashenkov 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 a3181aac513 IGNITE-25266 Sql. Implement accept(RexShuttle) on RelNodes 
that have expressions (#5855)
a3181aac513 is described below

commit a3181aac513fed8e71045d91742d9ea60c005904
Author: Andrew V. Mashenkov <[email protected]>
AuthorDate: Thu May 22 13:05:52 2025 +0300

    IGNITE-25266 Sql. Implement accept(RexShuttle) on RelNodes that have 
expressions (#5855)
---
 .../sql/engine/prepare/bounds/ExactBounds.java     | 14 ++++++++
 .../sql/engine/prepare/bounds/MultiBounds.java     | 15 ++++++++
 .../sql/engine/prepare/bounds/RangeBounds.java     | 15 ++++++++
 .../sql/engine/prepare/bounds/SearchBounds.java    |  8 ++++-
 .../internal/sql/engine/rel/AbstractIndexScan.java | 27 +++++++++-----
 .../sql/engine/rel/IgniteHashIndexSpool.java       |  9 +++--
 .../internal/sql/engine/rel/IgniteIndexScan.java   | 42 ++++++----------------
 .../internal/sql/engine/rel/IgniteKeyValueGet.java |  7 ++++
 .../sql/engine/rel/IgniteKeyValueModify.java       | 13 +++++++
 .../internal/sql/engine/rel/IgniteLimit.java       | 10 ++++--
 .../internal/sql/engine/rel/IgniteSelectCount.java | 13 +++++++
 .../sql/engine/rel/IgniteSortedIndexSpool.java     | 12 +++++--
 .../sql/engine/rel/IgniteSystemViewScan.java       |  6 ++++
 .../internal/sql/engine/rel/IgniteTableModify.java | 28 +++++++--------
 .../internal/sql/engine/rel/IgniteTableScan.java   | 38 ++++----------------
 .../engine/rel/ProjectableFilterableTableScan.java | 12 +++++--
 .../engine/rel/logical/IgniteLogicalIndexScan.java | 10 ++++++
 .../rel/logical/IgniteLogicalSystemViewScan.java   |  6 ++++
 .../engine/rel/logical/IgniteLogicalTableScan.java |  6 ++++
 .../ignite/internal/sql/engine/util/RexUtils.java  | 19 ++++++++++
 20 files changed, 211 insertions(+), 99 deletions(-)

diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/ExactBounds.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/ExactBounds.java
index fa24740e931..ec66cb95032 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/ExactBounds.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/ExactBounds.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.sql.engine.prepare.bounds;
 
 import java.util.Objects;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexShuttle;
 import org.apache.ignite.internal.tostring.S;
 
 /**
@@ -46,6 +47,19 @@ public class ExactBounds extends SearchBounds {
         return Type.EXACT;
     }
 
+    @Override
+    public SearchBounds accept(RexShuttle shuttle) {
+        RexNode condition = condition();
+        RexNode newCondition = shuttle.apply(condition);
+        RexNode newBound = shuttle.apply(bound);
+
+        if (newCondition == condition && newBound == bound) {
+            return this;
+        }
+
+        return new ExactBounds(newCondition, newBound);
+    }
+
     /** {@inheritDoc} */
     @Override
     public boolean equals(Object o) {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/MultiBounds.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/MultiBounds.java
index a7ace798ec7..0c04b5d4952 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/MultiBounds.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/MultiBounds.java
@@ -20,6 +20,8 @@ package org.apache.ignite.internal.sql.engine.prepare.bounds;
 import java.util.List;
 import java.util.Objects;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexShuttle;
+import org.apache.ignite.internal.sql.engine.util.RexUtils;
 import org.apache.ignite.internal.tostring.IgniteToStringInclude;
 import org.apache.ignite.internal.tostring.S;
 
@@ -48,6 +50,19 @@ public class MultiBounds extends SearchBounds {
         return Type.MULTI;
     }
 
+    @Override
+    public SearchBounds accept(RexShuttle shuttle) {
+        RexNode condition = condition();
+        RexNode newCondition = shuttle.apply(condition);
+        List<SearchBounds> newBounds = RexUtils.processSearchBounds(shuttle, 
bounds);
+
+        if (newCondition == condition && newBounds == bounds) {
+            return this;
+        }
+
+        return new MultiBounds(newCondition, newBounds);
+    }
+
     /** {@inheritDoc} */
     @Override
     public boolean equals(Object o) {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/RangeBounds.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/RangeBounds.java
index 590b5a485cd..4bf6e90fc78 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/RangeBounds.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/RangeBounds.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.sql.engine.prepare.bounds;
 
 import java.util.Objects;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexShuttle;
 import org.apache.ignite.internal.tostring.S;
 import org.jetbrains.annotations.Nullable;
 
@@ -95,6 +96,20 @@ public class RangeBounds extends SearchBounds {
         return Type.RANGE;
     }
 
+    @Override
+    public SearchBounds accept(RexShuttle shuttle) {
+        RexNode condition = condition();
+        RexNode newCondition = shuttle.apply(condition);
+        RexNode newLowerBound = shuttle.apply(lowerBound);
+        RexNode newUpperBound = shuttle.apply(upperBound);
+
+        if (newLowerBound == lowerBound && newUpperBound == upperBound && 
newCondition == condition) {
+            return this;
+        }
+
+        return new RangeBounds(condition, newLowerBound, newUpperBound, 
lowerInclude, upperInclude);
+    }
+
     /** {@inheritDoc} */
     @Override
     public boolean equals(Object o) {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/SearchBounds.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/SearchBounds.java
index e7ef3303c36..4a7534a4e4b 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/SearchBounds.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/bounds/SearchBounds.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.sql.engine.prepare.bounds;
 
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexShuttle;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -41,7 +42,7 @@ public abstract class SearchBounds {
     /**
      * Condition.
      */
-    public RexNode condition() {
+    public @Nullable RexNode condition() {
         return condition;
     }
 
@@ -50,6 +51,11 @@ public abstract class SearchBounds {
      */
     public abstract Type type();
 
+    /**
+     * Applies this shuttle and returns a new SearchBounds instance if changed.
+     */
+    public abstract SearchBounds accept(RexShuttle shuttle);
+
     /**
      * Search bounds type.
      */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/AbstractIndexScan.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/AbstractIndexScan.java
index 44f536100b7..fa16fa297cf 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/AbstractIndexScan.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/AbstractIndexScan.java
@@ -18,8 +18,6 @@
 package org.apache.ignite.internal.sql.engine.rel;
 
 import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptCost;
@@ -43,6 +41,7 @@ import 
org.apache.ignite.internal.sql.engine.prepare.bounds.SearchBounds;
 import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
 import org.apache.ignite.internal.sql.engine.schema.IgniteIndex.Type;
 import org.apache.ignite.internal.sql.engine.util.Commons;
+import org.apache.ignite.internal.sql.engine.util.RexUtils;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -103,18 +102,28 @@ public abstract class AbstractIndexScan extends 
ProjectableFilterableTableScan {
     /** {@inheritDoc} */
     @Override
     public RelNode accept(RexShuttle shuttle) {
-        if (searchBounds != null) {
-            List<RexNode> expressions = searchBounds.stream()
-                    .filter(Objects::nonNull)
-                    .map(SearchBounds::condition)
-                    .collect(Collectors.toList());
+        RexNode condition0 = shuttle.apply(condition);
+        List<RexNode> projects0 = shuttle.apply(projects);
+        List<SearchBounds> searchBounds0 = 
RexUtils.processSearchBounds(shuttle, searchBounds);
 
-            shuttle.apply(expressions);
+        if (condition0 == condition && projects0 == projects && searchBounds 
== searchBounds0) {
+            return this;
         }
 
-        return super.accept(shuttle);
+        return copy(projects0, condition0, searchBounds0);
     }
 
+    @Override
+    protected final ProjectableFilterableTableScan copy(@Nullable 
List<RexNode> newProjects, @Nullable RexNode newCondition) {
+        throw new IllegalStateException("Should never be called.");
+    }
+
+    protected abstract AbstractIndexScan copy(
+            @Nullable List<RexNode> newProjects,
+            @Nullable RexNode newCondition,
+            @Nullable List<SearchBounds> newSearchBounds
+    );
+
     /** Return index name. */
     public String indexName() {
         return idxName;
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteHashIndexSpool.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteHashIndexSpool.java
index 5f91c8edf79..7fb4848e835 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteHashIndexSpool.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteHashIndexSpool.java
@@ -101,9 +101,14 @@ public class IgniteHashIndexSpool extends 
AbstractIgniteSpool {
     /** {@inheritDoc} */
     @Override
     public RelNode accept(RexShuttle shuttle) {
-        shuttle.apply(cond);
+        RexNode condition0 = shuttle.apply(cond);
+        List<RexNode> searchRow0 = shuttle.apply(searchRow);
 
-        return super.accept(shuttle);
+        if (condition0 == cond && searchRow0 == searchRow) {
+            return this;
+        }
+
+        return new IgniteHashIndexSpool(getCluster(), getTraitSet(), 
getInput(), searchRow0, condition0, allowNulls);
     }
 
     @Override
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteIndexScan.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteIndexScan.java
index 05969322c0d..185eaf2e278 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteIndexScan.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteIndexScan.java
@@ -25,10 +25,8 @@ import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelInput;
-import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.SearchBounds;
 import org.apache.ignite.internal.sql.engine.schema.IgniteIndex;
@@ -157,36 +155,6 @@ public class IgniteIndexScan extends AbstractIndexScan 
implements SourceAwareIgn
         return visitor.visit(this);
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public RelNode accept(RexShuttle shuttle) {
-        RexNode newCondition = condition;
-        if (condition != null) {
-            newCondition = shuttle.apply(condition);
-        }
-
-        List<RexNode> newProjects = projects;
-        if (projects != null) {
-            newProjects = shuttle.apply(projects);
-        }
-
-        if (newCondition != condition || newProjects != projects) {
-            return new IgniteTableScan(
-                    sourceId,
-                    getCluster(),
-                    getTraitSet(),
-                    getHints(),
-                    getTable(),
-                    names,
-                    newProjects,
-                    newCondition,
-                    requiredColumns
-            );
-        } else {
-            return this;
-        }
-    }
-
     /** {@inheritDoc} */
     @Override
     public IgniteRel clone(long sourceId) {
@@ -201,6 +169,16 @@ public class IgniteIndexScan extends AbstractIndexScan 
implements SourceAwareIgn
                 idxName, type, collation, names, projects, condition, 
searchBounds, requiredColumns);
     }
 
+    @Override
+    protected IgniteIndexScan copy(
+            @Nullable List<RexNode> newProjects,
+            @Nullable RexNode newCondition,
+            @Nullable List<SearchBounds> newSearchBounds
+    ) {
+        return new IgniteIndexScan(sourceId, getCluster(), getTraitSet(), 
getTable(),
+                idxName, type, collation, names, newProjects, newCondition, 
newSearchBounds, requiredColumns);
+    }
+
     /** {@inheritDoc} */
     @Override
     public String getRelTypeName() {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteKeyValueGet.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteKeyValueGet.java
index 516b2f30a20..0bbf4d84678 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteKeyValueGet.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteKeyValueGet.java
@@ -93,6 +93,13 @@ public class IgniteKeyValueGet extends 
ProjectableFilterableTableScan implements
         );
     }
 
+    @Override
+    protected ProjectableFilterableTableScan copy(@Nullable List<RexNode> 
newProjects, @Nullable RexNode newCondition) {
+        return new IgniteKeyValueGet(
+                getCluster(), getTraitSet(), getTable(), getHints(), 
keyExpressions, names, newProjects, newCondition, requiredColumns
+        );
+    }
+
     /** {@inheritDoc} */
     @Override
     public IgniteKeyValueGet withHints(List<RelHint> hintList) {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteKeyValueModify.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteKeyValueModify.java
index 8bb7a251389..064136899d8 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteKeyValueModify.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteKeyValueModify.java
@@ -24,9 +24,11 @@ import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.AbstractRelNode;
 import org.apache.calcite.rel.RelInput;
+import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.ignite.internal.sql.engine.exec.TxAttributes;
 import org.apache.ignite.internal.sql.engine.exec.mapping.MappingService;
@@ -100,6 +102,17 @@ public class IgniteKeyValueModify extends AbstractRelNode 
implements IgniteRel {
         return visitor.visit(this);
     }
 
+    @Override
+    public RelNode accept(RexShuttle shuttle) {
+        List<RexNode> expressions0 = shuttle.apply(expressions);
+
+        if (expressions0 == expressions) {
+            return this;
+        }
+
+        return new IgniteKeyValueModify(getCluster(), getTraitSet(), table, 
operation, expressions0);
+    }
+
     /** {@inheritDoc} */
     @Override
     public IgniteRel clone(RelOptCluster cluster, List<IgniteRel> inputs) {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteLimit.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteLimit.java
index 55e3ae49768..60b1ec07a6b 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteLimit.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteLimit.java
@@ -111,10 +111,14 @@ public class IgniteLimit extends SingleRel implements 
IgniteRel {
     /** {@inheritDoc} */
     @Override
     public RelNode accept(RexShuttle shuttle) {
-        shuttle.apply(offset);
-        shuttle.apply(fetch);
+        RexNode offset0 = shuttle.apply(offset);
+        RexNode fetch0 = shuttle.apply(fetch);
 
-        return super.accept(shuttle);
+        if (offset0 == offset && fetch0 == fetch) {
+            return this;
+        }
+
+        return new IgniteLimit(getCluster(), getTraitSet(), getInput(), 
offset0, fetch0);
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSelectCount.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSelectCount.java
index 4c636dd9245..d16d5923cad 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSelectCount.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSelectCount.java
@@ -25,10 +25,12 @@ import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.AbstractRelNode;
 import org.apache.calcite.rel.RelInput;
+import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.ignite.internal.sql.engine.exec.mapping.MappingService;
 import org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCostFactory;
@@ -101,6 +103,17 @@ public class IgniteSelectCount extends AbstractRelNode 
implements IgniteRel {
         return visitor.visit(this);
     }
 
+    @Override
+    public RelNode accept(RexShuttle shuttle) {
+        List<RexNode> newExpressions = shuttle.apply(expressions);
+
+        if (newExpressions == expressions) {
+            return this;
+        }
+
+        return new IgniteSelectCount(getCluster(), getTraitSet(), table, 
newExpressions);
+    }
+
     /** {@inheritDoc} */
     @Override
     public IgniteRel clone(RelOptCluster cluster, List<IgniteRel> inputs) {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSortedIndexSpool.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSortedIndexSpool.java
index 2707bff81ad..99324cd48a0 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSortedIndexSpool.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSortedIndexSpool.java
@@ -35,11 +35,12 @@ import 
org.apache.ignite.internal.sql.engine.externalize.RelInputEx;
 import org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCost;
 import org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCostFactory;
 import org.apache.ignite.internal.sql.engine.prepare.bounds.SearchBounds;
+import org.apache.ignite.internal.sql.engine.util.RexUtils;
 
 /**
  * Relational operator that returns the sorted contents of a table and allow 
to lookup rows by specified bounds.
  */
-public class IgniteSortedIndexSpool extends AbstractIgniteSpool implements 
IgniteRel {
+public class IgniteSortedIndexSpool extends AbstractIgniteSpool {
     private static final String REL_TYPE_NAME = "SortedIndexSpool";
 
     private final RelCollation collation;
@@ -96,9 +97,14 @@ public class IgniteSortedIndexSpool extends 
AbstractIgniteSpool implements Ignit
     /** {@inheritDoc} */
     @Override
     public RelNode accept(RexShuttle shuttle) {
-        shuttle.apply(condition);
+        RexNode condition0 = shuttle.apply(condition);
+        List<SearchBounds> searchBounds0 = 
RexUtils.processSearchBounds(shuttle, searchBounds);
 
-        return super.accept(shuttle);
+        if (condition0 == condition && searchBounds0 == searchBounds) {
+            return this;
+        }
+
+        return new IgniteSortedIndexSpool(getCluster(), getTraitSet(), 
getInput(), collation(), condition0, searchBounds0);
     }
 
     /**
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSystemViewScan.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSystemViewScan.java
index d39ac12c5c8..5c516cb580d 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSystemViewScan.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteSystemViewScan.java
@@ -118,6 +118,12 @@ public class IgniteSystemViewScan extends 
ProjectableFilterableTableScan impleme
                 names, projects, condition, requiredColumns);
     }
 
+    @Override
+    protected ProjectableFilterableTableScan copy(@Nullable List<RexNode> 
newProjects, @Nullable RexNode newCondition) {
+        return new IgniteSystemViewScan(sourceId, getCluster(), getTraitSet(), 
getHints(), getTable(),
+                names, newProjects, newCondition, requiredColumns);
+    }
+
     /** {@inheritDoc} */
     @Override
     public IgniteSystemViewScan withHints(List<RelHint> hintList) {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableModify.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableModify.java
index db126a50abf..b1957d98959 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableModify.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableModify.java
@@ -151,23 +151,23 @@ public class IgniteTableModify extends TableModify 
implements SourceAwareIgniteR
     @Override
     public RelNode accept(RexShuttle shuttle) {
         List<RexNode> sourceExprList = getSourceExpressionList();
+        List<RexNode> newSourceExprList = shuttle.apply(sourceExprList);
 
-        if (sourceExprList != null) {
-            List<RexNode> newSourceExprList = shuttle.apply(sourceExprList);
-            return new IgniteTableModify(
-                    sourceId,
-                    getCluster(),
-                    traitSet,
-                    getTable(),
-                    input,
-                    getOperation(),
-                    getUpdateColumnList(),
-                    newSourceExprList,
-                    isFlattened()
-            );
-        } else {
+        if (newSourceExprList == sourceExprList) {
             return this;
         }
+
+        return new IgniteTableModify(
+                sourceId,
+                getCluster(),
+                traitSet,
+                getTable(),
+                input,
+                getOperation(),
+                getUpdateColumnList(),
+                newSourceExprList,
+                isFlattened()
+        );
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java
index fd567e59204..180cdd13c0a 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java
@@ -24,11 +24,9 @@ import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelInput;
-import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.hint.RelHint;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.jetbrains.annotations.Nullable;
 
@@ -143,36 +141,6 @@ public class IgniteTableScan extends 
ProjectableFilterableTableScan implements S
         return visitor.visit(this);
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public RelNode accept(RexShuttle shuttle) {
-        RexNode newCondition = condition;
-        if (condition != null) {
-            newCondition = shuttle.apply(condition);
-        }
-
-        List<RexNode> newProjects = projects;
-        if (projects != null) {
-            newProjects = shuttle.apply(projects);
-        }
-
-        if (newProjects != projects || newCondition != condition) {
-            return new IgniteTableScan(
-                    sourceId,
-                    getCluster(),
-                    getTraitSet(),
-                    getHints(),
-                    getTable(),
-                    names,
-                    newProjects,
-                    newCondition,
-                    requiredColumns
-            );
-        } else {
-            return this;
-        }
-    }
-
     /** {@inheritDoc} */
     @Override
     public IgniteRel clone(long sourceId) {
@@ -187,6 +155,12 @@ public class IgniteTableScan extends 
ProjectableFilterableTableScan implements S
         return new IgniteTableScan(sourceId, cluster, getTraitSet(), 
getHints(), getTable(), names, projects, condition, requiredColumns);
     }
 
+    @Override
+    protected ProjectableFilterableTableScan copy(@Nullable List<RexNode> 
newProjects, @Nullable RexNode newCondition) {
+        return new IgniteTableScan(sourceId, getCluster(), getTraitSet(), 
getHints(), getTable(),
+                names, newProjects, newCondition, requiredColumns);
+    }
+
     /** {@inheritDoc} */
     @Override
     public IgniteTableScan withHints(List<RelHint> hintList) {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/ProjectableFilterableTableScan.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/ProjectableFilterableTableScan.java
index 9a348a01f29..a5d25e3819c 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/ProjectableFilterableTableScan.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/ProjectableFilterableTableScan.java
@@ -127,6 +127,8 @@ public abstract class ProjectableFilterableTableScan 
extends TableScan {
         return this;
     }
 
+    protected abstract ProjectableFilterableTableScan copy(@Nullable 
List<RexNode> newProjects, @Nullable RexNode newCondition);
+
     /** {@inheritDoc} */
     @Override
     public RelWriter explainTerms(RelWriter pw) {
@@ -139,10 +141,14 @@ public abstract class ProjectableFilterableTableScan 
extends TableScan {
     /** {@inheritDoc} */
     @Override
     public RelNode accept(RexShuttle shuttle) {
-        shuttle.apply(condition);
-        shuttle.apply(projects);
+        RexNode condition0 = shuttle.apply(condition);
+        List<RexNode> projects0 = shuttle.apply(projects);
+
+        if (condition0 == condition && projects0 == projects) {
+            return this;
+        }
 
-        return super.accept(shuttle);
+        return copy(projects0, condition0);
     }
 
     protected RelWriter explainTerms0(RelWriter pw) {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalIndexScan.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalIndexScan.java
index fba570dd702..609cb8e19ea 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalIndexScan.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalIndexScan.java
@@ -157,6 +157,16 @@ public class IgniteLogicalIndexScan extends 
AbstractIndexScan {
         );
     }
 
+    @Override
+    protected IgniteLogicalIndexScan copy(
+            @Nullable List<RexNode> newProjects,
+            @Nullable RexNode newCondition,
+            @Nullable List<SearchBounds> newSearchBounds
+    ) {
+        return new IgniteLogicalIndexScan(getCluster(), getTraitSet(), 
getTable(), indexName(), type, names, newProjects, newCondition,
+                newSearchBounds, requiredColumns());
+    }
+
     /** {@inheritDoc} */
     @Override
     public String getRelTypeName() {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalSystemViewScan.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalSystemViewScan.java
index 32c1e0ad25c..5bcf508ac68 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalSystemViewScan.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalSystemViewScan.java
@@ -78,6 +78,12 @@ public class IgniteLogicalSystemViewScan extends 
ProjectableFilterableTableScan
                 names, projects, condition, requiredColumns);
     }
 
+    @Override
+    protected IgniteLogicalSystemViewScan copy(@Nullable List<RexNode> 
newProjects, @Nullable RexNode newCondition) {
+        return new IgniteLogicalSystemViewScan(getCluster(), getTraitSet(), 
getHints(), getTable(),
+                names, newProjects, newCondition, requiredColumns);
+    }
+
     /** {@inheritDoc} */
     @Override
     public String getRelTypeName() {
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java
index 8f6ada00f74..ff4a587f2b8 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java
@@ -76,6 +76,12 @@ public class IgniteLogicalTableScan extends 
ProjectableFilterableTableScan {
         return new IgniteLogicalTableScan(getCluster(), getTraitSet(), 
hintList, getTable(), names, projects, condition, requiredColumns);
     }
 
+    @Override
+    protected ProjectableFilterableTableScan copy(@Nullable List<RexNode> 
newProjects, @Nullable RexNode newCondition) {
+        return new IgniteLogicalTableScan(getCluster(), getTraitSet(), 
getHints(), getTable(),
+                names, newProjects, newCondition, requiredColumns);
+    }
+
     /** {@inheritDoc} */
     @Override
     public String getRelTypeName() {
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 ef9b21fce83..75d7601678b 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
@@ -1354,4 +1354,23 @@ public class RexUtils {
             return new RexLocalRef(inputRef.getIndex(), inputRef.getType());
         }
     }
+
+    /** Applies a {@link RexShuttle} to a list of {@link SearchBounds}. */
+    public static @Nullable List<SearchBounds> processSearchBounds(RexShuttle 
shuttle, @Nullable List<SearchBounds> searchBounds) {
+        if (nullOrEmpty(searchBounds)) {
+            return searchBounds;
+        }
+
+        List<SearchBounds> newSearchBounds = new 
ArrayList<>(searchBounds.size());
+
+        boolean wasChanged = false;
+        for (SearchBounds bound : searchBounds) {
+            SearchBounds newBound = bound == null ? null : 
bound.accept(shuttle);
+            newSearchBounds.add(newBound);
+
+            wasChanged = wasChanged || newBound != bound;
+        }
+
+        return wasChanged ? newSearchBounds : searchBounds;
+    }
 }

Reply via email to