This is an automated email from the ASF dual-hosted git repository. morningman pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new a5a50726bf [Ehancement](planner) Rewrite implicit cast to the predicates (#10920) a5a50726bf is described below commit a5a50726bff1f704dd626fd1bccc95bd40ce98dd Author: Kikyou1997 <33112463+kikyou1...@users.noreply.github.com> AuthorDate: Wed Jul 20 12:28:29 2022 +0800 [Ehancement](planner) Rewrite implicit cast to the predicates (#10920) During the analysis of BinaryPredicate, it will generate a CastExpr if the slot implicitly in the below case: SELECT * FROM t1 WHERE t1.col1 = '1'; col1 is integer column. This will prevent the binary predicate from pushing down to OlapScan which would impact the performance. --- .../java/org/apache/doris/analysis/Analyzer.java | 2 + .../doris/rewrite/RewriteImplicitCastRule.java | 106 +++++++++++++++++++++ .../org/apache/doris/analysis/ExplainTest.java | 2 +- .../doris/rewrite/RewriteImplicitCastRuleTest.java | 61 ++++++++++++ 4 files changed, 170 insertions(+), 1 deletion(-) 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 4ef6fb5a42..2aeeb24c44 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 @@ -57,6 +57,7 @@ import org.apache.doris.rewrite.RewriteBinaryPredicatesRule; import org.apache.doris.rewrite.RewriteDateLiteralRule; import org.apache.doris.rewrite.RewriteEncryptKeyRule; import org.apache.doris.rewrite.RewriteFromUnixTimeRule; +import org.apache.doris.rewrite.RewriteImplicitCastRule; import org.apache.doris.rewrite.RewriteInPredicateRule; import org.apache.doris.rewrite.mvrewrite.CountDistinctToBitmap; import org.apache.doris.rewrite.mvrewrite.CountDistinctToBitmapOrHLLRule; @@ -354,6 +355,7 @@ public class Analyzer { rules.add(NormalizeBinaryPredicatesRule.INSTANCE); // Put it after NormalizeBinaryPredicatesRule, make sure slotRef is on the left and Literal is on the right. rules.add(RewriteBinaryPredicatesRule.INSTANCE); + rules.add(RewriteImplicitCastRule.INSTANCE); rules.add(FoldConstantsRule.INSTANCE); rules.add(RewriteFromUnixTimeRule.INSTANCE); rules.add(CompoundPredicateWriteRule.INSTANCE); diff --git a/fe/fe-core/src/main/java/org/apache/doris/rewrite/RewriteImplicitCastRule.java b/fe/fe-core/src/main/java/org/apache/doris/rewrite/RewriteImplicitCastRule.java new file mode 100644 index 0000000000..cb3c68cbae --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/rewrite/RewriteImplicitCastRule.java @@ -0,0 +1,106 @@ +// 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.BinaryPredicate; +import org.apache.doris.analysis.CastExpr; +import org.apache.doris.analysis.Expr; +import org.apache.doris.analysis.IntLiteral; +import org.apache.doris.catalog.Type; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.rewrite.ExprRewriter.ClauseType; + +import java.util.List; + +/** + * During the analysis of BinaryPredicate, it will generate a CastExpr if the slot implicitly in the below case: + * SELECT * FROM t1 WHERE t1.col1 = '1'; + * col1 is integer column. + * This will prevent the binary predicate from pushing down to OlapScan which would impact the performance. + * TODO: For now, we only handle the implicit cast which cast left child with integer type + * and right child with StringLiteral type to BIGINT. + * We could do more than that in the future, such as LARGEINT type. + */ +public class RewriteImplicitCastRule implements ExprRewriteRule { + + public static RewriteImplicitCastRule INSTANCE = new RewriteImplicitCastRule(); + + @Override + public Expr apply(Expr expr, Analyzer analyzer, ClauseType clauseType) throws AnalysisException { + if (!(expr instanceof BinaryPredicate)) { + return expr; + } + BinaryPredicate predicate = (BinaryPredicate) expr; + if (!(predicate.getChild(0) instanceof CastExpr)) { + return expr; + } + CastExpr castExpr = (CastExpr) predicate.getChild(0); + if (!castExpr.isImplicit() + || !(predicate.getChild(1) instanceof IntLiteral) + || !clauseType.equals(ClauseType.WHERE_CLAUSE)) { + return expr; + } + Expr childOfCast = castExpr.getChild(0); + IntLiteral rightChild = (IntLiteral) predicate.getChild(1); + long rightValue = rightChild.getValue(); + Type leftType = childOfCast.getType(); + // no need to handle boolean since compare between a boolean with a string in not allow in doris + if (Type.TINYINT.equals(leftType)) { + return process(Type.TINYINT, + rightValue, IntLiteral.TINY_INT_MIN, IntLiteral.TINY_INT_MAX, expr, childOfCast); + } + if (Type.SMALLINT.equals(leftType)) { + return process(Type.SMALLINT, + rightValue, IntLiteral.SMALL_INT_MIN, IntLiteral.SMALL_INT_MAX, expr, childOfCast); + } + if (Type.INT.equals(leftType)) { + return process(Type.INT, + rightValue, IntLiteral.INT_MIN, IntLiteral.INT_MAX, expr, childOfCast); + } + if (Type.BIGINT.equals(leftType)) { + return process(Type.INT, + rightValue, IntLiteral.BIG_INT_MIN, IntLiteral.BIG_INT_MAX, expr, childOfCast); + } + return expr; + } + + // TODO: Let min, max value of a specific type be a part of definition of Type may + // be much better.By doing that, We would be able to abstract code in this block to + // a method. + private Expr process(Type type, + long rightValue, + long min, + long max, + Expr expr, + Expr childOfCast) throws AnalysisException { + // TODO: We could do constant folding here. + if (rightValue < min || rightValue > max) { + return expr; + } + replaceLeftChildWithNumericLiteral(expr, childOfCast, new IntLiteral(rightValue, type)); + return expr; + } + + private void replaceLeftChildWithNumericLiteral(Expr expr, Expr left, IntLiteral right) { + List<Expr> children = expr.getChildren(); + children.clear(); + children.add(0, left); + children.add(1, right); + } +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/ExplainTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/ExplainTest.java index ef99eb57d5..ec9aa76648 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/analysis/ExplainTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/ExplainTest.java @@ -97,7 +97,7 @@ public class ExplainTest { String queryStr = "explain verbose select * from test_explain.explain_t1 where dt = '1001';"; String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(ctx, queryStr, true); System.out.println(explainString); - Assert.assertTrue(explainString.contains("CAST")); + Assert.assertFalse(explainString.contains("CAST")); } public void testExplainConcatSelect() throws Exception { diff --git a/fe/fe-core/src/test/java/org/apache/doris/rewrite/RewriteImplicitCastRuleTest.java b/fe/fe-core/src/test/java/org/apache/doris/rewrite/RewriteImplicitCastRuleTest.java new file mode 100644 index 0000000000..2087d81113 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/rewrite/RewriteImplicitCastRuleTest.java @@ -0,0 +1,61 @@ +// 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.BinaryPredicate; +import org.apache.doris.analysis.BinaryPredicate.Operator; +import org.apache.doris.analysis.CastExpr; +import org.apache.doris.analysis.IntLiteral; +import org.apache.doris.analysis.SlotDescriptor; +import org.apache.doris.analysis.SlotId; +import org.apache.doris.analysis.SlotRef; +import org.apache.doris.catalog.Type; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.rewrite.ExprRewriter.ClauseType; + +import mockit.Mocked; +import org.junit.Assert; +import org.junit.Test; + +public class RewriteImplicitCastRuleTest { + + @Test + public void testRewriteCastString(@Mocked Analyzer analyzer) throws AnalysisException { + RewriteImplicitCastRule rule = new RewriteImplicitCastRule(); + IntLiteral tinyIntLiteral = new IntLiteral(1); + SlotId id = new SlotId(0); + SlotDescriptor slotDesc = new SlotDescriptor(id, null); + slotDesc.setType(Type.INT); + SlotRef slotRef = new SlotRef(slotDesc); + slotRef.setType(Type.INT); + BinaryPredicate binaryPredicate = new BinaryPredicate(Operator.EQ, slotRef.castTo(Type.BIGINT), tinyIntLiteral); + rule.apply(binaryPredicate, analyzer, ClauseType.WHERE_CLAUSE); + Assert.assertTrue(binaryPredicate.getChild(1) instanceof IntLiteral); + Assert.assertEquals(binaryPredicate.getChild(1).getType(), Type.INT); + Assert.assertSame(binaryPredicate.getChild(0), slotRef); + + IntLiteral smallIntLiteral = new IntLiteral(IntLiteral.SMALL_INT_MAX); + slotRef.setType(Type.TINYINT); + binaryPredicate = new BinaryPredicate(Operator.EQ, slotRef.castTo(Type.BIGINT), smallIntLiteral); + rule.apply(binaryPredicate, analyzer, ClauseType.WHERE_CLAUSE); + Assert.assertTrue(binaryPredicate.getChild(0) instanceof CastExpr); + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org