diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java index 3d463c82bab30b..b37b04d8022b58 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java @@ -22,47 +22,35 @@ import org.apache.doris.nereids.rules.exploration.mv.StructInfo.PlanCheckContext; import org.apache.doris.nereids.rules.exploration.mv.StructInfo.PlanSplitContext; import org.apache.doris.nereids.rules.exploration.mv.mapping.SlotMapping; +import org.apache.doris.nereids.rules.exploration.mv.rollup.AggFunctionRollUpHandler; +import org.apache.doris.nereids.rules.exploration.mv.rollup.BothCombinatorRollupHandler; +import org.apache.doris.nereids.rules.exploration.mv.rollup.DirectRollupHandler; +import org.apache.doris.nereids.rules.exploration.mv.rollup.MappingRollupHandler; +import org.apache.doris.nereids.rules.exploration.mv.rollup.SingleCombinatorRollupHandler; import org.apache.doris.nereids.trees.expressions.Alias; -import org.apache.doris.nereids.trees.expressions.Any; -import org.apache.doris.nereids.trees.expressions.Cast; import org.apache.doris.nereids.trees.expressions.ExprId; 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.Function; import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; -import org.apache.doris.nereids.trees.expressions.functions.agg.BitmapUnion; -import org.apache.doris.nereids.trees.expressions.functions.agg.BitmapUnionCount; -import org.apache.doris.nereids.trees.expressions.functions.agg.CouldRollUp; -import org.apache.doris.nereids.trees.expressions.functions.agg.Count; -import org.apache.doris.nereids.trees.expressions.functions.agg.HllUnion; -import org.apache.doris.nereids.trees.expressions.functions.agg.HllUnionAgg; -import org.apache.doris.nereids.trees.expressions.functions.agg.Ndv; -import org.apache.doris.nereids.trees.expressions.functions.scalar.HllCardinality; -import org.apache.doris.nereids.trees.expressions.functions.scalar.HllHash; -import org.apache.doris.nereids.trees.expressions.functions.scalar.ToBitmap; +import org.apache.doris.nereids.trees.expressions.functions.agg.RollUpTrait; import org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionRewriter; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.trees.plans.visitor.ExpressionLineageReplacer; -import org.apache.doris.nereids.types.BigIntType; -import org.apache.doris.nereids.types.VarcharType; import org.apache.doris.nereids.util.ExpressionUtils; -import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.BitSet; -import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -72,92 +60,15 @@ */ public abstract class AbstractMaterializedViewAggregateRule extends AbstractMaterializedViewRule { - protected static final Multimap - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP = ArrayListMultimap.create(); + public static final List ROLL_UP_HANDLERS = + ImmutableList.of(DirectRollupHandler.INSTANCE, + MappingRollupHandler.INSTANCE, + SingleCombinatorRollupHandler.INSTANCE, + BothCombinatorRollupHandler.INSTANCE); + protected static final AggregateExpressionRewriter AGGREGATE_EXPRESSION_REWRITER = new AggregateExpressionRewriter(); - static { - // support roll up when count distinct is in query - // the column type is not bitMap - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new Count(true, Any.INSTANCE), - new BitmapUnion(new ToBitmap(Any.INSTANCE))); - // with bitmap_union, to_bitmap and cast - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new Count(true, Any.INSTANCE), - new BitmapUnion(new ToBitmap(new Cast(Any.INSTANCE, BigIntType.INSTANCE)))); - - // support roll up when bitmap_union_count is in query - // the column type is bitMap - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( - new BitmapUnionCount(Any.INSTANCE), - new BitmapUnion(Any.INSTANCE)); - // the column type is not bitMap - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( - new BitmapUnionCount(new ToBitmap(Any.INSTANCE)), - new BitmapUnion(new ToBitmap(Any.INSTANCE))); - // with bitmap_union, to_bitmap and cast - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( - new BitmapUnionCount(new ToBitmap(new Cast(Any.INSTANCE, BigIntType.INSTANCE))), - new BitmapUnion(new ToBitmap(new Cast(Any.INSTANCE, BigIntType.INSTANCE)))); - - // support roll up when the column type is not hll - // query is approx_count_distinct - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new Ndv(Any.INSTANCE), - new HllUnion(new HllHash(Any.INSTANCE))); - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new Ndv(Any.INSTANCE), - new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); - - // query is HLL_UNION_AGG - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnionAgg(new HllHash(Any.INSTANCE)), - new HllUnion(new HllHash(Any.INSTANCE))); - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnionAgg(new HllHash(Any.INSTANCE)), - new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( - new HllUnionAgg(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT))), - new HllUnion(new HllHash(Any.INSTANCE))); - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( - new HllUnionAgg(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT))), - new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); - - // query is HLL_CARDINALITY - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllCardinality(new HllUnion(new HllHash(Any.INSTANCE))), - new HllUnion(new HllHash(Any.INSTANCE))); - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllCardinality(new HllUnion(new HllHash(Any.INSTANCE))), - new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( - new HllCardinality(new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))), - new HllUnion(new HllHash(Any.INSTANCE))); - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( - new HllCardinality(new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))), - new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); - - // query is HLL_RAW_AGG or HLL_UNION - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnion(new HllHash(Any.INSTANCE)), - new HllUnion(new HllHash(Any.INSTANCE))); - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnion(new HllHash(Any.INSTANCE)), - new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( - new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT))), - new HllUnion(new HllHash(Any.INSTANCE))); - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( - new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT))), - new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); - - // support roll up when the column type is hll - // query is HLL_UNION_AGG - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnionAgg(Any.INSTANCE), - new HllUnion(Any.INSTANCE)); - - // query is HLL_CARDINALITY - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllCardinality(new HllUnion(Any.INSTANCE)), - new HllUnion(Any.INSTANCE)); - - // query is HLL_RAW_AGG or HLL_UNION - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnion(Any.INSTANCE), - new HllUnion(Any.INSTANCE)); - - } - @Override protected Plan rewriteQueryByView(MatchMode matchMode, StructInfo queryStructInfo, @@ -375,35 +286,22 @@ private boolean isGroupByEquals(Pair> queryTopPlanA private static Function rollup(AggregateFunction queryAggregateFunction, Expression queryAggregateFunctionShuttled, Map mvExprToMvScanExprQueryBased) { - if (!(queryAggregateFunction instanceof CouldRollUp)) { - return null; - } - Expression rollupParam = null; - Expression viewRollupFunction = null; - // handle simple aggregate function roll up which is not in the AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP - if (mvExprToMvScanExprQueryBased.containsKey(queryAggregateFunctionShuttled) - && AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.keySet().stream() - .noneMatch(aggFunction -> aggFunction.equals(queryAggregateFunction))) { - rollupParam = mvExprToMvScanExprQueryBased.get(queryAggregateFunctionShuttled); - viewRollupFunction = queryAggregateFunctionShuttled; - } else { - // handle complex functions roll up - // eg: query is count(distinct param), mv sql is bitmap_union(to_bitmap(param)) - for (Expression mvExprShuttled : mvExprToMvScanExprQueryBased.keySet()) { - if (!(mvExprShuttled instanceof Function)) { + for (Map.Entry expressionEntry : mvExprToMvScanExprQueryBased.entrySet()) { + Pair mvExprToMvScanExprQueryBasedPair = Pair.of(expressionEntry.getKey(), + expressionEntry.getValue()); + for (AggFunctionRollUpHandler rollUpHandler : ROLL_UP_HANDLERS) { + if (!rollUpHandler.canRollup(queryAggregateFunction, queryAggregateFunctionShuttled, + mvExprToMvScanExprQueryBasedPair)) { continue; } - if (isAggregateFunctionEquivalent(queryAggregateFunction, (Function) mvExprShuttled)) { - rollupParam = mvExprToMvScanExprQueryBased.get(mvExprShuttled); - viewRollupFunction = mvExprShuttled; + Function rollupFunction = rollUpHandler.doRollup(queryAggregateFunction, + queryAggregateFunctionShuttled, mvExprToMvScanExprQueryBasedPair); + if (rollupFunction != null) { + return rollupFunction; } } } - if (rollupParam == null || !canRollup(viewRollupFunction)) { - return null; - } - // do roll up - return ((CouldRollUp) queryAggregateFunction).constructRollUp(rollupParam); + return null; } // Check the aggregate function can roll up or not, return true if could roll up @@ -418,7 +316,7 @@ private static boolean canRollup(Expression rollupExpression) { } if (rollupExpression instanceof AggregateFunction) { AggregateFunction aggregateFunction = (AggregateFunction) rollupExpression; - return !aggregateFunction.isDistinct() && aggregateFunction instanceof CouldRollUp; + return !aggregateFunction.isDistinct() && aggregateFunction instanceof RollUpTrait; } return true; } @@ -480,60 +378,6 @@ protected boolean checkPattern(StructInfo structInfo, CascadesContext cascadesCo && checkContext.isContainsTopAggregate() && checkContext.getTopAggregateNum() <= 1; } - /** - * Check the queryFunction is equivalent to view function when function roll up. - * Not only check the function name but also check the argument between query and view aggregate function. - * Such as query is - * select count(distinct a) + 1 from table group by b. - * mv is - * select bitmap_union(to_bitmap(a)) from table group by a, b. - * the queryAggregateFunction is count(distinct a), queryAggregateFunctionShuttled is count(distinct a) + 1 - * mvExprToMvScanExprQueryBased is { bitmap_union(to_bitmap(a)) : MTMVScan(output#0) } - * This will check the count(distinct a) in query is equivalent to bitmap_union(to_bitmap(a)) in mv, - * and then check their arguments is equivalent. - */ - private static boolean isAggregateFunctionEquivalent(Function queryFunction, Function viewFunction) { - if (queryFunction.equals(viewFunction)) { - return true; - } - // check the argument of rollup function is equivalent to view function or not - for (Map.Entry> equivalentFunctionEntry : - AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.asMap().entrySet()) { - if (equivalentFunctionEntry.getKey().equals(queryFunction)) { - // check is have equivalent function or not - for (Expression equivalentFunction : equivalentFunctionEntry.getValue()) { - if (!Any.equals(equivalentFunction, viewFunction)) { - continue; - } - // check param in query function is same as the view function - List viewFunctionArguments = extractArguments(equivalentFunction, viewFunction); - List queryFunctionArguments = - extractArguments(equivalentFunctionEntry.getKey(), queryFunction); - // check argument size,we only support roll up function which has only one argument currently - if (queryFunctionArguments.size() != 1 || viewFunctionArguments.size() != 1) { - continue; - } - if (Objects.equals(queryFunctionArguments.get(0), viewFunctionArguments.get(0))) { - return true; - } - } - } - } - return false; - } - - /** - * Extract the function arguments by functionWithAny pattern - * Such as functionWithAny def is bitmap_union(to_bitmap(Any.INSTANCE)), - * actualFunction is bitmap_union(to_bitmap(case when a = 5 then 1 else 2 end)) - * after extracting, the return argument is: case when a = 5 then 1 else 2 end - */ - private static List extractArguments(Expression functionWithAny, Function actualFunction) { - Set exprSetToRemove = functionWithAny.collectToSet(expr -> !(expr instanceof Any)); - return actualFunction.collectFirst(expr -> - exprSetToRemove.stream().noneMatch(exprToRemove -> exprToRemove.equals(expr))); - } - /** * Aggregate expression rewriter which is responsible for rewriting group by and * aggregate function expression diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/AggFunctionRollUpHandler.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/AggFunctionRollUpHandler.java new file mode 100644 index 00000000000000..97229af62c3382 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/AggFunctionRollUpHandler.java @@ -0,0 +1,78 @@ +// 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.exploration.mv.rollup; + +import org.apache.doris.common.Pair; +import org.apache.doris.nereids.trees.expressions.Any; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.functions.Function; +import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; +import org.apache.doris.nereids.trees.expressions.functions.agg.RollUpTrait; + +import java.util.List; +import java.util.Set; + +/** + * Aggregate function roll up handler + */ +public abstract class AggFunctionRollUpHandler { + + /** + * Decide the query and view function can roll up or not + */ + public boolean canRollup(AggregateFunction queryAggregateFunction, + Expression queryAggregateFunctionShuttled, + Pair mvExprToMvScanExprQueryBasedPair) { + Expression viewExpression = mvExprToMvScanExprQueryBasedPair.key(); + if (!(viewExpression instanceof RollUpTrait) || !((RollUpTrait) viewExpression).canRollUp()) { + return false; + } + AggregateFunction aggregateFunction = (AggregateFunction) viewExpression; + return !aggregateFunction.isDistinct(); + } + + /** + * Do the aggregate function roll up + */ + public abstract Function doRollup( + AggregateFunction queryAggregateFunction, + Expression queryAggregateFunctionShuttled, + Pair mvExprToMvScanExprQueryBasedPair); + + /** + * Extract the function arguments by functionWithAny pattern + * Such as functionWithAny def is bitmap_union(to_bitmap(Any.INSTANCE)), + * actualFunction is bitmap_union(to_bitmap(case when a = 5 then 1 else 2 end)) + * after extracting, the return argument is: case when a = 5 then 1 else 2 end + */ + protected static List extractArguments(Expression functionWithAny, Function actualFunction) { + Set exprSetToRemove = functionWithAny.collectToSet(expr -> !(expr instanceof Any)); + return actualFunction.collectFirst(expr -> + exprSetToRemove.stream().noneMatch(exprToRemove -> exprToRemove.equals(expr))); + } + + /** + * Extract the target expression in actualFunction by targetClazz + * Such as actualFunction def is avg_merge(avg_union(c1)), target Clazz is Combinator + * after extracting, the return argument is avg_union(c1) + */ + protected static T extractLastExpression(Expression actualFunction, Class targetClazz) { + List expressions = actualFunction.collectToList(targetClazz::isInstance); + return targetClazz.cast(expressions.get(expressions.size() - 1)); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/BothCombinatorRollupHandler.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/BothCombinatorRollupHandler.java new file mode 100644 index 00000000000000..b29b2668a7f847 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/BothCombinatorRollupHandler.java @@ -0,0 +1,64 @@ +// 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.exploration.mv.rollup; + +import org.apache.doris.common.Pair; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.functions.Function; +import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; +import org.apache.doris.nereids.trees.expressions.functions.agg.RollUpTrait; +import org.apache.doris.nereids.trees.expressions.functions.combinator.Combinator; + +import java.util.Objects; + +/** + * Handle the combinator aggregate function roll up, both query and view are combinator + * Such as query is select c1 sum_merge(sum_state(c2)) from orders group by c1; + * view is select c1 sum_union(sum_state(c2)) from orders group by c1; + */ +public class BothCombinatorRollupHandler extends AggFunctionRollUpHandler { + + public static BothCombinatorRollupHandler INSTANCE = new BothCombinatorRollupHandler(); + + @Override + public boolean canRollup(AggregateFunction queryAggregateFunction, + Expression queryAggregateFunctionShuttled, + Pair mvExprToMvScanExprQueryBasedPair) { + Expression viewFunction = mvExprToMvScanExprQueryBasedPair.key(); + if (!super.canRollup(queryAggregateFunction, queryAggregateFunctionShuttled, + mvExprToMvScanExprQueryBasedPair)) { + return false; + } + if (queryAggregateFunction instanceof Combinator && viewFunction instanceof Combinator) { + Combinator queryCombinator = extractLastExpression(queryAggregateFunction, Combinator.class); + Combinator viewCombinator = extractLastExpression(viewFunction, Combinator.class); + // construct actual aggregate function in combinator and compare + return Objects.equals(queryCombinator.getNestedFunction().withChildren(queryCombinator.getArguments()), + viewCombinator.getNestedFunction().withChildren(viewCombinator.getArguments())); + } + return false; + } + + @Override + public Function doRollup(AggregateFunction queryAggregateFunction, + Expression queryAggregateFunctionShuttled, + Pair mvExprToMvScanExprQueryBasedPair) { + Expression rollupParam = mvExprToMvScanExprQueryBasedPair.value(); + return ((RollUpTrait) queryAggregateFunction).constructRollUp(rollupParam); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/DirectRollupHandler.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/DirectRollupHandler.java new file mode 100644 index 00000000000000..e0106705bcd7af --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/DirectRollupHandler.java @@ -0,0 +1,63 @@ +// 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.exploration.mv.rollup; + +import org.apache.doris.common.Pair; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.functions.Function; +import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; +import org.apache.doris.nereids.trees.expressions.functions.agg.RollUpTrait; +import org.apache.doris.nereids.trees.expressions.functions.combinator.Combinator; + +/** + * Roll up directly, for example, + * query is select c1, sum(c2) from t1 group by c1 + * view is select c1, c2, sum(c2) from t1 group by c1, c2, + * the aggregate function in query and view is same, This handle the sum aggregate function roll up + */ +public class DirectRollupHandler extends AggFunctionRollUpHandler { + + public static DirectRollupHandler INSTANCE = new DirectRollupHandler(); + + @Override + public boolean canRollup( + AggregateFunction queryAggregateFunction, + Expression queryAggregateFunctionShuttled, + Pair mvExprToMvScanExprQueryBasedPair) { + Expression viewExpression = mvExprToMvScanExprQueryBasedPair.key(); + if (!super.canRollup(queryAggregateFunction, queryAggregateFunctionShuttled, + mvExprToMvScanExprQueryBasedPair)) { + return false; + } + return queryAggregateFunctionShuttled.equals(viewExpression) + && MappingRollupHandler.AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.keySet().stream() + .noneMatch(aggFunction -> aggFunction.equals(queryAggregateFunction)) + && !(queryAggregateFunction instanceof Combinator); + } + + @Override + public Function doRollup(AggregateFunction queryAggregateFunction, + Expression queryAggregateFunctionShuttled, + Pair mvExprToMvScanExprQueryBasedPair) { + Expression rollupParam = mvExprToMvScanExprQueryBasedPair.value(); + if (rollupParam == null) { + return null; + } + return ((RollUpTrait) queryAggregateFunction).constructRollUp(rollupParam); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/MappingRollupHandler.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/MappingRollupHandler.java new file mode 100644 index 00000000000000..cf14217c50dc75 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/MappingRollupHandler.java @@ -0,0 +1,181 @@ +// 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.exploration.mv.rollup; + +import org.apache.doris.common.Pair; +import org.apache.doris.nereids.trees.expressions.Any; +import org.apache.doris.nereids.trees.expressions.Cast; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.functions.Function; +import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; +import org.apache.doris.nereids.trees.expressions.functions.agg.BitmapUnion; +import org.apache.doris.nereids.trees.expressions.functions.agg.BitmapUnionCount; +import org.apache.doris.nereids.trees.expressions.functions.agg.Count; +import org.apache.doris.nereids.trees.expressions.functions.agg.HllUnion; +import org.apache.doris.nereids.trees.expressions.functions.agg.HllUnionAgg; +import org.apache.doris.nereids.trees.expressions.functions.agg.Ndv; +import org.apache.doris.nereids.trees.expressions.functions.agg.RollUpTrait; +import org.apache.doris.nereids.trees.expressions.functions.scalar.HllCardinality; +import org.apache.doris.nereids.trees.expressions.functions.scalar.HllHash; +import org.apache.doris.nereids.trees.expressions.functions.scalar.ToBitmap; +import org.apache.doris.nereids.types.BigIntType; +import org.apache.doris.nereids.types.VarcharType; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * Handle the aggregate functions roll up which are in AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP + */ +public class MappingRollupHandler extends AggFunctionRollUpHandler { + + public static MappingRollupHandler INSTANCE = new MappingRollupHandler(); + public static final Multimap + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP = ArrayListMultimap.create(); + + static { + // support roll up when count distinct is in query + // the column type is not bitMap + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new Count(true, Any.INSTANCE), + new BitmapUnion(new ToBitmap(Any.INSTANCE))); + // with bitmap_union, to_bitmap and cast + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new Count(true, Any.INSTANCE), + new BitmapUnion(new ToBitmap(new Cast(Any.INSTANCE, BigIntType.INSTANCE)))); + + // support roll up when bitmap_union_count is in query + // the column type is bitMap + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( + new BitmapUnionCount(Any.INSTANCE), + new BitmapUnion(Any.INSTANCE)); + // the column type is not bitMap + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( + new BitmapUnionCount(new ToBitmap(Any.INSTANCE)), + new BitmapUnion(new ToBitmap(Any.INSTANCE))); + // with bitmap_union, to_bitmap and cast + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( + new BitmapUnionCount(new ToBitmap(new Cast(Any.INSTANCE, BigIntType.INSTANCE))), + new BitmapUnion(new ToBitmap(new Cast(Any.INSTANCE, BigIntType.INSTANCE)))); + + // support roll up when the column type is not hll + // query is approx_count_distinct + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new Ndv(Any.INSTANCE), + new HllUnion(new HllHash(Any.INSTANCE))); + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new Ndv(Any.INSTANCE), + new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); + + // query is HLL_UNION_AGG + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnionAgg(new HllHash(Any.INSTANCE)), + new HllUnion(new HllHash(Any.INSTANCE))); + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnionAgg(new HllHash(Any.INSTANCE)), + new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( + new HllUnionAgg(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT))), + new HllUnion(new HllHash(Any.INSTANCE))); + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( + new HllUnionAgg(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT))), + new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); + + // query is HLL_CARDINALITY + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllCardinality(new HllUnion(new HllHash(Any.INSTANCE))), + new HllUnion(new HllHash(Any.INSTANCE))); + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllCardinality(new HllUnion(new HllHash(Any.INSTANCE))), + new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( + new HllCardinality(new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))), + new HllUnion(new HllHash(Any.INSTANCE))); + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( + new HllCardinality(new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))), + new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); + + // query is HLL_RAW_AGG or HLL_UNION + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnion(new HllHash(Any.INSTANCE)), + new HllUnion(new HllHash(Any.INSTANCE))); + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnion(new HllHash(Any.INSTANCE)), + new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( + new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT))), + new HllUnion(new HllHash(Any.INSTANCE))); + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put( + new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT))), + new HllUnion(new HllHash(new Cast(Any.INSTANCE, VarcharType.SYSTEM_DEFAULT)))); + + // support roll up when the column type is hll + // query is HLL_UNION_AGG + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnionAgg(Any.INSTANCE), + new HllUnion(Any.INSTANCE)); + + // query is HLL_CARDINALITY + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllCardinality(new HllUnion(Any.INSTANCE)), + new HllUnion(Any.INSTANCE)); + + // query is HLL_RAW_AGG or HLL_UNION + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.put(new HllUnion(Any.INSTANCE), + new HllUnion(Any.INSTANCE)); + + } + + @Override + public boolean canRollup(AggregateFunction queryAggregateFunction, + Expression queryAggregateFunctionShuttled, + Pair mvExprToMvScanExprQueryBasedPair) { + // handle complex functions roll up by mapping and combinator expression + // eg: query is count(distinct param), mv sql is bitmap_union(to_bitmap(param)) + Expression viewExpression = mvExprToMvScanExprQueryBasedPair.key(); + if (!super.canRollup(queryAggregateFunction, queryAggregateFunctionShuttled, + mvExprToMvScanExprQueryBasedPair)) { + return false; + } + Function viewFunction = (Function) viewExpression; + for (Map.Entry> equivalentFunctionEntry : + AGGREGATE_ROLL_UP_EQUIVALENT_FUNCTION_MAP.asMap().entrySet()) { + if (equivalentFunctionEntry.getKey().equals(queryAggregateFunction)) { + // check is have equivalent function or not + for (Expression equivalentFunction : equivalentFunctionEntry.getValue()) { + if (!Any.equals(equivalentFunction, viewFunction)) { + continue; + } + // check param in query function is same as the view function + List viewFunctionArguments = extractArguments(equivalentFunction, viewFunction); + List queryFunctionArguments = + extractArguments(equivalentFunctionEntry.getKey(), queryAggregateFunction); + // check argument size,we only support roll up function which has only one argument currently + if (queryFunctionArguments.size() != 1 || viewFunctionArguments.size() != 1) { + continue; + } + if (Objects.equals(queryFunctionArguments.get(0), viewFunctionArguments.get(0))) { + return true; + } + } + } + } + return false; + } + + @Override + public Function doRollup(AggregateFunction queryAggregateFunction, + Expression queryAggregateFunctionShuttled, + Pair mvExprToMvScanExprQueryBasedPair) { + Expression rollupParam = mvExprToMvScanExprQueryBasedPair.value(); + return ((RollUpTrait) queryAggregateFunction).constructRollUp(rollupParam); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/SingleCombinatorRollupHandler.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/SingleCombinatorRollupHandler.java new file mode 100644 index 00000000000000..d9677cbe6cca85 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/rollup/SingleCombinatorRollupHandler.java @@ -0,0 +1,75 @@ +// 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.exploration.mv.rollup; + +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.FunctionRegistry; +import org.apache.doris.common.Pair; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.functions.AggCombinerFunctionBuilder; +import org.apache.doris.nereids.trees.expressions.functions.BoundFunction; +import org.apache.doris.nereids.trees.expressions.functions.Function; +import org.apache.doris.nereids.trees.expressions.functions.FunctionBuilder; +import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; +import org.apache.doris.nereids.trees.expressions.functions.combinator.Combinator; +import org.apache.doris.nereids.trees.expressions.functions.combinator.StateCombinator; +import org.apache.doris.nereids.trees.expressions.functions.combinator.UnionCombinator; + +import java.util.Objects; + +/** + * Handle the combinator aggregate function roll up, Only view is combinator, query is aggregate function. + * Such as query is select c1 sum(c2) from orders group by c1; + * view is select c1 sum_union(sum_state(c2)) from orders group by c1; + * */ +public class SingleCombinatorRollupHandler extends AggFunctionRollUpHandler { + + public static SingleCombinatorRollupHandler INSTANCE = new SingleCombinatorRollupHandler(); + + @Override + public boolean canRollup(AggregateFunction queryAggregateFunction, + Expression queryAggregateFunctionShuttled, + Pair mvExprToMvScanExprQueryBasedPair) { + Expression viewFunction = mvExprToMvScanExprQueryBasedPair.key(); + if (!super.canRollup(queryAggregateFunction, queryAggregateFunctionShuttled, + mvExprToMvScanExprQueryBasedPair)) { + return false; + } + if (!(queryAggregateFunction instanceof Combinator) + && (viewFunction instanceof UnionCombinator || viewFunction instanceof StateCombinator)) { + Combinator viewCombinator = extractLastExpression(viewFunction, Combinator.class); + return Objects.equals(queryAggregateFunction, + viewCombinator.getNestedFunction().withChildren(viewCombinator.getArguments())); + } + return false; + } + + @Override + public Function doRollup(AggregateFunction queryAggregateFunction, + Expression queryAggregateFunctionShuttled, + Pair mvExprToMvScanExprQueryBasedPair) { + FunctionRegistry functionRegistry = Env.getCurrentEnv().getFunctionRegistry(); + String combinatorName = queryAggregateFunction.getName() + AggCombinerFunctionBuilder.MERGE_SUFFIX; + Expression rollupParam = mvExprToMvScanExprQueryBasedPair.value(); + FunctionBuilder functionBuilder = + functionRegistry.findFunctionBuilder(combinatorName, rollupParam); + Pair targetExpressionPair = + functionBuilder.build(combinatorName, rollupParam); + return (Function) targetExpressionPair.key(); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/BitmapUnion.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/BitmapUnion.java index bd2a071697d00d..3b3a37bb7607ed 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/BitmapUnion.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/BitmapUnion.java @@ -36,7 +36,7 @@ * AggregateFunction 'bitmap_union'. This class is generated by GenerateFunction. */ public class BitmapUnion extends AggregateFunction - implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, BitmapFunction, CouldRollUp { + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, BitmapFunction, RollUpTrait { public static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(BitmapType.INSTANCE).args(BitmapType.INSTANCE) @@ -84,4 +84,9 @@ public List getSignatures() { public Function constructRollUp(Expression param, Expression... varParams) { return new BitmapUnion(this.isDistinct(), param); } + + @Override + public boolean canRollUp() { + return true; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/BitmapUnionCount.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/BitmapUnionCount.java index 667fe2021fb28d..08772b06d57447 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/BitmapUnionCount.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/BitmapUnionCount.java @@ -37,7 +37,7 @@ * AggregateFunction 'bitmap_union_count'. This class is generated by GenerateFunction. */ public class BitmapUnionCount extends AggregateFunction - implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, BitmapFunction, CouldRollUp { + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, BitmapFunction, RollUpTrait { public static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(BigIntType.INSTANCE).args(BitmapType.INSTANCE) @@ -85,4 +85,9 @@ public List getSignatures() { public Function constructRollUp(Expression param, Expression... varParams) { return new BitmapUnionCount(param); } + + @Override + public boolean canRollUp() { + return false; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Count.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Count.java index afd1b39dbc12f3..2bfcbe91b35f84 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Count.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Count.java @@ -37,7 +37,7 @@ /** count agg function. */ public class Count extends AggregateFunction - implements ExplicitlyCastableSignature, AlwaysNotNullable, SupportWindowAnalytic, CouldRollUp { + implements ExplicitlyCastableSignature, AlwaysNotNullable, SupportWindowAnalytic, RollUpTrait { public static final List SIGNATURES = ImmutableList.of( // count(*) @@ -152,4 +152,9 @@ public Function constructRollUp(Expression param, Expression... varParams) { return new Sum(param); } } + + @Override + public boolean canRollUp() { + return true; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/HllUnion.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/HllUnion.java index 08c091f7402211..7f98d1b6c0d78c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/HllUnion.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/HllUnion.java @@ -36,7 +36,7 @@ * AggregateFunction 'hll_union'. This class is generated by GenerateFunction. */ public class HllUnion extends AggregateFunction - implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, HllFunction, CouldRollUp { + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, HllFunction, RollUpTrait { public static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(HllType.INSTANCE).args(HllType.INSTANCE) @@ -84,4 +84,9 @@ public List getSignatures() { public Function constructRollUp(Expression param, Expression... varParams) { return new HllUnion(param); } + + @Override + public boolean canRollUp() { + return true; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/HllUnionAgg.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/HllUnionAgg.java index 65ba8d44787218..15d02e73faff75 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/HllUnionAgg.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/HllUnionAgg.java @@ -37,7 +37,7 @@ * AggregateFunction 'hll_union_agg'. This class is generated by GenerateFunction. */ public class HllUnionAgg extends AggregateFunction - implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, HllFunction, CouldRollUp { + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, HllFunction, RollUpTrait { public static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(BigIntType.INSTANCE).args(HllType.INSTANCE) @@ -85,4 +85,9 @@ public List getSignatures() { public Function constructRollUp(Expression param, Expression... varParams) { return new HllUnionAgg(param); } + + @Override + public boolean canRollUp() { + return false; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Max.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Max.java index a879fe470b44ae..c04abb65d07c28 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Max.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Max.java @@ -37,7 +37,7 @@ /** max agg function. */ public class Max extends NullableAggregateFunction - implements UnaryExpression, CustomSignature, SupportWindowAnalytic, CouldRollUp { + implements UnaryExpression, CustomSignature, SupportWindowAnalytic, RollUpTrait { public Max(Expression child) { this(false, false, child); } @@ -91,4 +91,9 @@ public R accept(ExpressionVisitor visitor, C context) { public Function constructRollUp(Expression param, Expression... varParams) { return new Max(this.distinct, this.alwaysNullable, param); } + + @Override + public boolean canRollUp() { + return true; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Min.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Min.java index 8e8d0c7e874176..be2a3002dbd2c2 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Min.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Min.java @@ -37,7 +37,7 @@ /** min agg function. */ public class Min extends NullableAggregateFunction - implements UnaryExpression, CustomSignature, SupportWindowAnalytic, CouldRollUp { + implements UnaryExpression, CustomSignature, SupportWindowAnalytic, RollUpTrait { public Min(Expression child) { this(false, false, child); @@ -92,4 +92,9 @@ public R accept(ExpressionVisitor visitor, C context) { public Function constructRollUp(Expression param, Expression... varParams) { return new Min(this.distinct, this.alwaysNullable, param); } + + @Override + public boolean canRollUp() { + return true; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Ndv.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Ndv.java index 830d9214ec4ebe..25e5fb103dab8c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Ndv.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Ndv.java @@ -38,7 +38,7 @@ * AggregateFunction 'ndv'. This class is generated by GenserateFunction. */ public class Ndv extends AggregateFunction - implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, CouldRollUp { + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, RollUpTrait { public static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(BigIntType.INSTANCE).args(AnyDataType.INSTANCE_WITHOUT_INDEX) @@ -85,4 +85,9 @@ public List getSignatures() { public Function constructRollUp(Expression param, Expression... varParams) { return new HllUnionAgg(param); } + + @Override + public boolean canRollUp() { + return false; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/CouldRollUp.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/RollUpTrait.java similarity index 73% rename from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/CouldRollUp.java rename to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/RollUpTrait.java index 7004c16804a7a8..f521633c310bb7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/CouldRollUp.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/RollUpTrait.java @@ -21,14 +21,20 @@ import org.apache.doris.nereids.trees.expressions.functions.Function; /** - * Could roll up trait, it could be rolled up if a function appear in query which can be represented - * by aggregate function in view. + * Roll up trait, which identify an function could be rolled up if a function appear in query + * which can be represented by aggregate function in view. * Acquire the rolled up function by constructRollUp method. */ -public interface CouldRollUp { +public interface RollUpTrait { /** - * construct the roll up function with custom param + * Construct the roll up function with custom param */ Function constructRollUp(Expression param, Expression... varParams); + + /** + * identify the function itself can be rolled up + * Such as Sum can be rolled up directly, but BitmapUnionCount can not + */ + boolean canRollUp(); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Sum.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Sum.java index 0b00536d6a8826..e55f926ae4d3ca 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Sum.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Sum.java @@ -47,7 +47,7 @@ */ public class Sum extends NullableAggregateFunction implements UnaryExpression, ExplicitlyCastableSignature, ComputePrecisionForSum, SupportWindowAnalytic, - CouldRollUp { + RollUpTrait { public static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(BigIntType.INSTANCE).args(BooleanType.INSTANCE), @@ -129,4 +129,9 @@ public FunctionSignature searchSignature(List signatures) { public Function constructRollUp(Expression param, Expression... varParams) { return new Sum(this.distinct, param); } + + @Override + public boolean canRollUp() { + return true; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Sum0.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Sum0.java index b25dd5fe60e786..1f63c53dabc004 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Sum0.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Sum0.java @@ -49,7 +49,7 @@ */ public class Sum0 extends AggregateFunction implements UnaryExpression, AlwaysNotNullable, ExplicitlyCastableSignature, ComputePrecisionForSum, - SupportWindowAnalytic, CouldRollUp { + SupportWindowAnalytic, RollUpTrait { public static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(BigIntType.INSTANCE).args(BooleanType.INSTANCE), @@ -122,4 +122,9 @@ public FunctionSignature searchSignature(List signatures) { public Function constructRollUp(Expression param, Expression... varParams) { return new Sum0(this.distinct, param); } + + @Override + public boolean canRollUp() { + return true; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/Combinator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/Combinator.java new file mode 100644 index 00000000000000..59b06b8b2f904d --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/Combinator.java @@ -0,0 +1,29 @@ +// 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.trees.expressions.functions.combinator; + +import org.apache.doris.nereids.trees.expressions.functions.ExpressionTrait; +import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; + +/** + * Combinator interface which identify the expression is Combinator + */ +public interface Combinator extends ExpressionTrait { + + AggregateFunction getNestedFunction(); +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/ForEachCombinator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/ForEachCombinator.java index ecaf32479cfe25..c2a50a328a759c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/ForEachCombinator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/ForEachCombinator.java @@ -37,7 +37,7 @@ * combinator foreach */ public class ForEachCombinator extends AggregateFunction - implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNullable { + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNullable, Combinator { private final AggregateFunction nested; @@ -79,6 +79,7 @@ public DataType getDataType() { return ArrayType.of(nested.getDataType(), nested.nullable()); } + @Override public AggregateFunction getNestedFunction() { return nested; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/MergeCombinator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/MergeCombinator.java index a9b2d13d0d5319..318390ce05a655 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/MergeCombinator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/MergeCombinator.java @@ -17,12 +17,19 @@ package org.apache.doris.nereids.trees.expressions.functions.combinator; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.FunctionRegistry; import org.apache.doris.catalog.FunctionSignature; +import org.apache.doris.common.Pair; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.AggCombinerFunctionBuilder; +import org.apache.doris.nereids.trees.expressions.functions.BoundFunction; import org.apache.doris.nereids.trees.expressions.functions.ComputeNullable; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.functions.Function; +import org.apache.doris.nereids.trees.expressions.functions.FunctionBuilder; import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; +import org.apache.doris.nereids.trees.expressions.functions.agg.RollUpTrait; import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.AggStateType; @@ -37,7 +44,7 @@ * AggState combinator merge */ public class MergeCombinator extends AggregateFunction - implements UnaryExpression, ExplicitlyCastableSignature, ComputeNullable { + implements UnaryExpression, ExplicitlyCastableSignature, ComputeNullable, Combinator, RollUpTrait { private final AggregateFunction nested; private final AggStateType inputType; @@ -71,6 +78,7 @@ public DataType getDataType() { return nested.getDataType(); } + @Override public AggregateFunction getNestedFunction() { return nested; } @@ -84,4 +92,18 @@ public AggregateFunction withDistinctAndChildren(boolean distinct, List targetExpressionPair = functionBuilder.build(getName(), + param); + return (Function) targetExpressionPair.key(); + } + + @Override + public boolean canRollUp() { + return false; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/StateCombinator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/StateCombinator.java index 877824822c51ec..99f824b3238dd6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/StateCombinator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/StateCombinator.java @@ -17,12 +17,19 @@ package org.apache.doris.nereids.trees.expressions.functions.combinator; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.FunctionRegistry; import org.apache.doris.catalog.FunctionSignature; +import org.apache.doris.common.Pair; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.AggCombinerFunctionBuilder; import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable; +import org.apache.doris.nereids.trees.expressions.functions.BoundFunction; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.functions.Function; +import org.apache.doris.nereids.trees.expressions.functions.FunctionBuilder; import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; +import org.apache.doris.nereids.trees.expressions.functions.agg.RollUpTrait; import org.apache.doris.nereids.trees.expressions.functions.scalar.ScalarFunction; import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; @@ -38,7 +45,7 @@ * AggState combinator state */ public class StateCombinator extends ScalarFunction - implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable { + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, Combinator, RollUpTrait { private final AggregateFunction nested; private final AggStateType returnType; @@ -83,7 +90,25 @@ public DataType getDataType() { return returnType; } + @Override public AggregateFunction getNestedFunction() { return nested; } + + @Override + public Function constructRollUp(Expression param, Expression... varParams) { + String nestedName = AggCombinerFunctionBuilder.getNestedName(getName()); + FunctionRegistry functionRegistry = Env.getCurrentEnv().getFunctionRegistry(); + // state combinator roll up result should be union combinator + String combinatorName = nestedName + AggCombinerFunctionBuilder.UNION_SUFFIX; + FunctionBuilder functionBuilder = functionRegistry.findFunctionBuilder(combinatorName, param); + Pair targetExpressionPair = + functionBuilder.build(combinatorName, param); + return (Function) targetExpressionPair.key(); + } + + @Override + public boolean canRollUp() { + return true; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/UnionCombinator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/UnionCombinator.java index e1138dd4851a8a..5d7bbb05e03058 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/UnionCombinator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/UnionCombinator.java @@ -17,12 +17,19 @@ package org.apache.doris.nereids.trees.expressions.functions.combinator; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.FunctionRegistry; import org.apache.doris.catalog.FunctionSignature; +import org.apache.doris.common.Pair; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.AggCombinerFunctionBuilder; import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable; +import org.apache.doris.nereids.trees.expressions.functions.BoundFunction; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.functions.Function; +import org.apache.doris.nereids.trees.expressions.functions.FunctionBuilder; import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; +import org.apache.doris.nereids.trees.expressions.functions.agg.RollUpTrait; import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.AggStateType; @@ -37,7 +44,7 @@ * AggState combinator union */ public class UnionCombinator extends AggregateFunction - implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable { + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, Combinator, RollUpTrait { private final AggregateFunction nested; private final AggStateType inputType; @@ -71,6 +78,7 @@ public DataType getDataType() { return inputType; } + @Override public AggregateFunction getNestedFunction() { return nested; } @@ -79,4 +87,18 @@ public AggregateFunction getNestedFunction() { public AggregateFunction withDistinctAndChildren(boolean distinct, List children) { throw new UnsupportedOperationException("Unimplemented method 'withDistinctAndChildren'"); } + + @Override + public Function constructRollUp(Expression param, Expression... varParams) { + FunctionRegistry functionRegistry = Env.getCurrentEnv().getFunctionRegistry(); + FunctionBuilder functionBuilder = functionRegistry.findFunctionBuilder(getName(), param); + Pair targetExpressionPair = functionBuilder.build(getName(), + param); + return (Function) targetExpressionPair.key(); + } + + @Override + public boolean canRollUp() { + return true; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HllCardinality.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HllCardinality.java index f22fe7dfcdcbf2..588a0f1daec1df 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HllCardinality.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HllCardinality.java @@ -22,9 +22,9 @@ import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; import org.apache.doris.nereids.trees.expressions.functions.Function; -import org.apache.doris.nereids.trees.expressions.functions.agg.CouldRollUp; import org.apache.doris.nereids.trees.expressions.functions.agg.HllFunction; import org.apache.doris.nereids.trees.expressions.functions.agg.HllUnionAgg; +import org.apache.doris.nereids.trees.expressions.functions.agg.RollUpTrait; import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.BigIntType; @@ -39,7 +39,7 @@ * ScalarFunction 'hll_cardinality'. This class is generated by GenerateFunction. */ public class HllCardinality extends ScalarFunction - implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, HllFunction, CouldRollUp { + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNotNullable, HllFunction, RollUpTrait { public static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(BigIntType.INSTANCE).args(HllType.INSTANCE) @@ -75,4 +75,9 @@ public R accept(ExpressionVisitor visitor, C context) { public Function constructRollUp(Expression param, Expression... varParams) { return new HllUnionAgg(param); } + + @Override + public boolean canRollUp() { + return false; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateMTMVInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateMTMVInfo.java index b64ad88e15481b..6b008ba2565cab 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateMTMVInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateMTMVInfo.java @@ -24,6 +24,7 @@ import org.apache.doris.analysis.PartitionDesc; import org.apache.doris.analysis.RangePartitionDesc; import org.apache.doris.analysis.TableName; +import org.apache.doris.catalog.AggregateType; import org.apache.doris.catalog.Column; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.KeysType; @@ -59,6 +60,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalSink; import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias; import org.apache.doris.nereids.trees.plans.visitor.NondeterministicFunctionCollector; +import org.apache.doris.nereids.types.AggStateType; import org.apache.doris.nereids.util.Utils; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.SessionVariable; @@ -74,6 +76,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; @@ -317,8 +320,14 @@ private void getColumns(Plan plan) { } else { colNames.add(colName); } + // If datatype is AggStateType, AggregateType should be generic, or column definition check will fail columns.add(new ColumnDefinition( - colName, slots.get(i).getDataType(), slots.get(i).nullable(), + colName, + slots.get(i).getDataType(), + false, + slots.get(i).getDataType() instanceof AggStateType ? AggregateType.GENERIC : null, + slots.get(i).nullable(), + Optional.empty(), CollectionUtils.isEmpty(simpleColumnDefinitions) ? null : simpleColumnDefinitions.get(i).getComment())); } diff --git a/regression-test/data/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.out b/regression-test/data/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.out index cebddff9835c8a..48f8c25fbf4d08 100644 --- a/regression-test/data/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.out +++ b/regression-test/data/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.out @@ -355,3 +355,35 @@ 2023-12-11 1 2023-12-12 2 +-- !query33_0_before -- +o 3 9 o,o,o,o,o,o 4.666666666666667 mi 6 2 +o 4 2 o,o 4.0 yy 2 1 + +-- !query33_0_after -- +o 3 9 o,o,o,o,o,o 4.666666666666667 mi 6 2 +o 4 2 o,o 4.0 yy 2 1 + +-- !query33_1_before -- +o 3 9 o,o,o,o,o,o 4.666666666666667 mi 6 2 +o 4 2 o,o 4.0 yy 2 1 + +-- !query33_1_after -- +o 3 9 o,o,o,o,o,o 4.666666666666667 mi 6 2 +o 4 2 o,o 4.0 yy 2 1 + +-- !query35_0_before -- +o 3 9 o,o,o,o,o,o 4.666666666666667 mi 6 2 +o 4 2 o,o 4.0 yy 2 1 + +-- !query35_0_after -- +o 3 9 o,o,o,o,o,o 4.666666666666667 mi 6 2 +o 4 2 o,o 4.0 yy 2 1 + +-- !query36_0_before -- +o 3 9 o,o,o,o,o,o 4.666666666666667 mi 6 2 +o 4 2 o,o 4.0 yy 2 1 + +-- !query36_0_after -- +o 3 9 o,o,o,o,o,o 4.666666666666667 mi 6 2 +o 4 2 o,o 4.0 yy 2 1 + diff --git a/regression-test/data/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.out b/regression-test/data/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.out index 7901a62ef638a4..3b9c3a1219ea15 100644 --- a/regression-test/data/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.out +++ b/regression-test/data/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.out @@ -261,3 +261,57 @@ d c 17.00 2 4 4 68 100.0000 36.5000 6 1 0 22.0000 57.2000 +-- !query22_0_before -- +2023-12-08 2 3 1 +2023-12-09 4 3 1 +2023-12-10 2 4 1 +2023-12-11 3 3 2 +2023-12-12 2 3 2 + +-- !query22_0_after -- +2023-12-08 2 3 1 +2023-12-09 4 3 1 +2023-12-10 2 4 1 +2023-12-11 3 3 2 +2023-12-12 2 3 2 + +-- !query23_0_before -- +a 3 3 a,a,a 4.0 yy 3 1 +a 4 2 a,a 4.0 yy 2 1 +c 3 6 c,c,c 5.333333333333333 mi 3 2 + +-- !query23_0_after -- +a 3 3 a,a,a 4.0 yy 3 1 +a 4 2 a,a 4.0 yy 2 1 +c 3 6 c,c,c 5.333333333333333 mi 3 2 + +-- !query23_1_before -- +a 3 3 a,a,a 4.0 yy 3 1 +a 4 2 a,a 4.0 yy 2 1 +c 3 6 c,c,c 5.333333333333333 mi 3 2 + +-- !query23_1_after -- +a 3 3 a,a,a 4.0 yy 3 1 +a 4 2 a,a 4.0 yy 2 1 +c 3 6 c,c,c 5.333333333333333 mi 3 2 + +-- !query25_0_before -- +a 3 3 a,a,a 4.0 yy 3 1 +a 4 2 a,a 4.0 yy 2 1 +c 3 6 c,c,c 5.333333333333333 mi 3 2 + +-- !query25_0_after -- +a 3 3 a,a,a 4.0 yy 3 1 +a 4 2 a,a 4.0 yy 2 1 +c 3 6 c,c,c 5.333333333333333 mi 3 2 + +-- !query26_0_before -- +a 3 3 a,a,a 4.0 yy 3 1 +a 4 2 a,a 4.0 yy 2 1 +c 3 6 c,c,c 5.333333333333333 mi 3 2 + +-- !query26_0_after -- +a 3 3 a,a,a 4.0 yy 3 1 +a 4 2 a,a 4.0 yy 2 1 +c 3 6 c,c,c 5.333333333333333 mi 3 2 + diff --git a/regression-test/suites/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.groovy b/regression-test/suites/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.groovy index 8664607be40433..431b74ab7455ec 100644 --- a/regression-test/suites/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.groovy +++ b/regression-test/suites/nereids_rules_p0/mv/agg_with_roll_up/aggregate_with_roll_up.groovy @@ -1284,7 +1284,7 @@ suite("aggregate_with_roll_up") { avg(case when l_partkey in (2, 3, 4) then l_discount + o_totalprice + part_supp_a.qty_sum else 50 end) from lineitem left join orders on l_orderkey = o_orderkey - left join + left join (select ps_partkey, ps_suppkey, sum(ps_availqty) qty_sum, max(ps_availqty) qty_max, min(ps_availqty) qty_min, avg(ps_supplycost) cost_avg @@ -1303,7 +1303,7 @@ suite("aggregate_with_roll_up") { avg(case when l_partkey in (2, 3, 4) then l_discount + o_totalprice + part_supp_a.qty_sum else 50 end) from lineitem left join orders on l_orderkey = o_orderkey - left join + left join (select ps_partkey, ps_suppkey, sum(ps_availqty) qty_sum, max(ps_availqty) qty_max, min(ps_availqty) qty_min, avg(ps_supplycost) cost_avg @@ -1320,39 +1320,39 @@ suite("aggregate_with_roll_up") { // should rewrite fail, because the part of query is join but mv is aggregate def mv31_0 = """ - select - o_orderdate, - o_shippriority, - o_comment, - l_orderkey, - o_orderkey, - count(*) - from - orders + select + o_orderdate, + o_shippriority, + o_comment, + l_orderkey, + o_orderkey, + count(*) + from + orders left join lineitem on l_orderkey = o_orderkey - group by o_orderdate, - o_shippriority, - o_comment, - l_orderkey, + group by o_orderdate, + o_shippriority, + o_comment, + l_orderkey, o_orderkey; """ def query31_0 = """ - select - o_orderdate, - o_shippriority, - o_comment, - l_orderkey, - ps_partkey, - count(*) - from - orders left + select + o_orderdate, + o_shippriority, + o_comment, + l_orderkey, + ps_partkey, + count(*) + from + orders left join lineitem on l_orderkey = o_orderkey left join partsupp on ps_partkey = l_orderkey group by - o_orderdate, - o_shippriority, - o_comment, - l_orderkey, + o_orderdate, + o_shippriority, + o_comment, + l_orderkey, ps_partkey; """ order_qt_query31_0_before "${query31_0}" @@ -1362,22 +1362,22 @@ suite("aggregate_with_roll_up") { // should rewrite fail, because the part of query is join but mv is aggregate def mv32_0 = """ - select - o_orderdate, - count(*) - from - orders - group by + select + o_orderdate, + count(*) + from + orders + group by o_orderdate; """ def query32_0 = """ - select - o_orderdate, - count(*) - from - orders - group by - o_orderdate, + select + o_orderdate, + count(*) + from + orders + group by + o_orderdate, o_shippriority; """ order_qt_query32_0_before "${query32_0}" @@ -1385,4 +1385,264 @@ suite("aggregate_with_roll_up") { order_qt_query32_0_after "${query32_0}" sql """ DROP MATERIALIZED VIEW IF EXISTS mv32_0""" + // test combinator aggregate function rewrite + sql """set enable_agg_state=true""" + // query has no combinator and mv has combinator + // mv is union + def mv33_0 = """ + select + o_orderstatus, + l_partkey, + l_suppkey, + sum_union(sum_state(o_shippriority)), + group_concat_union(group_concat_state(o_orderstatus)), + avg_union(avg_state(l_linenumber)), + max_by_union(max_by_state(O_COMMENT,o_totalprice)), + count_union(count_state(l_orderkey)), + multi_distinct_count_union(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_partkey, + l_suppkey; + """ + def query33_0 = """ + select + o_orderstatus, + l_suppkey, + sum(o_shippriority), + group_concat(o_orderstatus), + avg(l_linenumber), + max_by(O_COMMENT,o_totalprice), + count(l_orderkey), + multi_distinct_count(l_shipmode) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_suppkey; + """ + order_qt_query33_0_before "${query33_0}" + check_mv_rewrite_success(db, mv33_0, query33_0, "mv33_0") + order_qt_query33_0_after "${query33_0}" + sql """ DROP MATERIALIZED VIEW IF EXISTS mv33_0""" + + + // mv is merge + def mv33_1 = """ + select + o_orderstatus, + l_partkey, + l_suppkey, + sum_merge(sum_state(o_shippriority)), + group_concat_merge(group_concat_state(o_orderstatus)), + avg_merge(avg_state(l_linenumber)), + max_by_merge(max_by_state(O_COMMENT,o_totalprice)), + count_merge(count_state(l_orderkey)), + multi_distinct_count_merge(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_partkey, + l_suppkey; + """ + def query33_1 = """ + select + o_orderstatus, + l_suppkey, + sum(o_shippriority), + group_concat(o_orderstatus), + avg(l_linenumber), + max_by(O_COMMENT,o_totalprice), + count(l_orderkey), + multi_distinct_count(l_shipmode) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_suppkey + order by o_orderstatus; + """ + order_qt_query33_1_before "${query33_1}" + check_mv_rewrite_fail(db, mv33_1, query33_1, "mv33_1") + order_qt_query33_1_after "${query33_1}" + sql """ DROP MATERIALIZED VIEW IF EXISTS mv33_1""" + + + + // both query and mv are combinator + // mv is union, query is union + def mv34_0 = """ + select + o_orderstatus, + l_partkey, + l_suppkey, + sum_union(sum_state(o_shippriority)), + group_concat_union(group_concat_state(o_orderstatus)), + avg_union(avg_state(l_linenumber)), + max_by_union(max_by_state(O_COMMENT,o_totalprice)), + count_union(count_state(l_orderkey)), + multi_distinct_count_union(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_partkey, + l_suppkey; + """ + def query34_0 = """ + select + o_orderstatus, + l_suppkey, + sum_union(sum_state(o_shippriority)), + group_concat_union(group_concat_state(o_orderstatus)), + avg_union(avg_state(l_linenumber)), + max_by_union(max_by_state(O_COMMENT,o_totalprice)), + count_union(count_state(l_orderkey)), + multi_distinct_count_union(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_suppkey; + """ + check_mv_rewrite_success(db, mv34_0, query34_0, "mv34_0") + sql """ DROP MATERIALIZED VIEW IF EXISTS mv34_0""" + + + // mv is union, query is merge + def mv35_0 = """ + select + o_orderstatus, + l_partkey, + l_suppkey, + sum_union(sum_state(o_shippriority)), + group_concat_union(group_concat_state(o_orderstatus)), + avg_union(avg_state(l_linenumber)), + max_by_union(max_by_state(O_COMMENT,o_totalprice)), + count_union(count_state(l_orderkey)), + multi_distinct_count_union(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_partkey, + l_suppkey; + """ + def query35_0 = """ + select + o_orderstatus, + l_suppkey, + sum_merge(sum_state(o_shippriority)), + group_concat_merge(group_concat_state(o_orderstatus)), + avg_merge(avg_state(l_linenumber)), + max_by_merge(max_by_state(O_COMMENT,o_totalprice)), + count_merge(count_state(l_orderkey)), + multi_distinct_count_merge(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_suppkey + order by o_orderstatus; + """ + order_qt_query35_0_before "${query35_0}" + check_mv_rewrite_success(db, mv35_0, query35_0, "mv35_0") + order_qt_query35_0_after "${query35_0}" + sql """ DROP MATERIALIZED VIEW IF EXISTS mv35_0""" + + + // mv is merge, query is merge + def mv36_0 = """ + select + o_orderstatus, + l_partkey, + l_suppkey, + sum_merge(sum_state(o_shippriority)), + group_concat_merge(group_concat_state(o_orderstatus)), + avg_merge(avg_state(l_linenumber)), + max_by_merge(max_by_state(O_COMMENT,o_totalprice)), + count_merge(count_state(l_orderkey)), + multi_distinct_count_merge(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_partkey, + l_suppkey; + """ + def query36_0 = """ + select + o_orderstatus, + l_suppkey, + sum_merge(sum_state(o_shippriority)), + group_concat_merge(group_concat_state(o_orderstatus)), + avg_merge(avg_state(l_linenumber)), + max_by_merge(max_by_state(O_COMMENT,o_totalprice)), + count_merge(count_state(l_orderkey)), + multi_distinct_count_merge(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_suppkey + order by o_orderstatus; + """ + order_qt_query36_0_before "${query36_0}" + check_mv_rewrite_fail(db, mv36_0, query36_0, "mv36_0") + order_qt_query36_0_after "${query36_0}" + sql """ DROP MATERIALIZED VIEW IF EXISTS mv36_0""" + + + // mv is merge, query is union + def mv37_0 = """ + select + o_orderstatus, + l_partkey, + l_suppkey, + sum_merge(sum_state(o_shippriority)), + group_concat_merge(group_concat_state(o_orderstatus)), + avg_merge(avg_state(l_linenumber)), + max_by_merge(max_by_state(O_COMMENT,o_totalprice)), + count_merge(count_state(l_orderkey)), + multi_distinct_count_merge(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_partkey, + l_suppkey; + """ + def query37_0 = """ + select + o_orderstatus, + l_suppkey, + sum_union(sum_state(o_shippriority)), + group_concat_union(group_concat_state(o_orderstatus)), + avg_union(avg_state(l_linenumber)), + max_by_union(max_by_state(O_COMMENT,o_totalprice)), + count_union(count_state(l_orderkey)), + multi_distinct_count_union(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderstatus, + l_suppkey; + """ + check_mv_rewrite_fail(db, mv37_0, query37_0, "mv37_0") + sql """ DROP MATERIALIZED VIEW IF EXISTS mv37_0""" } diff --git a/regression-test/suites/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.groovy b/regression-test/suites/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.groovy index 95ea99bc190670..b0e82c73d5f449 100644 --- a/regression-test/suites/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.groovy +++ b/regression-test/suites/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.groovy @@ -24,6 +24,7 @@ suite("aggregate_without_roll_up") { sql "SET enable_fallback_to_original_planner=false" sql "SET enable_materialized_view_rewrite=true" sql "SET enable_nereids_timeout = false" + sql "SET enable_agg_state = true" sql """ drop table if exists orders @@ -1044,7 +1045,7 @@ suite("aggregate_without_roll_up") { avg(case when l_partkey in (2, 3, 4) then l_discount + o_totalprice + part_supp_a.qty_sum else 50 end) from lineitem left join orders on l_orderkey = o_orderkey - left join + left join (select ps_partkey, ps_suppkey, sum(ps_availqty) qty_sum, max(ps_availqty) qty_max, min(ps_availqty) qty_min, avg(ps_supplycost) cost_avg @@ -1064,7 +1065,7 @@ suite("aggregate_without_roll_up") { avg(case when l_partkey in (2, 3, 4) then l_discount + o_totalprice + part_supp_a.qty_sum else 50 end) from lineitem left join orders on l_orderkey = o_orderkey - left join + left join (select ps_partkey, ps_suppkey, sum(ps_availqty) qty_sum, max(ps_availqty) qty_max, min(ps_availqty) qty_min, avg(ps_supplycost) cost_avg @@ -1078,4 +1079,289 @@ suite("aggregate_without_roll_up") { check_mv_rewrite_fail(db, mv21_2, query21_2, "mv21_2") order_qt_query21_2_after "${query21_2}" sql """ DROP MATERIALIZED VIEW IF EXISTS mv21_2""" + + + def mv22_0 = """ + select + o_orderdate, + l_partkey, + l_suppkey, + max_union(max_state(o_shippriority)) + from lineitem + left join orders t2 + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderdate, + l_partkey, + l_suppkey; + """ + def query22_0 = """ + select + o_orderdate, + l_partkey, + l_suppkey, + max(o_shippriority) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderdate, + l_partkey, + l_suppkey; + """ + order_qt_query22_0_before "${query22_0}" + check_mv_rewrite_success(db, mv22_0, query22_0, "mv22_0") + order_qt_query22_0_after "${query22_0}" + sql """ DROP MATERIALIZED VIEW IF EXISTS mv22_0""" + + // test combinator aggregate function rewrite + sql """set enable_agg_state=true""" + // query has no combinator and mv has combinator + // mv is union + def mv23_0 = """ + select + o_orderpriority, + l_suppkey, + sum_union(sum_state(o_shippriority)), + group_concat_union(group_concat_state(o_orderpriority)), + avg_union(avg_state(l_linenumber)), + max_by_union(max_by_state(O_COMMENT,o_totalprice)), + count_union(count_state(l_orderkey)), + multi_distinct_count_union(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey; + """ + def query23_0 = """ + select + o_orderpriority, + l_suppkey, + sum(o_shippriority), + group_concat(o_orderpriority), + avg(l_linenumber), + max_by(O_COMMENT,o_totalprice), + count(l_orderkey), + multi_distinct_count(l_shipmode) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey + order by o_orderpriority; + """ + order_qt_query23_0_before "${query23_0}" + check_mv_rewrite_success(db, mv23_0, query23_0, "mv23_0") + order_qt_query23_0_after "${query23_0}" + sql """ DROP MATERIALIZED VIEW IF EXISTS mv23_0""" + + + // mv is merge + def mv23_1 = """ + select + o_orderpriority, + l_suppkey, + sum_merge(sum_state(o_shippriority)), + group_concat_merge(group_concat_state(o_orderpriority)), + avg_merge(avg_state(l_linenumber)), + max_by_merge(max_by_state(O_COMMENT,o_totalprice)), + count_merge(count_state(l_orderkey)), + multi_distinct_count_merge(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey; + """ + def query23_1 = """ + select + o_orderpriority, + l_suppkey, + sum(o_shippriority), + group_concat(o_orderpriority), + avg(l_linenumber), + max_by(O_COMMENT,o_totalprice), + count(l_orderkey), + multi_distinct_count(l_shipmode) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey + order by o_orderpriority; + """ + order_qt_query23_1_before "${query23_1}" + // not supported, this usage is rare + check_mv_rewrite_fail(db, mv23_1, query23_1, "mv23_1") + order_qt_query23_1_after "${query23_1}" + sql """ DROP MATERIALIZED VIEW IF EXISTS mv23_1""" + + + + // both query and mv are combinator + // mv is union, query is union + def mv24_0 = """ + select + o_orderpriority, + l_suppkey, + sum_union(sum_state(o_shippriority)), + group_concat_union(group_concat_state(o_orderpriority)), + avg_union(avg_state(l_linenumber)), + max_by_union(max_by_state(O_COMMENT,o_totalprice)), + count_union(count_state(l_orderkey)), + multi_distinct_count_union(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey; + """ + def query24_0 = """ + select + o_orderpriority, + l_suppkey, + sum_union(sum_state(o_shippriority)), + group_concat_union(group_concat_state(o_orderpriority)), + avg_union(avg_state(l_linenumber)), + max_by_union(max_by_state(O_COMMENT,o_totalprice)), + count_union(count_state(l_orderkey)), + multi_distinct_count_union(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey; + """ + check_mv_rewrite_success(db, mv24_0, query24_0, "mv24_0") + sql """ DROP MATERIALIZED VIEW IF EXISTS mv24_0""" + + + // mv is union, query is merge + def mv25_0 = """ + select + o_orderpriority, + l_suppkey, + sum_union(sum_state(o_shippriority)), + group_concat_union(group_concat_state(o_orderpriority)), + avg_union(avg_state(l_linenumber)), + max_by_union(max_by_state(O_COMMENT,o_totalprice)), + count_union(count_state(l_orderkey)), + multi_distinct_count_union(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey; + """ + def query25_0 = """ + select + o_orderpriority, + l_suppkey, + sum_merge(sum_state(o_shippriority)), + group_concat_merge(group_concat_state(o_orderpriority)), + avg_merge(avg_state(l_linenumber)), + max_by_merge(max_by_state(O_COMMENT,o_totalprice)), + count_merge(count_state(l_orderkey)), + multi_distinct_count_merge(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey + order by o_orderpriority; + """ + order_qt_query25_0_before "${query25_0}" + check_mv_rewrite_success(db, mv25_0, query25_0, "mv25_0") + order_qt_query25_0_after "${query25_0}" + sql """ DROP MATERIALIZED VIEW IF EXISTS mv25_0""" + + + // mv is merge, query is merge + def mv26_0 = """ + select + o_orderpriority, + l_suppkey, + sum_merge(sum_state(o_shippriority)), + group_concat_merge(group_concat_state(o_orderpriority)), + avg_merge(avg_state(l_linenumber)), + max_by_merge(max_by_state(O_COMMENT,o_totalprice)), + count_merge(count_state(l_orderkey)), + multi_distinct_count_merge(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey; + """ + def query26_0 = """ + select + o_orderpriority, + l_suppkey, + sum_merge(sum_state(o_shippriority)), + group_concat_merge(group_concat_state(o_orderpriority)), + avg_merge(avg_state(l_linenumber)), + max_by_merge(max_by_state(O_COMMENT,o_totalprice)), + count_merge(count_state(l_orderkey)), + multi_distinct_count_merge(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey + order by o_orderpriority; + """ + order_qt_query26_0_before "${query26_0}" + check_mv_rewrite_success(db, mv26_0, query26_0, "mv26_0") + order_qt_query26_0_after "${query26_0}" + sql """ DROP MATERIALIZED VIEW IF EXISTS mv26_0""" + + + // mv is merge, query is union + def mv27_0 = """ + select + o_orderpriority, + l_suppkey, + sum_merge(sum_state(o_shippriority)), + group_concat_merge(group_concat_state(o_orderpriority)), + avg_merge(avg_state(l_linenumber)), + max_by_merge(max_by_state(O_COMMENT,o_totalprice)), + count_merge(count_state(l_orderkey)), + multi_distinct_count_merge(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey; + """ + def query27_0 = """ + select + o_orderpriority, + l_suppkey, + sum_union(sum_state(o_shippriority)), + group_concat_union(group_concat_state(o_orderpriority)), + avg_union(avg_state(l_linenumber)), + max_by_union(max_by_state(O_COMMENT,o_totalprice)), + count_union(count_state(l_orderkey)), + multi_distinct_count_union(multi_distinct_count_state(l_shipmode)) + from lineitem + left join orders + on lineitem.l_orderkey = o_orderkey and l_shipdate = o_orderdate + group by + o_orderpriority, + l_suppkey; + """ + check_mv_rewrite_fail(db, mv27_0, query27_0, "mv27_0") + sql """ DROP MATERIALIZED VIEW IF EXISTS mv27_0""" }