This is an automated email from the ASF dual-hosted git repository. morrysnow pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new b45f501e511 [improvement](nereids) Support aggregate functions without from clause (#25500) b45f501e511 is described below commit b45f501e51145de5c52d2ee0201175133f0317a6 Author: JingDas <114388747+jing...@users.noreply.github.com> AuthorDate: Thu Oct 19 12:07:37 2023 +0800 [improvement](nereids) Support aggregate functions without from clause (#25500) Support aggregate functions in select without from clause, here are some examples as following: SELECT 1, 'a', COUNT(), SUM(1) + 1, AVG(2) / COUNT(), MAX(3), MIN(4), RANK() OVER() AS w_rank, DENSE_RANK() OVER() AS w_dense_rank, ROW_NUMBER() OVER() AS w_row_number, SUM(5) OVER() AS w_sum, AVG(6) OVER() AS w_avg, COUNT() OVER() AS w_count, MAX(7) OVER() AS w_max, MIN(8) OVER() AS w_min; --- .../doris/nereids/jobs/executor/Analyzer.java | 4 +- .../org/apache/doris/nereids/rules/RuleType.java | 1 + .../nereids/rules/analysis/CheckAnalysis.java | 1 - .../analysis/OneRowRelationExtractAggregate.java | 68 ++++++++++++++++++++++ .../rules/analysis/ProjectToGlobalAggregate.java | 35 +---------- .../doris/nereids/rules/rewrite/ColumnPruning.java | 3 + .../expressions/visitor/ExpressionVisitors.java} | 45 ++------------ .../trees/plans/logical/LogicalOneRowRelation.java | 4 -- .../select_no_from/sql/projectAggFuncs.out | 4 ++ .../select_no_from/sql/projectAggFuncs.out | 4 ++ .../select_no_from/sql/projectAggFuncs.sql | 19 +++++- .../nereids_syntax_p0/one_row_relation.groovy | 7 --- .../select_no_from/sql/projectAggFuncs.sql | 18 +++++- 13 files changed, 122 insertions(+), 91 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java index 333fc8a16de..e773ed41f60 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java @@ -34,6 +34,7 @@ import org.apache.doris.nereids.rules.analysis.EliminateGroupByConstant; import org.apache.doris.nereids.rules.analysis.FillUpMissingSlots; import org.apache.doris.nereids.rules.analysis.NormalizeAggregate; import org.apache.doris.nereids.rules.analysis.NormalizeRepeat; +import org.apache.doris.nereids.rules.analysis.OneRowRelationExtractAggregate; import org.apache.doris.nereids.rules.analysis.ProjectToGlobalAggregate; import org.apache.doris.nereids.rules.analysis.ProjectWithDistinctToAggregate; import org.apache.doris.nereids.rules.analysis.ReplaceExpressionByChildOutput; @@ -103,7 +104,8 @@ public class Analyzer extends AbstractBatchJobExecutor { // please see rule BindSlotReference or BindFunction for example new ProjectWithDistinctToAggregate(), new ResolveOrdinalInOrderByAndGroupBy(), - new ReplaceExpressionByChildOutput() + new ReplaceExpressionByChildOutput(), + new OneRowRelationExtractAggregate() ), topDown( new FillUpMissingSlots(), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java index 617cb352908..f3b862f0c6d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java @@ -71,6 +71,7 @@ public enum RuleType { RESOLVE_PROJECT_ALIAS(RuleTypeClass.REWRITE), RESOLVE_AGGREGATE_ALIAS(RuleTypeClass.REWRITE), PROJECT_TO_GLOBAL_AGGREGATE(RuleTypeClass.REWRITE), + ONE_ROW_RELATION_EXTRACT_AGGREGATE(RuleTypeClass.REWRITE), PROJECT_WITH_DISTINCT_TO_AGGREGATE(RuleTypeClass.REWRITE), AVG_DISTINCT_TO_SUM_DIV_COUNT(RuleTypeClass.REWRITE), ANALYZE_CTE(RuleTypeClass.REWRITE), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckAnalysis.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckAnalysis.java index d32823799e2..fc6ddfcf79b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckAnalysis.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckAnalysis.java @@ -76,7 +76,6 @@ public class CheckAnalysis implements AnalysisRuleFactory { TableGeneratingFunction.class, WindowExpression.class)) .put(LogicalOneRowRelation.class, ImmutableSet.of( - AggregateFunction.class, GroupingScalarFunction.class, TableGeneratingFunction.class, WindowExpression.class)) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/OneRowRelationExtractAggregate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/OneRowRelationExtractAggregate.java new file mode 100644 index 00000000000..37aaf22ce76 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/OneRowRelationExtractAggregate.java @@ -0,0 +1,68 @@ +// 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.doris.nereids.rules.analysis; + +import org.apache.doris.nereids.rules.Rule; +import org.apache.doris.nereids.rules.RuleType; +import org.apache.doris.nereids.trees.expressions.NamedExpression; +import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitors; +import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; +import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation; +import org.apache.doris.nereids.trees.plans.logical.LogicalRelation; + +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * OneRowRelationExtractAggregate. + * <p> + * example sql: + * <pre> + * SELECT 1, 'a', COUNT(); + * </pre> + * <p> + * origin plan: + * <p> + * LogicalOneRowRelation ( projects=[1 AS `1`#0, 'a' AS `'a'`#1, count(*) AS `count(*)`#2] ) + * transformed plan: + * <p> + * LogicalAggregate[23] ( groupByExpr=[], outputExpr=[1 AS `1`#0, 'a' AS `'a'`#1, count(*) AS `count(*)`#2], + * hasRepeat=false ) + * LogicalOneRowRelation ( projects=[] ) + */ +public class OneRowRelationExtractAggregate extends OneAnalysisRuleFactory { + @Override + public Rule build() { + return RuleType.ONE_ROW_RELATION_EXTRACT_AGGREGATE.build( + logicalOneRowRelation().then(relation -> { + List<NamedExpression> outputs = relation.getOutputs(); + boolean needGlobalAggregate = outputs + .stream() + .anyMatch(p -> p.accept(ExpressionVisitors.CONTAINS_AGGREGATE_CHECKER, null)); + if (needGlobalAggregate) { + LogicalRelation newRelation = new LogicalOneRowRelation(relation.getRelationId(), + ImmutableList.of()); + return new LogicalAggregate<>(ImmutableList.of(), relation.getOutputs(), newRelation); + } else { + return relation; + } + }) + ); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java index 66371ae0006..da642e76610 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java @@ -19,10 +19,7 @@ package org.apache.doris.nereids.rules.analysis; import org.apache.doris.nereids.rules.Rule; import org.apache.doris.nereids.rules.RuleType; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.WindowExpression; -import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; -import org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionVisitor; +import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitors; import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; import com.google.common.collect.ImmutableList; @@ -49,7 +46,7 @@ public class ProjectToGlobalAggregate extends OneAnalysisRuleFactory { logicalProject().then(project -> { boolean needGlobalAggregate = project.getProjects() .stream() - .anyMatch(p -> p.accept(ContainsAggregateChecker.INSTANCE, null)); + .anyMatch(p -> p.accept(ExpressionVisitors.CONTAINS_AGGREGATE_CHECKER, null)); if (needGlobalAggregate) { return new LogicalAggregate<>(ImmutableList.of(), project.getProjects(), project.child()); @@ -59,32 +56,4 @@ public class ProjectToGlobalAggregate extends OneAnalysisRuleFactory { }) ); } - - private static class ContainsAggregateChecker extends DefaultExpressionVisitor<Boolean, Void> { - - private static final ContainsAggregateChecker INSTANCE = new ContainsAggregateChecker(); - - @Override - public Boolean visit(Expression expr, Void context) { - boolean needAggregate = false; - for (Expression child : expr.children()) { - needAggregate = needAggregate || child.accept(this, context); - } - return needAggregate; - } - - @Override - public Boolean visitWindow(WindowExpression windowExpression, Void context) { - boolean needAggregate = false; - for (Expression child : windowExpression.getExpressionsInWindowSpec()) { - needAggregate = needAggregate || child.accept(this, context); - } - return needAggregate; - } - - @Override - public Boolean visitAggregateFunction(AggregateFunction aggregateFunction, Void context) { - return true; - } - } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ColumnPruning.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ColumnPruning.java index 375ce34e6a8..32e9cf64b67 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ColumnPruning.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/ColumnPruning.java @@ -215,6 +215,9 @@ public class ColumnPruning extends DefaultPlanRewriter<PruneContext> implements /** prune output */ public static <P extends Plan> P pruneOutput(P plan, List<NamedExpression> originOutput, Function<List<NamedExpression>, P> withPrunedOutput, PruneContext context) { + if (originOutput.isEmpty()) { + return plan; + } List<NamedExpression> prunedOutputs = originOutput.stream() .filter(output -> context.requiredSlots.contains(output.toSlot())) .collect(ImmutableList.toImmutableList()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitors.java similarity index 55% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitors.java index 66371ae0006..513da0e93d9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitors.java @@ -15,55 +15,22 @@ // specific language governing permissions and limitations // under the License. -package org.apache.doris.nereids.rules.analysis; +package org.apache.doris.nereids.trees.expressions.visitor; -import org.apache.doris.nereids.rules.Rule; -import org.apache.doris.nereids.rules.RuleType; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.WindowExpression; import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; -import org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionVisitor; -import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; - -import com.google.common.collect.ImmutableList; /** - * ProjectToGlobalAggregate. - * <p> - * example sql: - * <pre> - * select sum(value) - * from tbl - * </pre> - * - * origin plan: transformed plan: - * <p> - * LogicalProject(projects=[sum(value)]) LogicalAggregate(groupBy=[], output=[sum(value)]) - * | => | - * LogicalOlapScan(table=tbl) LogicalOlapScan(table=tbl) + * This is the factory for all ExpressionVisitor instance. + * All children instance of DefaultExpressionVisitor or ExpressionVisitor for common usage + * should be here and expose self by class static final field. */ -public class ProjectToGlobalAggregate extends OneAnalysisRuleFactory { - @Override - public Rule build() { - return RuleType.PROJECT_TO_GLOBAL_AGGREGATE.build( - logicalProject().then(project -> { - boolean needGlobalAggregate = project.getProjects() - .stream() - .anyMatch(p -> p.accept(ContainsAggregateChecker.INSTANCE, null)); +public class ExpressionVisitors { - if (needGlobalAggregate) { - return new LogicalAggregate<>(ImmutableList.of(), project.getProjects(), project.child()); - } else { - return project; - } - }) - ); - } + public static final ContainsAggregateChecker CONTAINS_AGGREGATE_CHECKER = new ContainsAggregateChecker(); private static class ContainsAggregateChecker extends DefaultExpressionVisitor<Boolean, Void> { - - private static final ContainsAggregateChecker INSTANCE = new ContainsAggregateChecker(); - @Override public Boolean visit(Expression expr, Void context) { boolean needAggregate = false; diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOneRowRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOneRowRelation.java index 68351c9a902..ffc7c0d625a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOneRowRelation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOneRowRelation.java @@ -22,7 +22,6 @@ import org.apache.doris.nereids.properties.LogicalProperties; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.NamedExpression; import org.apache.doris.nereids.trees.expressions.Slot; -import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; import org.apache.doris.nereids.trees.plans.RelationId; @@ -30,7 +29,6 @@ import org.apache.doris.nereids.trees.plans.algebra.OneRowRelation; import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; import org.apache.doris.nereids.util.Utils; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.util.List; @@ -52,8 +50,6 @@ public class LogicalOneRowRelation extends LogicalRelation implements OneRowRela private LogicalOneRowRelation(RelationId relationId, List<NamedExpression> projects, Optional<GroupExpression> groupExpression, Optional<LogicalProperties> logicalProperties) { super(relationId, PlanType.LOGICAL_ONE_ROW_RELATION, groupExpression, logicalProperties); - Preconditions.checkArgument(projects.stream().noneMatch(p -> p.containsType(AggregateFunction.class)), - "OneRowRelation can not contains any aggregate function"); this.projects = ImmutableList.copyOf(Objects.requireNonNull(projects, "projects can not be null")); } diff --git a/regression-test/data/nereids_p0/select_no_from/sql/projectAggFuncs.out b/regression-test/data/nereids_p0/select_no_from/sql/projectAggFuncs.out new file mode 100644 index 00000000000..7ae8fd347ed --- /dev/null +++ b/regression-test/data/nereids_p0/select_no_from/sql/projectAggFuncs.out @@ -0,0 +1,4 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !projectAggFuncs -- +1 a 1 2 2.0 3 4 1 1 1 5 6.0 1 7 8 + diff --git a/regression-test/data/query_p0/select_no_from/sql/projectAggFuncs.out b/regression-test/data/query_p0/select_no_from/sql/projectAggFuncs.out new file mode 100644 index 00000000000..7ae8fd347ed --- /dev/null +++ b/regression-test/data/query_p0/select_no_from/sql/projectAggFuncs.out @@ -0,0 +1,4 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !projectAggFuncs -- +1 a 1 2 2.0 3 4 1 1 1 5 6.0 1 7 8 + diff --git a/regression-test/suites/nereids_p0/select_no_from/sql/projectAggFuncs.sql b/regression-test/suites/nereids_p0/select_no_from/sql/projectAggFuncs.sql index 50c3d56ed8f..d2416eb991c 100644 --- a/regression-test/suites/nereids_p0/select_no_from/sql/projectAggFuncs.sql +++ b/regression-test/suites/nereids_p0/select_no_from/sql/projectAggFuncs.sql @@ -1,4 +1,17 @@ -/* -- database: presto; groups: no_from -SELECT COUNT(10), MAX(50), MIN(90.0) -*/ +SELECT 1, + 'a', + COUNT(), + SUM(1) + 1, + AVG(2) / COUNT(), + MAX(3), + MIN(4), + RANK() OVER() AS w_rank, + DENSE_RANK() OVER() AS w_dense_rank, + ROW_NUMBER() OVER() AS w_row_number, + SUM(5) OVER() AS w_sum, + AVG(6) OVER() AS w_avg, + COUNT() OVER() AS w_count, + MAX(7) OVER() AS w_max, + MIN(8) OVER() AS w_min; + diff --git a/regression-test/suites/nereids_syntax_p0/one_row_relation.groovy b/regression-test/suites/nereids_syntax_p0/one_row_relation.groovy index 9b814cc4fe0..e389960e79e 100644 --- a/regression-test/suites/nereids_syntax_p0/one_row_relation.groovy +++ b/regression-test/suites/nereids_syntax_p0/one_row_relation.groovy @@ -31,11 +31,4 @@ suite("one_row_relation") { )a""" result([[100, "abc", "ab", "de", null]]) } - - test { - sql """ - select sum(1); - """ - exception "OneRowRelation can not contains any aggregate function" - } } diff --git a/regression-test/suites/query_p0/select_no_from/sql/projectAggFuncs.sql b/regression-test/suites/query_p0/select_no_from/sql/projectAggFuncs.sql index 50c3d56ed8f..a0007ff2df7 100644 --- a/regression-test/suites/query_p0/select_no_from/sql/projectAggFuncs.sql +++ b/regression-test/suites/query_p0/select_no_from/sql/projectAggFuncs.sql @@ -1,4 +1,16 @@ -/* -- database: presto; groups: no_from -SELECT COUNT(10), MAX(50), MIN(90.0) -*/ +SELECT 1, + 'a', + COUNT(), + SUM(1) + 1, + AVG(2) / COUNT(), + MAX(3), + MIN(4), + RANK() OVER() AS w_rank, + DENSE_RANK() OVER() AS w_dense_rank, + ROW_NUMBER() OVER() AS w_row_number, + SUM(5) OVER() AS w_sum, + AVG(6) OVER() AS w_avg, + COUNT() OVER() AS w_count, + MAX(7) OVER() AS w_max, + MIN(8) OVER() AS w_min; --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org