0001-Avoid-pulling-up-restrict-infos-from-subqueries.patch
text/x-diff
Filename: 0001-Avoid-pulling-up-restrict-infos-from-subqueries.patch
Type: text/x-diff
Part: 0
From 04c89be4b2802a0b51b10ca4828108a338c77e71 Mon Sep 17 00:00:00 2001 From: Alexander Pyhalov <a.pyhalov@postgrespro.ru> Date: Tue, 18 Mar 2025 13:46:08 +0300 Subject: [PATCH] Avoid pulling up restrict infos from subqueries Semi-join joins below left/right join are deparsed as subqueries. We can't refer to subqueries vars from upper relations, so avoid pulling conditions from them. --- .../postgres_fdw/expected/postgres_fdw.out | 39 +++++++++++++++++++ contrib/postgres_fdw/postgres_fdw.c | 22 +++++++++-- contrib/postgres_fdw/sql/postgres_fdw.sql | 18 +++++++++ 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index bb4ed3059c4..88385e06f31 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -4936,6 +4936,45 @@ SELECT ft2.*, ft4.* FROM ft2 INNER JOIN ----+----+----+----+----+----+----+----+----+----+---- (0 rows) +-- semi-join conditions shouldn't pop up as +-- left/right join join clause +set enable_material to off; +EXPLAIN (verbose, costs off) + SELECT NULL FROM + (SELECT * FROM ft2 WHERE EXISTS (SELECT 1 FROM ft4 WHERE ft2.c1 < 10)) + RIGHT JOIN + (SELECT * FROM ft2 WHERE EXISTS (SELECT 1 FROM ft4 WHERE ft2.c1 < 10)) + ON (TRUE) +LIMIT 10; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: NULL::text + Relations: ((public.ft2 ft2_1) SEMI JOIN (public.ft4 ft4_1)) LEFT JOIN ((public.ft2) SEMI JOIN (public.ft4)) + Remote SQL: SELECT NULL FROM ((SELECT NULL FROM "S 1"."T 1" r6 WHERE ((r6."C 1" < 10)) AND EXISTS (SELECT NULL FROM "S 1"."T 3" r7)) s8 LEFT JOIN (SELECT NULL FROM "S 1"."T 1" r4 WHERE ((r4."C 1" < 10)) AND EXISTS (SELECT NULL FROM "S 1"."T 3" r5)) s9 ON (TRUE)) LIMIT 10::bigint +(4 rows) + +SELECT NULL FROM + (SELECT * FROM ft2 WHERE EXISTS (SELECT 1 FROM ft4 WHERE ft2.c1 < 10)) + RIGHT JOIN + (SELECT * FROM ft2 WHERE EXISTS (SELECT 1 FROM ft4 WHERE ft2.c1 < 10)) + ON (TRUE) +LIMIT 10; + ?column? +---------- + + + + + + + + + + +(10 rows) + +reset enable_material; -- Can't push down semi-join with inner rel vars in targetlist EXPLAIN (verbose, costs off) SELECT ft1.c1 FROM ft1 JOIN ft2 on ft1.c1 = ft2.c1 WHERE diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 1131a8bf77e..8af8b802a24 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -5964,16 +5964,30 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, break; case JOIN_LEFT: - fpinfo->joinclauses = list_concat(fpinfo->joinclauses, + /* + * When semi-join is involved in inner or outer part of left join, + * it's deparsed as a subquery and we can't refer to its vars + * on upper level + */ + if (bms_is_empty(fpinfo_i->hidden_subquery_rels)) + fpinfo->joinclauses = list_concat(fpinfo->joinclauses, fpinfo_i->remote_conds); - fpinfo->remote_conds = list_concat(fpinfo->remote_conds, + if (bms_is_empty(fpinfo_o->hidden_subquery_rels)) + fpinfo->remote_conds = list_concat(fpinfo->remote_conds, fpinfo_o->remote_conds); break; case JOIN_RIGHT: - fpinfo->joinclauses = list_concat(fpinfo->joinclauses, + /* + * When semi-join is involved in inner or outer part of right join, + * it's deparsed as a subquery and we can't refer to its vars + * on upper level + */ + if (bms_is_empty(fpinfo_o->hidden_subquery_rels)) + fpinfo->joinclauses = list_concat(fpinfo->joinclauses, fpinfo_o->remote_conds); - fpinfo->remote_conds = list_concat(fpinfo->remote_conds, + if (bms_is_empty(fpinfo_i->hidden_subquery_rels)) + fpinfo->remote_conds = list_concat(fpinfo->remote_conds, fpinfo_i->remote_conds); break; diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index d45e9f8ab52..faedeab9d41 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -1455,6 +1455,24 @@ SELECT ft2.*, ft4.* FROM ft2 INNER JOIN WHERE ft2.c1 > 900 ORDER BY ft2.c1 LIMIT 10; +-- semi-join conditions shouldn't pop up as +-- left/right join join clause +set enable_material to off; +EXPLAIN (verbose, costs off) + SELECT NULL FROM + (SELECT * FROM ft2 WHERE EXISTS (SELECT 1 FROM ft4 WHERE ft2.c1 < 10)) + RIGHT JOIN + (SELECT * FROM ft2 WHERE EXISTS (SELECT 1 FROM ft4 WHERE ft2.c1 < 10)) + ON (TRUE) +LIMIT 10; +SELECT NULL FROM + (SELECT * FROM ft2 WHERE EXISTS (SELECT 1 FROM ft4 WHERE ft2.c1 < 10)) + RIGHT JOIN + (SELECT * FROM ft2 WHERE EXISTS (SELECT 1 FROM ft4 WHERE ft2.c1 < 10)) + ON (TRUE) +LIMIT 10; +reset enable_material; + -- Can't push down semi-join with inner rel vars in targetlist EXPLAIN (verbose, costs off) SELECT ft1.c1 FROM ft1 JOIN ft2 on ft1.c1 = ft2.c1 WHERE -- 2.43.0