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

hyuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 15fa9bc67a8ed12ec6b8e0d1dbced8760ae307ab
Author: Haisheng Yuan <h.y...@alibaba-inc.com>
AuthorDate: Sun Mar 8 16:04:42 2020 -0500

    [CALCITE-3753] Introduce SubstitutionRule interface and execute 
substitutional rule first
    
    A rule that implements SubstitutionRule interface indicates that the new
    RelNode is definitely better than the old one, which will be pruned by 
setting
    importance to 0. In addition, the rule matches for SubstitutionRule will be
    inserted into the head of RuleQueue so that they can be executed as early as
    possible.
---
 .../org/apache/calcite/plan/SubstitutionRule.java  | 26 ++++++++++++++++++++++
 .../org/apache/calcite/plan/volcano/RelSet.java    |  2 +-
 .../org/apache/calcite/plan/volcano/RuleQueue.java | 22 ++++++++++--------
 .../calcite/plan/volcano/VolcanoPlanner.java       | 16 ++++---------
 .../calcite/plan/volcano/VolcanoRuleCall.java      |  5 +++++
 .../calcite/rel/rules/AggregateRemoveRule.java     |  4 ++--
 .../calcite/rel/rules/AggregateValuesRule.java     |  3 ++-
 .../apache/calcite/rel/rules/CalcRemoveRule.java   |  3 ++-
 .../rel/rules/ExchangeRemoveConstantKeysRule.java  |  4 +++-
 .../apache/calcite/rel/rules/FilterMergeRule.java  |  3 ++-
 .../rel/rules/FilterProjectTransposeRule.java      |  4 +---
 .../rel/rules/ProjectJoinJoinRemoveRule.java       |  4 +++-
 .../calcite/rel/rules/ProjectJoinRemoveRule.java   |  3 ++-
 .../calcite/rel/rules/ProjectRemoveRule.java       |  3 ++-
 .../apache/calcite/rel/rules/PruneEmptyRules.java  |  3 ++-
 .../calcite/rel/rules/ReduceExpressionsRule.java   |  4 +++-
 .../rel/rules/SortRemoveConstantKeysRule.java      |  4 +++-
 .../test/enumerable/EnumerableCorrelateTest.java   |  4 ++--
 18 files changed, 78 insertions(+), 39 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionRule.java 
b/core/src/main/java/org/apache/calcite/plan/SubstitutionRule.java
new file mode 100644
index 0000000..a070078
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionRule.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.plan;
+
+/**
+ * A rule that implements this interface indicates that the new RelNode
+ * is definitely better than the old one, which will be pruned by setting
+ * importance to 0.
+ */
+public interface SubstitutionRule {
+
+}
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java 
b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
index 3c7bcbe..5de6b7f 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
@@ -420,7 +420,7 @@ class RelSet {
     // once to fire again.)
     for (RelNode rel : rels) {
       assert planner.getSet(rel) == this;
-      planner.fireRules(rel, true);
+      planner.fireRules(rel);
     }
   }
 }
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java 
b/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java
index 5ac8bf2..34c43ef 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.plan.volcano;
 
 import org.apache.calcite.plan.RelOptRuleOperand;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.trace.CalciteTrace;
@@ -33,7 +34,6 @@ import java.util.EnumMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.Map;
-import java.util.Queue;
 import java.util.Set;
 
 /**
@@ -140,7 +140,11 @@ class RuleQueue {
 
       LOGGER.trace("{} Rule-match queued: {}", matchList.phase.toString(), 
matchName);
 
-      matchList.queue.offer(match);
+      if (match.getRule() instanceof SubstitutionRule) {
+        matchList.list.offerFirst(match);
+      } else {
+        matchList.list.offer(match);
+      }
 
       matchList.matchMap.put(
           planner.getSubset(match.rels[0]), match);
@@ -169,11 +173,11 @@ class RuleQueue {
 
     VolcanoRuleMatch match;
     for (;;) {
-      if (phaseMatchList.queue.isEmpty()) {
+      if (phaseMatchList.list.isEmpty()) {
         return null;
       }
 
-      match = phaseMatchList.queue.poll();
+      match = phaseMatchList.list.poll();
 
       if (skipMatch(match)) {
         LOGGER.debug("Skip match: {}", match);
@@ -268,14 +272,14 @@ class RuleQueue {
     final VolcanoPlannerPhase phase;
 
     /**
-     * Current queue of VolcanoRuleMatches for this phase. New rule-matches
-     * are appended to the end of this queue.
+     * Current list of VolcanoRuleMatches for this phase. New rule-matches
+     * are appended to the end of this list.
      * The rules are not sorted in any way.
      */
