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


The following commit(s) were added to refs/heads/master by this push:
     new aafdc52  [CALCITE-2729] Introducing WindowReduceExpressionsRule 
(Chunwei Lei)
aafdc52 is described below

commit aafdc5219682e535144b1f25e2e41884f793d514
Author: chunwei.lcw <[email protected]>
AuthorDate: Sun Nov 11 13:55:43 2018 +0800

    [CALCITE-2729] Introducing WindowReduceExpressionsRule (Chunwei Lei)
---
 .../apache/calcite/prepare/CalcitePrepareImpl.java |  1 +
 .../calcite/rel/rules/ReduceExpressionsRule.java   | 88 ++++++++++++++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.java   | 19 +++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 28 +++++++
 4 files changed, 136 insertions(+)

diff --git 
a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java 
b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index a7181a0..d5fee2d 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -241,6 +241,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
           ReduceExpressionsRule.PROJECT_INSTANCE,
           ReduceExpressionsRule.FILTER_INSTANCE,
           ReduceExpressionsRule.CALC_INSTANCE,
+          ReduceExpressionsRule.WINDOW_INSTANCE,
           ReduceExpressionsRule.JOIN_INSTANCE,
           ValuesReduceRule.FILTER_INSTANCE,
           ValuesReduceRule.PROJECT_FILTER_INSTANCE,
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 48ed3cd..e55c417 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,9 @@ 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.rel.RelCollation;
+import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Calc;
 import org.apache.calcite.rel.core.EquiJoin;
@@ -29,9 +32,11 @@ import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinInfo;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.rel.core.Window;
 import org.apache.calcite.rel.logical.LogicalCalc;
 import org.apache.calcite.rel.logical.LogicalFilter;
 import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.logical.LogicalWindow;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -55,6 +60,7 @@ import org.apache.calcite.rex.RexSubQuery;
 import org.apache.calcite.rex.RexUnknownAs;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.rex.RexVisitorImpl;
