From 5b462194d1614534571dc3e161f8e14536c175ad Mon Sep 17 00:00:00 2001 From: Pxl Date: Thu, 25 Jan 2024 10:06:37 +0800 Subject: [PATCH] [Feature](materialized-view) support rewrite case when to if on legacy planner to make mv work (#30320) support rewrite case when to if on legacy planner to make mv work --- .../org/apache/doris/analysis/Analyzer.java | 2 + .../org/apache/doris/analysis/CaseExpr.java | 14 ++--- .../apache/doris/rewrite/CaseWhenToIf.java | 52 +++++++++++++++++++ .../mv_p0/test_casewhen/test_casewhen.out | 11 ++++ .../mv_p0/test_casewhen/test_casewhen.groovy | 41 +++++++++++++++ 5 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/rewrite/CaseWhenToIf.java create mode 100644 regression-test/data/mv_p0/test_casewhen/test_casewhen.out create mode 100644 regression-test/suites/mv_p0/test_casewhen/test_casewhen.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java index b41666820b..2e7d7d729a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java @@ -48,6 +48,7 @@ import org.apache.doris.planner.RuntimeFilter; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.SessionVariable; import org.apache.doris.rewrite.BetweenToCompoundRule; +import org.apache.doris.rewrite.CaseWhenToIf; import org.apache.doris.rewrite.CompoundPredicateWriteRule; import org.apache.doris.rewrite.ElementAtToSlotRefRule; import org.apache.doris.rewrite.EliminateUnnecessaryFunctions; @@ -460,6 +461,7 @@ public class Analyzer { rules.add(EliminateUnnecessaryFunctions.INSTANCE); rules.add(ElementAtToSlotRefRule.INSTANCE); rules.add(FunctionAlias.INSTANCE); + rules.add(CaseWhenToIf.INSTANCE); List onceRules = Lists.newArrayList(); onceRules.add(ExtractCommonFactorsRule.INSTANCE); onceRules.add(InferFiltersRule.INSTANCE); diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CaseExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CaseExpr.java index 3d3070ec3c..51feb0bed7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CaseExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CaseExpr.java @@ -352,11 +352,7 @@ public class CaseExpr extends Expr { } if (caseExpr instanceof NullLiteral) { - if (expr.hasElseExpr) { - return expr.getChild(expr.getChildren().size() - 1); - } else { - return new NullLiteral(); - } + return expr.getFinalResult(); } if (expr.hasElseExpr) { @@ -402,8 +398,12 @@ public class CaseExpr extends Expr { } } - if (expr.hasElseExpr) { - return expr.getChild(expr.getChildren().size() - 1); + return expr.getFinalResult(); + } + + public Expr getFinalResult() { + if (hasElseExpr) { + return getChild(getChildren().size() - 1); } else { return new NullLiteral(); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/rewrite/CaseWhenToIf.java b/fe/fe-core/src/main/java/org/apache/doris/rewrite/CaseWhenToIf.java new file mode 100644 index 0000000000..51c2e9f1bd --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/rewrite/CaseWhenToIf.java @@ -0,0 +1,52 @@ +// 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.rewrite; + +import org.apache.doris.analysis.Analyzer; +import org.apache.doris.analysis.CaseExpr; +import org.apache.doris.analysis.Expr; +import org.apache.doris.analysis.FunctionCallExpr; +import org.apache.doris.common.AnalysisException; + +import com.google.common.collect.Lists; + +import java.util.ArrayList; + +/** + * Change function 'case when' to 'if', same with + * nereids/rules/expression/rules/CaseWhenToIf.java + */ +public final class CaseWhenToIf implements ExprRewriteRule { + public static ExprRewriteRule INSTANCE = new CaseWhenToIf(); + + @Override + public Expr apply(Expr expr, Analyzer analyzer, ExprRewriter.ClauseType clauseType) throws AnalysisException { + if (!(expr instanceof CaseExpr)) { + return expr; + } + CaseExpr caseWhen = (CaseExpr) expr; + if (caseWhen.getConditionExprs().size() == 1) { + ArrayList ifArgs = Lists.newArrayList(); + ifArgs.add(caseWhen.getConditionExprs().get(0)); + ifArgs.add(caseWhen.getReturnExprs().get(0)); + ifArgs.add(caseWhen.getFinalResult()); + return new FunctionCallExpr("if", ifArgs); + } + return expr; + } +} diff --git a/regression-test/data/mv_p0/test_casewhen/test_casewhen.out b/regression-test/data/mv_p0/test_casewhen/test_casewhen.out new file mode 100644 index 0000000000..fdf4432d53 --- /dev/null +++ b/regression-test/data/mv_p0/test_casewhen/test_casewhen.out @@ -0,0 +1,11 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select_star -- +1 1 1 2020-02-02 1 +1 1 1 2020-02-02 11 +1 1 1 2020-02-02 1 +1 2 2 2020-02-02 1 + +-- !select_mv -- +1 5 +2 2 + diff --git a/regression-test/suites/mv_p0/test_casewhen/test_casewhen.groovy b/regression-test/suites/mv_p0/test_casewhen/test_casewhen.groovy new file mode 100644 index 0000000000..7132b3394a --- /dev/null +++ b/regression-test/suites/mv_p0/test_casewhen/test_casewhen.groovy @@ -0,0 +1,41 @@ +// 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. + +import org.codehaus.groovy.runtime.IOGroovyMethods + +suite ("test_casewhen") { + + sql """ DROP TABLE IF EXISTS sales_records; """ + + sql """ + create table sales_records(record_id int, seller_id int, store_id int, sale_date date, sale_amt bigint) distributed by hash(record_id) properties("replication_num" = "1"); + """ + + sql """insert into sales_records values(1,1,1,"2020-02-02",11),(1,1,1,"2020-02-02",1);""" + + createMV ("create materialized view store_amt as select store_id, sum(case when sale_amt>10 then 1 else 2 end) from sales_records group by store_id;") + + sql """insert into sales_records values(1,1,1,"2020-02-02",1),(1,2,2,"2020-02-02",1);""" + + qt_select_star "select * from sales_records order by 1,2;" + + explain { + sql("select store_id, sum(case when sale_amt>10 then 1 else 2 end) from sales_records group by store_id order by 1;") + contains "(store_amt)" + } + qt_select_mv "select store_id, sum(case when sale_amt>10 then 1 else 2 end) from sales_records group by store_id order by 1;" +}