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 0956a6ef0a1722..9869d9c131bec8 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 @@ -46,6 +46,7 @@ import org.apache.doris.rewrite.mvrewrite.HLLHashToSlotRefRule; import org.apache.doris.rewrite.mvrewrite.NDVToHll; import org.apache.doris.rewrite.mvrewrite.ToBitmapToSlotRefRule; +import org.apache.doris.rewrite.BinaryPredicatesDateRule; import org.apache.doris.thrift.TQueryGlobals; import com.google.common.base.Joiner; @@ -255,6 +256,7 @@ public GlobalState(Catalog catalog, ConnectContext context) { // pushdown and Parquet row group pruning based on min/max statistics. rules.add(NormalizeBinaryPredicatesRule.INSTANCE); rules.add(FoldConstantsRule.INSTANCE); + rules.add(BinaryPredicatesDateRule.INSTANCE); exprRewriter_ = new ExprRewriter(rules); // init mv rewriter List mvRewriteRules = Lists.newArrayList(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/rewrite/BinaryPredicatesDateRule.java b/fe/fe-core/src/main/java/org/apache/doris/rewrite/BinaryPredicatesDateRule.java new file mode 100644 index 00000000000000..200466cb994e11 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/rewrite/BinaryPredicatesDateRule.java @@ -0,0 +1,50 @@ +// 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.BoolLiteral; +import org.apache.doris.common.AnalysisException; + +/** + * Binary predicate date rule try to convert date expression, if date is invalid, it will be + * converted into bool literal to avoid to scan all partitions + * Examples: + * date = "2020-10-32" => FALSE + */ +public class BinaryPredicatesDateRule implements ExprRewriteRule { + public static ExprRewriteRule INSTANCE = new BinaryPredicatesDateRule(); + + @Override + public Expr apply(Expr expr, Analyzer analyzer) throws AnalysisException { + if (!(expr instanceof BinaryPredicate)) return expr; + Expr lchild = expr.getChild(0); + if (!lchild.getType().isDateType()) { + return expr; + } + Expr valueExpr = expr.getChild(1); + if(valueExpr.getType().isDateType() && valueExpr.isConstant() + && valueExpr instanceof CastExpr) { + return new BoolLiteral(false); + } + return expr; + } +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java b/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java old mode 100644 new mode 100755 index 3dacff51f55b7c..ac381077d4845f --- a/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java @@ -1381,6 +1381,69 @@ public void testIntDateTime() throws Exception { explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); Assert.assertTrue(explainString.contains("PREDICATES: `date` IN ('2020-10-30 00:00:00')")); } + + @Test + public void testCheckInvalidDate() throws Exception { + FeConstants.runningUnitTest = true; + connectContext.setDatabase("default_cluster:test"); + //valid date + String sql = "select day from tbl_int_date where day = '2020-10-30'"; + String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("PREDICATES: `day` = '2020-10-30 00:00:00'")); + //valid date + sql = "select day from tbl_int_date where day = 20201030"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("PREDICATES: `day` = '2020-10-30 00:00:00'")); + //invalid date + sql = "select day from tbl_int_date where day = '2020-10-32'"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + System.out.println(explainString); + Assert.assertTrue(explainString.contains("EMPTYSET")); + //invalid date + sql = "select day from tbl_int_date where day = 'hello'"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("EMPTYSET")); + //invalid date + sql = "select day from tbl_int_date where day = 2020-10-30"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + //invalid date + sql = "select day from tbl_int_date where day = 10-30"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("EMPTYSET")); + + //valid datetime + sql = "select day from tbl_int_date where date = '2020-10-30 12:12:30'"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("PREDICATES: `date` = '2020-10-30 12:12:30'")); + //valid datetime + sql = "select day from tbl_int_date where date = 20201030"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("PREDICATES: `date` = '2020-10-30 00:00:00'")); + //valid datetime + sql = "select day from tbl_int_date where date = '2020-10-30'"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("PREDICATES: `date` = '2020-10-30 00:00:00'")); + //invalid datetime + sql = "select day from tbl_int_date where date = '2020-10-32'"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("EMPTYSET")); + //invalid datetime + sql = "select day from tbl_int_date where date = 'hello'"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("EMPTYSET")); + //invalid datetime + sql = "select day from tbl_int_date where date = 2020-10-30"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("EMPTYSET")); + //invalid datetime + sql = "select day from tbl_int_date where date = 10-30"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("EMPTYSET")); + //invalid datetime + sql = "select day from tbl_int_date where date = '2020-10-12 12:23:76'"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("EMPTYSET")); + } }