-    final Queue<VolcanoRuleMatch> queue = new LinkedList<>();
+    final Deque<VolcanoRuleMatch> list = new LinkedList<>();
 
     /**
-     * A set of rule-match names contained in {@link #queue}. Allows fast
+     * A set of rule-match names contained in {@link #list}. Allows fast
      * detection of duplicate rule-matches.
      */
     final Set<String> names = new HashSet<>();
@@ -291,7 +295,7 @@ class RuleQueue {
     }
 
     void clear() {
-      queue.clear();
+      list.clear();
       names.clear();
       matchMap.clear();
     }
diff --git 
a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java 
b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
index fcdd501..9b7cdc9 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
@@ -1306,20 +1306,12 @@ public class VolcanoPlanner extends 
AbstractRelOptPlanner {
    *
    * @param rel      Relational expression which has just been created (or 
maybe
    *                 from the queue)
-   * @param deferred If true, each time a rule matches, just add an entry to
-   *                 the queue.
    */
-  void fireRules(
-      RelNode rel,
-      boolean deferred) {
+  void fireRules(RelNode rel) {
     for (RelOptRuleOperand operand : classOperands.get(rel.getClass())) {
       if (operand.matches(rel)) {
         final VolcanoRuleCall ruleCall;
-        if (deferred) {
-          ruleCall = new DeferringRuleCall(this, operand);
-        } else {
-          ruleCall = new VolcanoRuleCall(this, operand);
-        }
+        ruleCall = new DeferringRuleCall(this, operand);
         ruleCall.match(rel);
       }
     }
@@ -1568,11 +1560,11 @@ public class VolcanoPlanner extends 
AbstractRelOptPlanner {
     }
 
     // Queue up all rules triggered by this relexp's creation.
-    fireRules(rel, true);
+    fireRules(rel);
 
     // It's a new subset.
     if (set.subsets.size() > subsetBeforeCount) {
-      fireRules(subset, true);
+      fireRules(subset);
     }
 
     return subset;
diff --git 
a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java 
b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java
index 6256d3e..0d7a958 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java
@@ -21,6 +21,7 @@ import org.apache.calcite.plan.RelOptListener;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptRuleOperand;
 import org.apache.calcite.plan.RelOptRuleOperandChildPolicy;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.RelNode;
 
 import com.google.common.collect.ImmutableList;
@@ -139,6 +140,10 @@ public class VolcanoRuleCall extends RelOptRuleCall {
         }
       }
 
+      if (this.getRule() instanceof SubstitutionRule) {
+        volcanoPlanner.setImportance(rels[0], 0d);
+      }
+
       // Registering the root relational expression implicitly registers
       // its descendants. Register any explicit equivalences first, so we
       // don't register twice and cause churn.
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
index 22af6da..8f6ac60 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
@@ -18,6 +18,7 @@ package org.apache.calcite.rel.rules;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
@@ -45,7 +46,7 @@ import java.util.Objects;
  * or all the aggregate functions are splittable,
  * and the underlying relational expression is already distinct.
  */
-public class AggregateRemoveRule extends RelOptRule {
+public class AggregateRemoveRule extends RelOptRule implements 
SubstitutionRule {
   public static final AggregateRemoveRule INSTANCE =
       new AggregateRemoveRule(LogicalAggregate.class,
           RelFactories.LOGICAL_BUILDER);
@@ -123,7 +124,6 @@ public class AggregateRemoveRule extends RelOptRule {
       // aggregate functions, add a project for the same effect.
       relBuilder.project(relBuilder.fields(aggregate.getGroupSet()));
     }
-    call.getPlanner().setImportance(aggregate, 0d);
     call.transformTo(relBuilder.build());
   }
 }
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/AggregateValuesRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/AggregateValuesRule.java
index ee6e141..9f88ed3 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateValuesRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateValuesRule.java
@@ -18,6 +18,7 @@ package org.apache.calcite.rel.rules;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.RelFactories;
@@ -52,7 +53,7 @@ import java.util.List;
  * Any non-empty {@code GROUP BY} clause will return one row per group key
  * value, and each group will consist of at least one row.
  */
-public class AggregateValuesRule extends RelOptRule {
+public class AggregateValuesRule extends RelOptRule implements 
SubstitutionRule {
   public static final AggregateValuesRule INSTANCE =
       new AggregateValuesRule(RelFactories.LOGICAL_BUILDER);
 
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/CalcRemoveRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/CalcRemoveRule.java
index d869732..73c6209 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/CalcRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/CalcRemoveRule.java
@@ -18,6 +18,7 @@ package org.apache.calcite.rel.rules;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.logical.LogicalCalc;
@@ -34,7 +35,7 @@ import org.apache.calcite.tools.RelBuilderFactory;
  *
  * @see ProjectRemoveRule
  */
-public class CalcRemoveRule extends RelOptRule {
+public class CalcRemoveRule extends RelOptRule implements SubstitutionRule {
   //~ Static fields/initializers ---------------------------------------------
 
   public static final CalcRemoveRule INSTANCE =
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/ExchangeRemoveConstantKeysRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/ExchangeRemoveConstantKeysRule.java
index a5f131b..4ff0ec6 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/ExchangeRemoveConstantKeysRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/ExchangeRemoveConstantKeysRule.java
@@ -19,6 +19,7 @@ package org.apache.calcite.rel.rules;
 import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelDistribution;
@@ -49,7 +50,8 @@ import java.util.stream.Collectors;
  * <code>SELECT 1 AS key, value FROM src</code>.</p>
  *
  */
-public class ExchangeRemoveConstantKeysRule extends RelOptRule {
+public class ExchangeRemoveConstantKeysRule extends RelOptRule
+    implements SubstitutionRule {
   /**
    * Singleton rule that removes constants inside a
    * {@link LogicalExchange}.
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/FilterMergeRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/FilterMergeRule.java
index 33e598f..a4df314 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterMergeRule.java
@@ -19,6 +19,7 @@ package org.apache.calcite.rel.rules;
 import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rex.RexBuilder;
@@ -32,7 +33,7 @@ import org.apache.calcite.tools.RelBuilderFactory;
  * Planner rule that combines two
  * {@link org.apache.calcite.rel.logical.LogicalFilter}s.
  */
-public class FilterMergeRule extends RelOptRule {
+public class FilterMergeRule extends RelOptRule implements SubstitutionRule {
   public static final FilterMergeRule INSTANCE =
       new FilterMergeRule(RelFactories.LOGICAL_BUILDER);
 
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
index 6876b66..12e57f0 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
@@ -27,8 +27,6 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
-import org.apache.calcite.rel.logical.LogicalFilter;
-import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexOver;
 import org.apache.calcite.rex.RexUtil;
@@ -53,7 +51,7 @@ public class FilterProjectTransposeRule extends RelOptRule {
    * {@link org.apache.calcite.rel.core.Correlate} from being de-correlated.
    */
   public static final FilterProjectTransposeRule INSTANCE =
-      new FilterProjectTransposeRule(LogicalFilter.class, 
LogicalProject.class, true, true,
+      new FilterProjectTransposeRule(Filter.class, Project.class, true, true,
           RelFactories.LOGICAL_BUILDER);
 
   private final boolean copyFilter;
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/ProjectJoinJoinRemoveRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/ProjectJoinJoinRemoveRule.java
index 97b5769..16c2f4b 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/ProjectJoinJoinRemoveRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/ProjectJoinJoinRemoveRule.java
@@ -19,6 +19,7 @@ package org.apache.calcite.rel.rules;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinRelType;
@@ -61,7 +62,8 @@ import java.util.stream.Collectors;
  * on s.product_id = pc.product_id</pre></blockquote>
  *
  */
-public class ProjectJoinJoinRemoveRule extends RelOptRule {
+public class ProjectJoinJoinRemoveRule extends RelOptRule
+    implements SubstitutionRule {
   public static final ProjectJoinJoinRemoveRule INSTANCE =
       new ProjectJoinJoinRemoveRule(LogicalProject.class,
           LogicalJoin.class, RelFactories.LOGICAL_BUILDER);
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/ProjectJoinRemoveRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/ProjectJoinRemoveRule.java
index a458a80..9174c7a 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectJoinRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectJoinRemoveRule.java
@@ -19,6 +19,7 @@ package org.apache.calcite.rel.rules;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinRelType;
@@ -55,7 +56,7 @@ import java.util.stream.Collectors;
  * <pre>select s.product_id from sales as s</pre></blockquote>
  *
  */
-public class ProjectJoinRemoveRule extends RelOptRule {
+public class ProjectJoinRemoveRule extends RelOptRule implements 
SubstitutionRule {
   public static final ProjectJoinRemoveRule INSTANCE =
       new ProjectJoinRemoveRule(LogicalProject.class,
           LogicalJoin.class, RelFactories.LOGICAL_BUILDER);
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
index 08e27cc..e957dbe 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
@@ -18,6 +18,7 @@ package org.apache.calcite.rel.rules;
 
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
@@ -39,7 +40,7 @@ import java.util.List;
  * @see CalcRemoveRule
  * @see ProjectMergeRule
  */
-public class ProjectRemoveRule extends RelOptRule {
+public class ProjectRemoveRule extends RelOptRule implements SubstitutionRule {
   public static final ProjectRemoveRule INSTANCE =
       new ProjectRemoveRule(RelFactories.LOGICAL_BUILDER);
 
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java 
b/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
index 62e872e..be76678 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
@@ -19,6 +19,7 @@ package org.apache.calcite.rel.rules;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.plan.hep.HepRelVertex;
 import org.apache.calcite.plan.volcano.RelSubset;
 import org.apache.calcite.rel.RelNode;
@@ -59,7 +60,7 @@ import static org.apache.calcite.plan.RelOptRule.unordered;
  *
  * @see LogicalValues#createEmpty
  */
-public abstract class PruneEmptyRules {
+public abstract class PruneEmptyRules implements SubstitutionRule {
   //~ Static fields/initializers ---------------------------------------------
 
   /**
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index 5fafff3..602e955 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -21,6 +21,7 @@ import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
@@ -93,7 +94,8 @@ import java.util.stream.Collectors;
  * is the same as the type of the resulting cast expression
  * </ul>
  */
-public abstract class ReduceExpressionsRule extends RelOptRule {
+public abstract class ReduceExpressionsRule extends RelOptRule
+    implements SubstitutionRule {
   //~ Static fields/initializers ---------------------------------------------
 
   /**
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/SortRemoveConstantKeysRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/SortRemoveConstantKeysRule.java
index ca50570..d3bc06f 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/SortRemoveConstantKeysRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/SortRemoveConstantKeysRule.java
@@ -19,6 +19,7 @@ package org.apache.calcite.rel.rules;
 import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
@@ -38,7 +39,8 @@ import java.util.stream.Collectors;
  *
  * <p>Requires {@link RelCollationTraitDef}.
  */
-public class SortRemoveConstantKeysRule extends RelOptRule {
+public class SortRemoveConstantKeysRule extends RelOptRule
+    implements SubstitutionRule {
   public static final SortRemoveConstantKeysRule INSTANCE =
       new SortRemoveConstantKeysRule();
 
diff --git 
a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
 
b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
index 9b7ccb9..92f081b 100644
--- 
a/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
+++ 
b/core/src/test/java/org/apache/calcite/test/enumerable/EnumerableCorrelateTest.java
@@ -125,10 +125,10 @@ public class EnumerableCorrelateTest {
         })
         .explainContains(""
             + "EnumerableCalc(expr#0..3=[{inputs}], empid=[$t1], name=[$t3])\n"
-            + "  EnumerableCorrelate(correlation=[$cor5], joinType=[inner], 
requiredColumns=[{0}])\n"
+            + "  EnumerableCorrelate(correlation=[$cor1], joinType=[inner], 
requiredColumns=[{0}])\n"
             + "    EnumerableAggregate(group=[{0}])\n"
             + "      EnumerableTableScan(table=[[s, depts]])\n"
-            + "    EnumerableCalc(expr#0..4=[{inputs}], expr#5=[100], 
expr#6=[>($t0, $t5)], expr#7=[$cor5], expr#8=[$t7.deptno], expr#9=[=($t1, 
$t8)], expr#10=[AND($t6, $t9)], proj#0..2=[{exprs}], $condition=[$t10])\n"
+            + "    EnumerableCalc(expr#0..4=[{inputs}], expr#5=[$cor1], 
expr#6=[$t5.deptno], expr#7=[=($t1, $t6)], expr#8=[100], expr#9=[>($t0, $t8)], 
expr#10=[AND($t7, $t9)], proj#0..2=[{exprs}], $condition=[$t10])\n"
             + "      EnumerableTableScan(table=[[s, emps]])")
         .returnsUnordered(
             "empid=110; name=Theodore",

Reply via email to