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

jhyde 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 ecbafbf  [CALCITE-4925] AggregateReduceFunctionsRule should accept 
arbitrary predicates
ecbafbf is described below

commit ecbafbfbd356955db08e363b71c03d8923e6fe98
Author: Will Noble <[email protected]>
AuthorDate: Wed Dec 1 02:38:25 2021 -0800

    [CALCITE-4925] AggregateReduceFunctionsRule should accept arbitrary 
predicates
    
    Allow selective application of the reduce-functions rule with arbitrary 
specificity.
    
    Close apache/calcite#2634
---
 .../rel/rules/AggregateReduceFunctionsRule.java    | 33 ++++++++++++++++++----
 .../org/apache/calcite/test/RelOptRulesTest.java   | 10 +++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 22 +++++++++++++++
 3 files changed, 59 insertions(+), 6 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
index 47dd5d1..522835f 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
@@ -53,6 +53,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.function.IntPredicate;
+import java.util.function.Predicate;
 
 /**
  * Planner rule that reduces aggregate functions in
@@ -173,7 +174,8 @@ public class AggregateReduceFunctionsRule
 
   /** Returns whether this rule can reduce a given aggregate function call. */
   public boolean canReduce(AggregateCall call) {
-    return functionsToReduce.contains(call.getAggregation().getKind());
+    return functionsToReduce.contains(call.getAggregation().getKind())
+        && config.extraCondition().test(call);
   }
 
   /**
@@ -209,7 +211,7 @@ public class AggregateReduceFunctionsRule
     relBuilder.push(oldAggRel.getInput());
     final List<RexNode> inputExprs = new ArrayList<>(relBuilder.fields());
 
-    // create new agg function calls and rest of project list together
+    // create new aggregate function calls and rest of project list together
     for (AggregateCall oldCall : oldCalls) {
       projList.add(
           reduceAgg(
@@ -798,7 +800,7 @@ public class AggregateReduceFunctionsRule
   }
 
   /**
-   * Do a shallow clone of oldAggRel and update aggCalls. Could be refactored
+   * Does a shallow clone of oldAggRel and updates aggCalls. Could be 
refactored
    * into Aggregate and subclasses - but it's only needed for some
    * subclasses.
    *
@@ -816,13 +818,13 @@ public class AggregateReduceFunctionsRule
   }
 
   /**
-   * Add a calc with the expressions to compute the original agg calls from the
-   * decomposed ones.
+   * Adds a calculation with the expressions to compute the original aggregate
+   * calls from the decomposed ones.
    *
    * @param relBuilder Builder of relational expressions; at the top of its
    *                   stack is its input
    * @param rowType The output row type of the original aggregate.
-   * @param exprs The expressions to compute the original agg calls.
+   * @param exprs The expressions to compute the original aggregate calls
    */
   protected void newCalcRel(RelBuilder relBuilder,
       RelDataType rowType,
@@ -847,8 +849,24 @@ public class AggregateReduceFunctionsRule
       return new AggregateReduceFunctionsRule(this);
     }
 
+    /** The set of aggregate function types to try to reduce.
+     *
+     * <p>Any aggregate function whose type is omitted from this set, OR which
+     * does not pass the {@link #extraCondition}, will be ignored.
+     */
     @Nullable Set<SqlKind> functionsToReduce();
 
+    /** A test that must pass before attempting to reduce any aggregate 
function.
+     *
+     * <p>Any aggegate function which does not pass, OR whose type is omitted
+     * from {@link #functionsToReduce}, will be ignored. The default predicate
+     * always passes.
+     */
+    @Value.Default
+    default Predicate<AggregateCall> extraCondition() {
+      return ignored -> true;
+    }
+
     /** Sets {@link #functionsToReduce}. */
     Config withFunctionsToReduce(@Nullable Iterable<SqlKind> functionSet);
 
@@ -856,6 +874,9 @@ public class AggregateReduceFunctionsRule
       return withFunctionsToReduce((Iterable<SqlKind>) functionSet);
     }
 
+    /** Sets {@link #extraCondition}. */
+    Config withExtraCondition(Predicate<AggregateCall> test);
+
     /** Returns the validated set of functions to reduce, or the default set
      * if not specified. */
     default Set<SqlKind> actualFunctionsToReduce() {
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 2cad6a9..a01731a 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -6321,6 +6321,16 @@ class RelOptRulesTest extends RelOptTestBase {
     sql(sql).withRule(rule).check();
   }
 
+  @Test void testReduceWithNonTypePredicate() {
+    // Make sure we can reduce with more specificity than just agg function 
type.
+    final RelOptRule rule = AggregateReduceFunctionsRule.Config.DEFAULT
+        .withExtraCondition(call -> call.distinctKeys != null)
+        .toRule();
+    final String sql = "select avg(sal), avg(sal) within distinct (deptno)\n"
+        + "from emp";
+    sql(sql).withRule(rule).check();
+  }
+
   /** Test case for
   * <a href="https://issues.apache.org/jira/browse/CALCITE-2803";>[CALCITE-2803]
   * Identify expanded IS NOT DISTINCT FROM expression when pushing project 
past join</a>.
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 2b22095..e9a4152 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -10877,6 +10877,28 @@ LogicalValues(tuples=[[{ 11, 1, 10 }, { 23, 3, 20 }]])
 ]]>
     </Resource>
   </TestCase>
+  <TestCase name="testReduceWithNonTypePredicate">
+    <Resource name="sql">
+      <![CDATA[select avg(sal), avg(sal) within distinct (deptno)
+from emp]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalAggregate(group=[{}], EXPR$0=[AVG($0)], EXPR$1=[AVG($0) WITHIN DISTINCT 
($1)])
+  LogicalProject(SAL=[$5], DEPTNO=[$7])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(EXPR$0=[$0], EXPR$1=[CAST(/($1, $2)):INTEGER])
+  LogicalProject(EXPR$0=[$0], $f1=[CASE(=($2, 0), null:INTEGER, $1)], $f2=[$2])
+    LogicalAggregate(group=[{}], EXPR$0=[AVG($0)], agg#1=[$SUM0($0) WITHIN 
DISTINCT ($1)], agg#2=[COUNT() WITHIN DISTINCT ($1)])
+      LogicalProject(SAL=[$5], DEPTNO=[$7])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+  </TestCase>
   <TestCase name="testRemoveDistinctOnAgg">
     <Resource name="sql">
       <![CDATA[SELECT empno, SUM(distinct sal), MIN(sal), MIN(distinct sal), 
MAX(distinct sal), bit_and(distinct sal), bit_or(sal), count(distinct sal) from 
sales.emp group by empno, deptno

Reply via email to