+import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.fun.SqlRowOperator;
@@ -76,6 +82,7 @@ import java.util.Deque;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 /**
  * Collection of planner rules that apply various simplifying transformations 
on
@@ -131,6 +138,14 @@ public abstract class ReduceExpressionsRule extends 
RelOptRule {
       new CalcReduceExpressionsRule(LogicalCalc.class, true,
           RelFactories.LOGICAL_BUILDER);
 
+  /**
+   * Singleton rule that reduces constants inside a
+   * {@link org.apache.calcite.rel.logical.LogicalWindow}.
+   */
+  public static final ReduceExpressionsRule WINDOW_INSTANCE =
+      new WindowReduceExpressionsRule(LogicalWindow.class, true,
+          RelFactories.LOGICAL_BUILDER);
+
   protected final boolean matchNullability;
 
   /**
@@ -453,6 +468,79 @@ public abstract class ReduceExpressionsRule extends 
RelOptRule {
     }
   }
 
+  /**
+   * Rule that reduces constants inside a {@link 
org.apache.calcite.rel.core.Window}.
+   */
+  public static class WindowReduceExpressionsRule
+      extends ReduceExpressionsRule {
+
+    public WindowReduceExpressionsRule(Class<? extends Window> windowClass,
+        boolean matchNullability, RelBuilderFactory relBuilderFactory) {
+      super(windowClass, matchNullability, relBuilderFactory,
+          "ReduceExpressionsRule(Window)");
+    }
+
+    @Override public void onMatch(RelOptRuleCall call) {
+      LogicalWindow window = call.rel(0);
+      RexBuilder rexBuilder = window.getCluster().getRexBuilder();
+      final RelMetadataQuery mq = RelMetadataQuery.instance();
+      final RelOptPredicateList predicates = mq
+          .getPulledUpPredicates(window.getInput());
+
+      boolean reduced = false;
+      final List<Window.Group> groups = new ArrayList<>();
+      for (Window.Group group : window.groups) {
+        List<Window.RexWinAggCall> aggCalls = new ArrayList<>();
+        for (Window.RexWinAggCall rexWinAggCall : group.aggCalls) {
+          final List<RexNode> expList = new ArrayList<>(
+              rexWinAggCall.getOperands());
+          boolean opReduced = reduceExpressions(window, expList, predicates);
+          aggCalls.add(opReduced
+              ?
+              new Window.RexWinAggCall(
+                  (SqlAggFunction) rexWinAggCall.getOperator(),
+                  rexWinAggCall.type, expList, rexWinAggCall.ordinal,
+                  rexWinAggCall.distinct)
+              :
+              rexWinAggCall);
+          reduced |= opReduced;
+        }
+
+        final ImmutableBitSet.Builder keyBuilder = ImmutableBitSet.builder();
+        group.keys.asList().stream().filter(key
+            -> !predicates.constantMap.containsKey(rexBuilder.
+            makeInputRef(window.getInput(), key))).collect(
+            Collectors.toList()).forEach(i -> keyBuilder.set(i));
+        ImmutableBitSet keys = keyBuilder.build();
+        reduced |= keys.cardinality() != group.keys.cardinality();
+
+        final List<RelFieldCollation> collationsList = group.orderKeys
+            .getFieldCollations().stream().filter(fc -> !predicates.constantMap
+                .containsKey(rexBuilder
+                    .makeInputRef(window.getInput(), fc.getFieldIndex())))
+            .collect(Collectors.toList());
+
+        boolean collationReduced =
+            group.orderKeys.getFieldCollations().size() != 
collationsList.size();
+        reduced |= collationReduced;
+        RelCollation relCollation = collationReduced
+            ?
+            RelCollations.of(collationsList)
+            :
+            group.orderKeys;
+        groups.add(
+            new Window.Group(keys, group.isRows, group.lowerBound,
+                group.upperBound, relCollation, aggCalls));
+      }
+      if (reduced) {
+        call.transformTo(LogicalWindow
+            .create(window.getTraitSet(), window.getInput(),
+                window.getConstants(), window.getRowType(), groups));
+        call.getPlanner().setImportance(window, 0);
+      }
+    }
+  }
+
   //~ Constructors -----------------------------------------------------------
 
   /**
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java 
b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index ef2b705..c612cad 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -2357,6 +2357,25 @@ public class RelOptRulesTest extends RelOptTestBase {
             + " where a - b < 0");
   }
 
+  @Test public void testReduceConstantsWindow() {
+    HepProgram program = new HepProgramBuilder()
+        .addRuleInstance(ProjectToWindowRule.PROJECT)
+        .addRuleInstance(ProjectMergeRule.INSTANCE)
+        .addRuleInstance(ProjectWindowTransposeRule.INSTANCE)
+        .addRuleInstance(ReduceExpressionsRule.WINDOW_INSTANCE)
+        .build();
+
+    final String sql = "select col1, col2, col3\n"
+        + "from (\n"
+        + "  select empno,\n"
+        + "    sum(100) over (partition by deptno, sal order by sal) as 
col1,\n"
+        + "    sum(100) over (partition by sal order by deptno) as col2,\n"
+        + "    sum(sal) over (partition by deptno order by sal) as col3\n"
+        + "  from emp where sal = 5000)";
+
+    checkPlanning(program, sql);
+  }
+
   @Test public void testEmptyFilterProjectUnion() throws Exception {
     HepProgram program = new HepProgramBuilder()
         .addRuleInstance(FilterSetOpTransposeRule.INSTANCE)
diff --git 
a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml 
b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 92dc2b1..cea2776 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -8826,4 +8826,32 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], 
MGR=[$3], HIREDATE=[$4], SAL=[$
             <![CDATA[select * from emp where MGR > 0 and case when MGR > 0 
then deptno / MGR else null end > 1]]>
         </Resource>
     </TestCase>
+    <TestCase name="testReduceConstantsWindow">
+        <Resource name="sql">
+            <![CDATA[select col1, col2, col3
+from (
+  select empno,
+    sum(100) over (partition by deptno, sal order by sal) as col1,
+    sum(100) over (partition by deptno order by deptno) as col2,
+    sum(sal) over (partition by deptno order by sal) as col3
+  from emp where sal = 5000)
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject($0=[$2], $1=[$3], $2=[$4])
+  LogicalWindow(window#0=[window(partition {1} order by [] range between 
UNBOUNDED PRECEDING and CURRENT ROW aggs [SUM($2)])], 
window#1=[window(partition {} order by [1] range between UNBOUNDED PRECEDING 
and CURRENT ROW aggs [SUM($2)])], window#2=[window(partition {1} order by [] 
range between UNBOUNDED PRECEDING and CURRENT ROW aggs [SUM(5000)])])
+    LogicalProject(SAL=[$5], DEPTNO=[$7])
+      LogicalFilter(condition=[=($5, 5000)])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(COL1=[SUM(100) OVER (PARTITION BY $7, $5 ORDER BY $5 RANGE 
BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)], COL2=[SUM(100) OVER (PARTITION 
BY $5 ORDER BY $7 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)], 
COL3=[SUM($5) OVER (PARTITION BY $7 ORDER BY $5 RANGE BETWEEN UNBOUNDED 
PRECEDING AND CURRENT ROW)])
+  LogicalFilter(condition=[=($5, 5000)])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
 </Root>

Reply via email to