diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateFilter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateFilter.java index 2f46c43ecffc771..157555d5591a63e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateFilter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateFilter.java @@ -25,6 +25,7 @@ import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.NamedExpression; import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral; +import org.apache.doris.nereids.trees.expressions.literal.NullLiteral; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; @@ -45,12 +46,13 @@ public class EliminateFilter implements RewriteRuleFactory { @Override public List buildRules() { return ImmutableList.of(logicalFilter().when( - filter -> filter.getConjuncts().stream().anyMatch(BooleanLiteral.class::isInstance)) + filter -> filter.getConjuncts().stream().anyMatch(BooleanLiteral.class::isInstance) + || filter.getConjuncts().stream().anyMatch(NullLiteral.class::isInstance)) .thenApply(ctx -> { LogicalFilter filter = ctx.root; ImmutableSet.Builder newConjuncts = ImmutableSet.builder(); for (Expression expression : filter.getConjuncts()) { - if (expression == BooleanLiteral.FALSE) { + if (expression == BooleanLiteral.FALSE || expression.isNullLiteral()) { return new LogicalEmptyRelation(ctx.statementContext.getNextRelationId(), filter.getOutput()); } else if (expression != BooleanLiteral.TRUE) { @@ -80,7 +82,7 @@ public List buildRules() { Expression foldExpression = FoldConstantRule.INSTANCE.rewrite(newExpr, context); - if (foldExpression == BooleanLiteral.FALSE) { + if (foldExpression == BooleanLiteral.FALSE || expression.isNullLiteral()) { return new LogicalEmptyRelation( ctx.statementContext.getNextRelationId(), filter.getOutput()); } else if (foldExpression != BooleanLiteral.TRUE) { diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateFilterTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateFilterTest.java index 9f35a0c025398a4..6b4b85d3f8027ee 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateFilterTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateFilterTest.java @@ -18,6 +18,7 @@ package org.apache.doris.nereids.rules.rewrite; import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral; +import org.apache.doris.nereids.trees.expressions.literal.NullLiteral; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; import org.apache.doris.nereids.util.LogicalPlanBuilder; import org.apache.doris.nereids.util.MemoPatternMatchSupported; @@ -42,6 +43,17 @@ void testEliminateFilterFalse() { .matches(logicalEmptyRelation()); } + @Test + void testEliminateFilterNull() { + LogicalPlan filterNull = new LogicalPlanBuilder(PlanConstructor.newLogicalOlapScan(0, "t1", 0)) + .filter(NullLiteral.INSTANCE) + .build(); + + PlanChecker.from(MemoTestUtils.createConnectContext(), filterNull) + .applyTopDown(new EliminateFilter()) + .matches(logicalEmptyRelation()); + } + @Test void testEliminateFilterTrue() { LogicalPlan filterTrue = new LogicalPlanBuilder(PlanConstructor.newLogicalOlapScan(0, "t1", 0)) diff --git a/regression-test/data/empty_relation/eliminate_empty.out b/regression-test/data/empty_relation/eliminate_empty.out index f01d0a947ee8e56..8bad386ff2200a4 100644 --- a/regression-test/data/empty_relation/eliminate_empty.out +++ b/regression-test/data/empty_relation/eliminate_empty.out @@ -70,6 +70,81 @@ PhysicalResultSink -- !except_empty_data -- +-- !null_join -- +PhysicalResultSink +--PhysicalEmptyRelation + +-- !null_explain_union_empty_data -- +PhysicalResultSink +--PhysicalDistribute[DistributionSpecGather] +----hashAgg[LOCAL] +------PhysicalProject +--------PhysicalOlapScan[nation] + +-- !null_union_empty_data -- +1 + +-- !null_explain_union_empty_empty -- +PhysicalResultSink +--PhysicalEmptyRelation + +-- !null_union_empty_empty -- + +-- !null_union_emtpy_onerow -- +10 + +-- !null_explain_intersect_data_empty -- +PhysicalResultSink +--PhysicalEmptyRelation + +-- !null_explain_intersect_empty_data -- +PhysicalResultSink +--PhysicalEmptyRelation + +-- !null_explain_except_data_empty -- +PhysicalResultSink +--PhysicalDistribute[DistributionSpecGather] +----PhysicalProject +------hashAgg[LOCAL] +--------PhysicalProject +----------PhysicalOlapScan[nation] + +-- !null_explain_except_data_empty_data -- +PhysicalResultSink +--PhysicalDistribute[DistributionSpecGather] +----PhysicalExcept +------PhysicalDistribute[DistributionSpecHash] +--------PhysicalProject +----------PhysicalOlapScan[nation] +------PhysicalDistribute[DistributionSpecHash] +--------PhysicalProject +----------filter(( not (n_nationkey = 1))) +------------PhysicalOlapScan[nation] + +-- !null_except_data_empty_data -- +1 + +-- !null_explain_except_empty_data -- +PhysicalResultSink +--PhysicalEmptyRelation + +-- !null_intersect_data_empty -- + +-- !null_intersect_empty_data -- + +-- !null_except_data_empty -- +1 + +-- !null_except_empty_data -- + +-- !prune_partition1 -- +PhysicalResultSink +--PhysicalEmptyRelation + +-- !prune_partition2 -- +PhysicalResultSink +--PhysicalEmptyRelation + -- !join_with_empty_child -- 2 8 e v 3 4 7 at 2 diff --git a/regression-test/suites/empty_relation/eliminate_empty.groovy b/regression-test/suites/empty_relation/eliminate_empty.groovy index dc602a466c78589..8d5f1baea7b65eb 100644 --- a/regression-test/suites/empty_relation/eliminate_empty.groovy +++ b/regression-test/suites/empty_relation/eliminate_empty.groovy @@ -128,6 +128,143 @@ suite("eliminate_empty") { select r_regionkey from region where false except select n_nationkey from nation """ + qt_null_join """ + explain shape plan + select * + from + nation + join + (select * from region where Null) R + """ + + qt_null_explain_union_empty_data """ + explain shape plan + select * + from (select n_nationkey from nation union select r_regionkey from region where Null) T + """ + qt_null_union_empty_data """ + select * + from (select n_nationkey from nation union select r_regionkey from region where Null) T + """ + + qt_null_explain_union_empty_empty """ + explain shape plan + select * + from ( + select n_nationkey from nation where Null + union + select r_regionkey from region where Null + ) T + """ + qt_null_union_empty_empty """ + select * + from ( + select n_nationkey from nation where Null + union + select r_regionkey from region where Null + ) T + """ + qt_null_union_emtpy_onerow """ + select * + from ( + select n_nationkey from nation where Null + union + select 10 + union + select 10 + )T + """ + + qt_null_explain_intersect_data_empty """ + explain shape plan + select n_nationkey from nation intersect select r_regionkey from region where Null + """ + + qt_null_explain_intersect_empty_data """ + explain shape plan + select r_regionkey from region where Null intersect select n_nationkey from nation + """ + + qt_null_explain_except_data_empty """ + explain shape plan + select n_nationkey from nation except select r_regionkey from region where Null + """ + + qt_null_explain_except_data_empty_data """ + explain shape plan + select n_nationkey from nation + except + select r_regionkey from region where Null + except + select n_nationkey from nation where n_nationkey != 1; + """ + + qt_null_except_data_empty_data """ + select n_nationkey from nation + except + select r_regionkey from region where Null + except + select n_nationkey from nation where n_nationkey != 1; + """ + + qt_null_explain_except_empty_data """ + explain shape plan + select r_regionkey from region where Null except select n_nationkey from nation + """ + + + qt_null_intersect_data_empty """ + select n_nationkey from nation intersect select r_regionkey from region where Null + """ + + qt_null_intersect_empty_data """ + select r_regionkey from region where Null intersect select n_nationkey from nation + """ + + qt_null_except_data_empty """ + select n_nationkey from nation except select r_regionkey from region where Null + """ + + qt_null_except_empty_data """ + select r_regionkey from region where Null except select n_nationkey from nation + """ + + sql """ + drop table if exists eliminate_partition_prune; + """ + sql """ + CREATE TABLE `eliminate_partition_prune` ( + `k1` int(11) NULL COMMENT "", + `k2` int(11) NULL COMMENT "", + `k3` int(11) NULL COMMENT "" + ) + PARTITION BY RANGE(`k1`, `k2`) + (PARTITION p1 VALUES LESS THAN ("3", "1"), + PARTITION p2 VALUES [("3", "1"), ("7", "10")), + PARTITION p3 VALUES [("7", "10"), ("10", "15"))) + DISTRIBUTED BY HASH(`k1`) BUCKETS 10 + PROPERTIES ('replication_num' = '1'); + """ + + + qt_prune_partition1 """ + explain shape plan + select sum(k2) + from + (select * from eliminate_partition_prune where k1=100) T + group by k3; + """ + sql """ + insert into eliminate_partition_prune values (7, 0, 0) + """ + qt_prune_partition2 """ + explain shape plan + select sum(k2) + from + (select * from eliminate_partition_prune where k1=100) T + group by k3; + """ + sql """drop table if exists table_5_undef_partitions2_keys3""" sql """drop table if exists table_10_undef_partitions2_keys3""" @@ -179,4 +316,4 @@ suite("eliminate_empty") { sql """drop table if exists table_5_undef_partitions2_keys3""" sql """drop table if exists table_10_undef_partitions2_keys3""" } -} \ No newline at end of file +} diff --git a/regression-test/suites/nereids_syntax_p0/test_simplify_comparison.groovy b/regression-test/suites/nereids_syntax_p0/test_simplify_comparison.groovy index 5b83af29c134f32..fe89b8d6162a9b0 100644 --- a/regression-test/suites/nereids_syntax_p0/test_simplify_comparison.groovy +++ b/regression-test/suites/nereids_syntax_p0/test_simplify_comparison.groovy @@ -88,15 +88,6 @@ suite("test_simplify_comparison") { contains "CAST" } - explain { - sql "verbose select * from simple_test_table_t where a = cast(1.1 as double) and b = cast(1.1 as double) and c = cast(1.1 as double) and d = cast(1.1 as double);" - contains "a[#0] IS NULL" - contains "b[#1] IS NULL" - contains "c[#2] IS NULL" - contains "d[#3] IS NULL" - contains "AND NULL" - } - explain { sql "verbose select * from simple_test_table_t where e = cast(1.1 as double);" contains "CAST(e[#4] AS DOUBLE) = 1.1" @@ -204,15 +195,6 @@ suite("test_simplify_comparison") { contains "CAST" } - explain { - sql "verbose select * from simple_test_table_t where a = 1.1 and b = 1.1 and c = 1.1 and d = 1.1;" - contains "a[#0] IS NULL" - contains "b[#1] IS NULL" - contains "c[#2] IS NULL" - contains "d[#3] IS NULL" - contains "AND NULL" - } - explain { sql "verbose select * from simple_test_table_t where e = 1.1;" contains "CAST(e[#4] AS DOUBLE) = 1.1" @@ -272,4 +254,4 @@ suite("test_simplify_comparison") { qt_select1 """select * from simple_test_table_t where cast(a as decimal(5,1)) = 10.0;""" qt_select2 """select a.col1, cast(a.col1 as decimal(7,2)) col3, case when a.col1 is null then 15 when cast(a.col1 as decimal(7,2)) < -99997.99 then 18 when cast(a.col1 as decimal(7,2)) < 1.001 then 3 else -55 end col2 from (select 1 as col1) a;""" -} \ No newline at end of file +}