From 465b238b8461d799d7c399688257511fb26189be Mon Sep 17 00:00:00 2001 From: stonepage <40830455+st1page@users.noreply.github.com> Date: Mon, 28 Nov 2022 14:07:23 +0800 Subject: [PATCH] test(planner): add predicata push down planner test (#6578) * add predicate push down planner test * add com comments * fix mistake * dedup test case * dedup test case * improve test for agg/proj * add todo Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- .../planner_test/tests/testdata/join.yaml | 27 -- .../tests/testdata/predicate_pushdown.yaml | 261 ++++++++++++++---- .../optimizer/plan_node/logical_hop_window.rs | 1 + .../src/optimizer/plan_node/logical_limit.rs | 1 + .../src/optimizer/plan_node/logical_topn.rs | 1 + 5 files changed, 211 insertions(+), 80 deletions(-) diff --git a/src/frontend/planner_test/tests/testdata/join.yaml b/src/frontend/planner_test/tests/testdata/join.yaml index 5ebc009d14273..7964206373c55 100644 --- a/src/frontend/planner_test/tests/testdata/join.yaml +++ b/src/frontend/planner_test/tests/testdata/join.yaml @@ -143,33 +143,6 @@ | └─BatchScan { table: bc, columns: [bc.b, bc.c], distribution: SomeShard } └─BatchExchange { order: [], dist: HashShard(ca.c) } └─BatchScan { table: ca, columns: [ca.c, ca.a], distribution: SomeShard } -- name: Only push to left - sql: | - create table t1 (v1 int, v2 int); - create table t2 (v1 int, v2 int); - select * from t1 left join t2 where t1.v2 > 100; - optimized_logical_plan: | - LogicalJoin { type: LeftOuter, on: true, output: all } - ├─LogicalScan { table: t1, output_columns: [t1.v1, t1.v2], required_columns: [v1, v2], predicate: (t1.v2 > 100:Int32) } - └─LogicalScan { table: t2, columns: [t2.v1, t2.v2] } -- name: Only push to right - sql: | - create table t1 (v1 int, v2 int); - create table t2 (v1 int, v2 int); - select * from t1 right join t2 where t2.v2 > 100; - optimized_logical_plan: | - LogicalJoin { type: LeftOuter, on: true, output: [t1.v1, t1.v2, t2.v1, t2.v2] } - ├─LogicalScan { table: t2, output_columns: [t2.v1, t2.v2], required_columns: [v1, v2], predicate: (t2.v2 > 100:Int32) } - └─LogicalScan { table: t1, columns: [t1.v1, t1.v2] } -- name: Push to left, right and on - sql: | - create table t1 (v1 int, v2 int); - create table t2 (v1 int, v2 int); - select * from t1, t2 where t1.v1 > 100 and t2.v1 < 1000 and t1.v2 = t2.v2; - optimized_logical_plan: | - LogicalJoin { type: Inner, on: (t1.v2 = t2.v2), output: all } - ├─LogicalScan { table: t1, output_columns: [t1.v1, t1.v2], required_columns: [v1, v2], predicate: (t1.v1 > 100:Int32) } - └─LogicalScan { table: t2, output_columns: [t2.v1, t2.v2], required_columns: [v1, v2], predicate: (t2.v1 < 1000:Int32) } - name: Left & right has same SomeShard distribution. There should still be exchanges below hash join sql: | create table t(x int); diff --git a/src/frontend/planner_test/tests/testdata/predicate_pushdown.yaml b/src/frontend/planner_test/tests/testdata/predicate_pushdown.yaml index eee87318c6288..6073d1e9ab9fd 100644 --- a/src/frontend/planner_test/tests/testdata/predicate_pushdown.yaml +++ b/src/frontend/planner_test/tests/testdata/predicate_pushdown.yaml @@ -1,68 +1,223 @@ # This file is automatically generated. See `src/frontend/planner_test/README.md` for more information. -- sql: | +- name: Always false should not be pushed below SimpleAgg + sql: | + create table t(v1 int, v2 int, v3 int, v4 int); + select min(v1) from t having false; + logical_plan: | + LogicalProject { exprs: [min(t.v1)] } + └─LogicalFilter { predicate: false:Boolean } + └─LogicalAgg { aggs: [min(t.v1)] } + └─LogicalProject { exprs: [t.v1] } + └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.v4, t._row_id] } + optimized_logical_plan: | + LogicalFilter { predicate: false:Boolean } + └─LogicalAgg { aggs: [min(t.v1)] } + └─LogicalScan { table: t, columns: [t.v1] } +- name: filter should not transpose limit + sql: | + create table t(v1 int, v2 int, v3 int, v4 int); + with cte as (select * from t limit 10) select * from cte where v1=10 AND v2=20 AND v3=30; + logical_plan: | + LogicalProject { exprs: [t.v1, t.v2, t.v3, t.v4] } + └─LogicalFilter { predicate: (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) } + └─LogicalLimit { limit: 10, offset: 0 } + └─LogicalProject { exprs: [t.v1, t.v2, t.v3, t.v4] } + └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.v4, t._row_id] } + optimized_logical_plan: | + LogicalFilter { predicate: (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) } + └─LogicalLimit { limit: 10, offset: 0 } + └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.v4] } +- name: filter should not transpose TopN + sql: | + create table t(v1 int, v2 int, v3 int, v4 int); + with cte as (select * from t order by v1 limit 10 ) select * from cte where v1=10 AND v2=20 AND v3=30; + logical_plan: | + LogicalProject { exprs: [t.v1, t.v2, t.v3, t.v4] } + └─LogicalFilter { predicate: (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) } + └─LogicalTopN { order: "[t.v1 ASC]", limit: 10, offset: 0 } + └─LogicalProject { exprs: [t.v1, t.v2, t.v3, t.v4] } + └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.v4, t._row_id] } + optimized_logical_plan: | + LogicalFilter { predicate: (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) } + └─LogicalTopN { order: "[t.v1 ASC]", limit: 10, offset: 0 } + └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.v4] } +# TODO: hop's predicate pushdown https://github.com/risingwavelabs/risingwave/issues/6606 +- name: filter hop transpose + sql: | + create table t(v1 int, v2 int, v3 int, v4 int, ts date); + with cte as (select * from hop(t, ts, interval '1' day, interval '3' day)) + select * from cte + where v1=10 AND v2=20 AND v3=30 AND ts >= date '1997-07-01' + AND window_start >= date '1997-07-02' AND window_end >= date '1997-07-03' + AND window_start >= ts + interval '1' day AND window_end > ts + interval '4' day; + logical_plan: | + LogicalProject { exprs: [t.v1, t.v2, t.v3, t.v4, t.ts, window_start, window_end] } + └─LogicalFilter { predicate: (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) AND (t.ts >= '1997-07-01':Varchar::Date) AND (window_start >= '1997-07-02':Varchar::Date) AND (window_end >= '1997-07-03':Varchar::Date) AND (window_start >= (t.ts + '1 day':Interval)) AND (window_end > (t.ts + '4 days':Interval)) } + └─LogicalProject { exprs: [t.v1, t.v2, t.v3, t.v4, t.ts, window_start, window_end] } + └─LogicalHopWindow { time_col: t.ts, slide: 1 day, size: 3 days, output: all } + └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.v4, t.ts, t._row_id] } + optimized_logical_plan: | + LogicalFilter { predicate: (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) AND (t.ts >= '1997-07-01':Varchar::Date) AND (window_start >= '1997-07-02':Varchar::Date) AND (window_end >= '1997-07-03':Varchar::Date) AND (window_start >= (t.ts + '1 day':Interval)) AND (window_end > (t.ts + '4 days':Interval)) } + └─LogicalHopWindow { time_col: t.ts, slide: 1 day, size: 3 days, output: all } + └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.v4, t.ts] } +- name: filter union transpose + sql: | create table t1 (v1 int, v2 int, v3 int); create table t2 (v1 int, v2 int, v3 int); - select * from t1 join t2 on t1.v1=t2.v2 and t1.v1>1 where t2.v2>2; + with cte as (select * from t1 union all select * from t2) select * from cte where v1=10 AND v2=20 AND v3=30; logical_plan: | - LogicalProject { exprs: [t1.v1, t1.v2, t1.v3, t2.v1, t2.v2, t2.v3] } - └─LogicalFilter { predicate: (t2.v2 > 2:Int32) } - └─LogicalJoin { type: Inner, on: (t1.v1 = t2.v2) AND (t1.v1 > 1:Int32), output: all } - ├─LogicalScan { table: t1, columns: [t1.v1, t1.v2, t1.v3, t1._row_id] } - └─LogicalScan { table: t2, columns: [t2.v1, t2.v2, t2.v3, t2._row_id] } + LogicalProject { exprs: [t1.v1, t1.v2, t1.v3] } + └─LogicalFilter { predicate: (t1.v1 = 10:Int32) AND (t1.v2 = 20:Int32) AND (t1.v3 = 30:Int32) } + └─LogicalUnion { all: true } + ├─LogicalProject { exprs: [t1.v1, t1.v2, t1.v3] } + | └─LogicalScan { table: t1, columns: [t1.v1, t1.v2, t1.v3, t1._row_id] } + └─LogicalProject { exprs: [t2.v1, t2.v2, t2.v3] } + └─LogicalScan { table: t2, columns: [t2.v1, t2.v2, t2.v3, t2._row_id] } optimized_logical_plan: | - LogicalJoin { type: Inner, on: (t1.v1 = t2.v2), output: all } - ├─LogicalScan { table: t1, output_columns: [t1.v1, t1.v2, t1.v3], required_columns: [v1, v2, v3], predicate: (t1.v1 > 1:Int32) } - └─LogicalScan { table: t2, output_columns: [t2.v1, t2.v2, t2.v3], required_columns: [v1, v2, v3], predicate: (t2.v2 > 2:Int32) } -- sql: | - create table t (v1 bigint, v2 double precision); - select * from (select * from t) where v2 > 1; + LogicalUnion { all: true } + ├─LogicalScan { table: t1, output_columns: [t1.v1, t1.v2, t1.v3], required_columns: [v1, v2, v3], predicate: (t1.v1 = 10:Int32) AND (t1.v2 = 20:Int32) AND (t1.v3 = 30:Int32) } + └─LogicalScan { table: t2, output_columns: [t2.v1, t2.v2, t2.v3], required_columns: [v1, v2, v3], predicate: (t2.v1 = 10:Int32) AND (t2.v2 = 20:Int32) AND (t2.v3 = 30:Int32) } +- name: filter project transpose + sql: | + create table t(v1 int, v2 int, v3 int, v4 int, ts date); + with cte as (select v1,v2,v3,v4,v1+v2 as expr_a, v3*v4 as expr_b from t) select * from cte where expr_a>10 AND v1=10 AND v2=20 AND v3=30 AND expr_a > expr_b AND expr_a > v1; logical_plan: | - LogicalProject { exprs: [t.v1, t.v2] } - └─LogicalFilter { predicate: (t.v2 > 1:Int32) } - └─LogicalProject { exprs: [t.v1, t.v2] } - └─LogicalScan { table: t, columns: [t.v1, t.v2, t._row_id] } + LogicalProject { exprs: [t.v1, t.v2, t.v3, t.v4, (t.v1 + t.v2), (t.v3 * t.v4)] } + └─LogicalFilter { predicate: ((t.v1 + t.v2) > 10:Int32) AND (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) AND ((t.v1 + t.v2) > (t.v3 * t.v4)) AND ((t.v1 + t.v2) > t.v1) } + └─LogicalProject { exprs: [t.v1, t.v2, t.v3, t.v4, (t.v1 + t.v2), (t.v3 * t.v4)] } + └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.v4, t.ts, t._row_id] } optimized_logical_plan: | - LogicalScan { table: t, output_columns: [t.v1, t.v2], required_columns: [v1, v2], predicate: (t.v2 > 1:Int32) } -- sql: | - create table t (v1 bigint, v2 double precision); - select v1 from (select v2, v1 from t) where v2 > 1; + LogicalProject { exprs: [t.v1, t.v2, t.v3, t.v4, (t.v1 + t.v2), (t.v3 * t.v4)] } + └─LogicalScan { table: t, output_columns: [t.v1, t.v2, t.v3, t.v4], required_columns: [v1, v2, v3, v4], predicate: ((t.v1 + t.v2) > 10:Int32) AND (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) AND ((t.v1 + t.v2) > (t.v3 * t.v4)) AND ((t.v1 + t.v2) > t.v1) } +- name: filter agg transpose + sql: | + create table t(v1 int, v2 int, v3 int, v4 int, ts date); + with cte as (select v1, v2, v3, count(*) as cnt, count(1) as cnt2 from t group by v1, v2, v3) select * from cte where v1=10 AND v2=20 AND v3=30 AND cnt > v1 AND v2 > v3 AND cnt > cnt2; logical_plan: | - LogicalProject { exprs: [t.v1] } - └─LogicalFilter { predicate: (t.v2 > 1:Int32) } - └─LogicalProject { exprs: [t.v2, t.v1] } - └─LogicalScan { table: t, columns: [t.v1, t.v2, t._row_id] } + LogicalProject { exprs: [t.v1, t.v2, t.v3, count, count(1:Int32)] } + └─LogicalFilter { predicate: (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) AND (count > t.v1) AND (t.v2 > t.v3) AND (count > count(1:Int32)) } + └─LogicalProject { exprs: [t.v1, t.v2, t.v3, count, count(1:Int32)] } + └─LogicalAgg { group_key: [t.v1, t.v2, t.v3], aggs: [count, count(1:Int32)] } + └─LogicalProject { exprs: [t.v1, t.v2, t.v3, 1:Int32] } + └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.v4, t.ts, t._row_id] } optimized_logical_plan: | - LogicalScan { table: t, output_columns: [t.v1], required_columns: [v1, v2], predicate: (t.v2 > 1:Int32) } -- sql: | - create table t (v1 bigint, v2 double precision); - select v1 from (select v2 as a2, v1 from t where v1 > 2) where a2 > 1; + LogicalFilter { predicate: (count > t.v1) AND (count > count(1:Int32)) } + └─LogicalAgg { group_key: [t.v1, t.v2, t.v3], aggs: [count, count(1:Int32)] } + └─LogicalProject { exprs: [t.v1, t.v2, t.v3, 1:Int32] } + └─LogicalScan { table: t, output_columns: [t.v1, t.v2, t.v3], required_columns: [v1, v2, v3], predicate: (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) AND (t.v2 > t.v3) } +- name: filter project set transpose + sql: | + create table t(v1 int, v2 int, v3 int, arr int[]); + with cte as (select v1, v2, v3, unnest(arr) as arr_unnested from t) select * from cte where v1=10 AND v2=20 AND v3=30 AND arr_unnested=30; logical_plan: | - LogicalProject { exprs: [t.v1] } - └─LogicalFilter { predicate: (t.v2 > 1:Int32) } - └─LogicalProject { exprs: [t.v2, t.v1] } - └─LogicalFilter { predicate: (t.v1 > 2:Int32) } - └─LogicalScan { table: t, columns: [t.v1, t.v2, t._row_id] } + LogicalProject { exprs: [t.v1, t.v2, t.v3, Unnest($3)] } + └─LogicalFilter { predicate: (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) AND (Unnest($3) = 30:Int32) } + └─LogicalProject { exprs: [t.v1, t.v2, t.v3, Unnest($3)] } + └─LogicalProjectSet { select_list: [$0, $1, $2, Unnest($3)] } + └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.arr, t._row_id] } optimized_logical_plan: | - LogicalScan { table: t, output_columns: [t.v1], required_columns: [v1, v2], predicate: (t.v2 > 1:Int32) AND (t.v1 > 2:Int32) } -- sql: | - create table t(v1 int, v2 int, v3 int, v4 int); - select * from (select v1, min(v2) as min from t group by v1) where v1 > 1 and min > 1 and 1 > 0 and v1 > min; + LogicalProject { exprs: [t.v1, t.v2, t.v3, Unnest($3)] } + └─LogicalFilter { predicate: (t.v1 = 10:Int32) AND (t.v2 = 20:Int32) AND (t.v3 = 30:Int32) AND (Unnest($3) = 30:Int32) } + └─LogicalProjectSet { select_list: [$0, $1, $2, Unnest($3)] } + └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.arr, t._row_id] } +- name: filter inner join transpose + sql: | + create table t1(v1 int, v2 int); + create table t2(v3 int, v4 int); + with cte as (select * from t1 join t2) select * from cte where v1 is null AND v2 is null AND v3 is null AND v4 is null; logical_plan: | - LogicalProject { exprs: [t.v1, min(t.v2)] } - └─LogicalFilter { predicate: (t.v1 > 1:Int32) AND (min(t.v2) > 1:Int32) AND (1:Int32 > 0:Int32) AND (t.v1 > min(t.v2)) } - └─LogicalProject { exprs: [t.v1, min(t.v2)] } - └─LogicalAgg { group_key: [t.v1], aggs: [min(t.v2)] } - └─LogicalProject { exprs: [t.v1, t.v2] } - └─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.v4, t._row_id] } + LogicalProject { exprs: [t1.v1, t1.v2, t2.v3, t2.v4] } + └─LogicalFilter { predicate: IsNull(t1.v1) AND IsNull(t1.v2) AND IsNull(t2.v3) AND IsNull(t2.v4) } + └─LogicalProject { exprs: [t1.v1, t1.v2, t2.v3, t2.v4] } + └─LogicalJoin { type: Inner, on: true, output: all } + ├─LogicalScan { table: t1, columns: [t1.v1, t1.v2, t1._row_id] } + └─LogicalScan { table: t2, columns: [t2.v3, t2.v4, t2._row_id] } optimized_logical_plan: | - LogicalFilter { predicate: (min(t.v2) > 1:Int32) AND (t.v1 > min(t.v2)) } - └─LogicalAgg { group_key: [t.v1], aggs: [min(t.v2)] } - └─LogicalScan { table: t, output_columns: [t.v1, t.v2], required_columns: [v1, v2], predicate: (t.v1 > 1:Int32) AND (1:Int32 > 0:Int32) } -- name: Always false should not be pushed below SimpleAgg + LogicalJoin { type: Inner, on: true, output: all } + ├─LogicalScan { table: t1, output_columns: [t1.v1, t1.v2], required_columns: [v1, v2], predicate: IsNull(t1.v1) AND IsNull(t1.v2) } + └─LogicalScan { table: t2, output_columns: [t2.v3, t2.v4], required_columns: [v3, v4], predicate: IsNull(t2.v3) AND IsNull(t2.v4) } +- name: filter left join transpose sql: | - create table t(v1 int, v2 int, v3 int, v4 int); - select min(v1) from t having false; + create table t1(v1 int, v2 int); + create table t2(v3 int, v4 int); + with cte as (select * from t1 left join t2) select * from cte where v1 is null AND v2 is null AND v3 is null AND v4 is null; + logical_plan: | + LogicalProject { exprs: [t1.v1, t1.v2, t2.v3, t2.v4] } + └─LogicalFilter { predicate: IsNull(t1.v1) AND IsNull(t1.v2) AND IsNull(t2.v3) AND IsNull(t2.v4) } + └─LogicalProject { exprs: [t1.v1, t1.v2, t2.v3, t2.v4] } + └─LogicalJoin { type: LeftOuter, on: true, output: all } + ├─LogicalScan { table: t1, columns: [t1.v1, t1.v2, t1._row_id] } + └─LogicalScan { table: t2, columns: [t2.v3, t2.v4, t2._row_id] } optimized_logical_plan: | - LogicalFilter { predicate: false:Boolean } - └─LogicalAgg { aggs: [min(t.v1)] } - └─LogicalScan { table: t, columns: [t.v1] } + LogicalFilter { predicate: IsNull(t2.v3) AND IsNull(t2.v4) } + └─LogicalJoin { type: LeftOuter, on: true, output: all } + ├─LogicalScan { table: t1, output_columns: [t1.v1, t1.v2], required_columns: [v1, v2], predicate: IsNull(t1.v1) AND IsNull(t1.v2) } + └─LogicalScan { table: t2, columns: [t2.v3, t2.v4] } +- name: filter right join transpose + sql: | + create table t1(v1 int, v2 int); + create table t2(v3 int, v4 int); + with cte as (select * from t1 right join t2) select * from cte where v1 is null AND v2 is null AND v3 is null AND v4 is null; + logical_plan: | + LogicalProject { exprs: [t1.v1, t1.v2, t2.v3, t2.v4] } + └─LogicalFilter { predicate: IsNull(t1.v1) AND IsNull(t1.v2) AND IsNull(t2.v3) AND IsNull(t2.v4) } + └─LogicalProject { exprs: [t1.v1, t1.v2, t2.v3, t2.v4] } + └─LogicalJoin { type: RightOuter, on: true, output: all } + ├─LogicalScan { table: t1, columns: [t1.v1, t1.v2, t1._row_id] } + └─LogicalScan { table: t2, columns: [t2.v3, t2.v4, t2._row_id] } + optimized_logical_plan: | + LogicalFilter { predicate: IsNull(t1.v1) AND IsNull(t1.v2) } + └─LogicalJoin { type: LeftOuter, on: true, output: [t1.v1, t1.v2, t2.v3, t2.v4] } + ├─LogicalScan { table: t2, output_columns: [t2.v3, t2.v4], required_columns: [v3, v4], predicate: IsNull(t2.v3) AND IsNull(t2.v4) } + └─LogicalScan { table: t1, columns: [t1.v1, t1.v2] } +- name: filter full outer join transpose + sql: | + create table t1(v1 int, v2 int); + create table t2(v3 int, v4 int); + with cte as (select * from t1 full outer join t2) select * from cte where v1 is null AND v2 is null AND v3 is null AND v4 is null; + logical_plan: | + LogicalProject { exprs: [t1.v1, t1.v2, t2.v3, t2.v4] } + └─LogicalFilter { predicate: IsNull(t1.v1) AND IsNull(t1.v2) AND IsNull(t2.v3) AND IsNull(t2.v4) } + └─LogicalProject { exprs: [t1.v1, t1.v2, t2.v3, t2.v4] } + └─LogicalJoin { type: FullOuter, on: true, output: all } + ├─LogicalScan { table: t1, columns: [t1.v1, t1.v2, t1._row_id] } + └─LogicalScan { table: t2, columns: [t2.v3, t2.v4, t2._row_id] } + optimized_logical_plan: | + LogicalFilter { predicate: IsNull(t1.v1) AND IsNull(t1.v2) AND IsNull(t2.v3) AND IsNull(t2.v4) } + └─LogicalJoin { type: FullOuter, on: true, output: all } + ├─LogicalScan { table: t1, columns: [t1.v1, t1.v2] } + └─LogicalScan { table: t2, columns: [t2.v3, t2.v4] } +- name: filter semi join transpose + sql: | + create table t1(v1 int, v2 int); + create table t2(v1 int, v2 int); + with cte as (select * from t1 where exists (select * from t2)) select * from cte where v1 is null AND v2 is null; + logical_plan: | + LogicalProject { exprs: [t1.v1, t1.v2] } + └─LogicalFilter { predicate: IsNull(t1.v1) AND IsNull(t1.v2) } + └─LogicalProject { exprs: [t1.v1, t1.v2] } + └─LogicalApply { type: LeftSemi, on: true, correlated_id: 1 } + ├─LogicalScan { table: t1, columns: [t1.v1, t1.v2, t1._row_id] } + └─LogicalProject { exprs: [t2.v1, t2.v2] } + └─LogicalScan { table: t2, columns: [t2.v1, t2.v2, t2._row_id] } + optimized_logical_plan: | + LogicalJoin { type: LeftSemi, on: true, output: all } + ├─LogicalScan { table: t1, output_columns: [t1.v1, t1.v2], required_columns: [v1, v2], predicate: IsNull(t1.v1) AND IsNull(t1.v2) } + └─LogicalScan { table: t2, columns: [] } +- name: filter anti join transpose + sql: | + create table t1(v1 int, v2 int); + create table t2(v1 int, v2 int); + with cte as (select * from t1 where not exists (select * from t2)) select * from cte where v1 is null AND v2 is null; + logical_plan: | + LogicalProject { exprs: [t1.v1, t1.v2] } + └─LogicalFilter { predicate: IsNull(t1.v1) AND IsNull(t1.v2) } + └─LogicalProject { exprs: [t1.v1, t1.v2] } + └─LogicalApply { type: LeftAnti, on: true, correlated_id: 1 } + ├─LogicalScan { table: t1, columns: [t1.v1, t1.v2, t1._row_id] } + └─LogicalProject { exprs: [t2.v1, t2.v2] } + └─LogicalScan { table: t2, columns: [t2.v1, t2.v2, t2._row_id] } + optimized_logical_plan: | + LogicalJoin { type: LeftAnti, on: true, output: all } + ├─LogicalScan { table: t1, output_columns: [t1.v1, t1.v2], required_columns: [v1, v2], predicate: IsNull(t1.v1) AND IsNull(t1.v2) } + └─LogicalScan { table: t2, columns: [] } diff --git a/src/frontend/src/optimizer/plan_node/logical_hop_window.rs b/src/frontend/src/optimizer/plan_node/logical_hop_window.rs index a1f13c3dd872a..3c9f5c972407a 100644 --- a/src/frontend/src/optimizer/plan_node/logical_hop_window.rs +++ b/src/frontend/src/optimizer/plan_node/logical_hop_window.rs @@ -317,6 +317,7 @@ impl ColPrunable for LogicalHopWindow { impl PredicatePushdown for LogicalHopWindow { fn predicate_pushdown(&self, predicate: Condition) -> PlanRef { + // TODO: hop's predicate pushdown https://github.com/risingwavelabs/risingwave/issues/6606 gen_filter_and_pushdown(self, predicate, Condition::true_cond()) } } diff --git a/src/frontend/src/optimizer/plan_node/logical_limit.rs b/src/frontend/src/optimizer/plan_node/logical_limit.rs index 652526277622c..f92cc853097ff 100644 --- a/src/frontend/src/optimizer/plan_node/logical_limit.rs +++ b/src/frontend/src/optimizer/plan_node/logical_limit.rs @@ -98,6 +98,7 @@ impl ColPrunable for LogicalLimit { impl PredicatePushdown for LogicalLimit { fn predicate_pushdown(&self, predicate: Condition) -> PlanRef { + // filter can not transpose limit gen_filter_and_pushdown(self, predicate, Condition::true_cond()) } } diff --git a/src/frontend/src/optimizer/plan_node/logical_topn.rs b/src/frontend/src/optimizer/plan_node/logical_topn.rs index 4345c69803f8a..13be73cdd4385 100644 --- a/src/frontend/src/optimizer/plan_node/logical_topn.rs +++ b/src/frontend/src/optimizer/plan_node/logical_topn.rs @@ -352,6 +352,7 @@ impl ColPrunable for LogicalTopN { impl PredicatePushdown for LogicalTopN { fn predicate_pushdown(&self, predicate: Condition) -> PlanRef { + // filter can not transpose topN gen_filter_and_pushdown(self, predicate, Condition::true_cond()) } }