Skip to content

Commit 8c7bb02

Browse files
committed
Fix old oversight in join removal logic.
Commit 9e7e29c introduced an Assert that join removal didn't reduce the eval_at set of any PlaceHolderVar to empty. At first glance it looks like join_is_removable ensures that's true --- but actually, the loop in join_is_removable skips PlaceHolderVars that are not referenced above the join due to be removed. So, if we don't want any empty eval_at sets, the right thing to do is to delete any now-unreferenced PlaceHolderVars from the data structure entirely. Per fuzz testing by Andreas Seltenreich. Back-patch to 9.3 where the aforesaid Assert was added.
1 parent d31e794 commit 8c7bb02

File tree

3 files changed

+45
-6
lines changed

3 files changed

+45
-6
lines changed

src/backend/optimizer/plan/analyzejoins.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -382,16 +382,24 @@ remove_rel_from_query(PlannerInfo *root, int relid, Relids joinrelids)
382382
}
383383

384384
/*
385-
* Likewise remove references from PlaceHolderVar data structures.
385+
* Likewise remove references from PlaceHolderVar data structures,
386+
* removing any no-longer-needed placeholders entirely.
386387
*/
387-
foreach(l, root->placeholder_list)
388+
for (l = list_head(root->placeholder_list); l != NULL; l = nextl)
388389
{
389390
PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l);
390391

391-
phinfo->ph_eval_at = bms_del_member(phinfo->ph_eval_at, relid);
392-
Assert(!bms_is_empty(phinfo->ph_eval_at));
393-
Assert(!bms_is_member(relid, phinfo->ph_lateral));
394-
phinfo->ph_needed = bms_del_member(phinfo->ph_needed, relid);
392+
nextl = lnext(l);
393+
if (bms_is_subset(phinfo->ph_needed, joinrelids))
394+
root->placeholder_list = list_delete_ptr(root->placeholder_list,
395+
phinfo);
396+
else
397+
{
398+
phinfo->ph_eval_at = bms_del_member(phinfo->ph_eval_at, relid);
399+
Assert(!bms_is_empty(phinfo->ph_eval_at));
400+
Assert(!bms_is_member(relid, phinfo->ph_lateral));
401+
phinfo->ph_needed = bms_del_member(phinfo->ph_needed, relid);
402+
}
395403
}
396404

397405
/*

src/test/regress/expected/join.out

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3743,6 +3743,22 @@ SELECT * FROM
37433743
1 | 4567890123456789 | -4567890123456789 | 4567890123456789
37443744
(5 rows)
37453745

3746+
rollback;
3747+
-- another join removal bug: we must clean up correctly when removing a PHV
3748+
begin;
3749+
create temp table uniquetbl (f1 text unique);
3750+
explain (costs off)
3751+
select t1.* from
3752+
uniquetbl as t1
3753+
left join (select *, '***'::text as d1 from uniquetbl) t2
3754+
on t1.f1 = t2.f1
3755+
left join uniquetbl t3
3756+
on t2.d1 = t3.f1;
3757+
QUERY PLAN
3758+
--------------------------
3759+
Seq Scan on uniquetbl t1
3760+
(1 row)
3761+
37463762
rollback;
37473763
-- bug #8444: we've historically allowed duplicate aliases within aliased JOINs
37483764
select * from

src/test/regress/sql/join.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,21 @@ SELECT * FROM
11961196

11971197
rollback;
11981198

1199+
-- another join removal bug: we must clean up correctly when removing a PHV
1200+
begin;
1201+
1202+
create temp table uniquetbl (f1 text unique);
1203+
1204+
explain (costs off)
1205+
select t1.* from
1206+
uniquetbl as t1
1207+
left join (select *, '***'::text as d1 from uniquetbl) t2
1208+
on t1.f1 = t2.f1
1209+
left join uniquetbl t3
1210+
on t2.d1 = t3.f1;
1211+
1212+
rollback;
1213+
11991214
-- bug #8444: we've historically allowed duplicate aliases within aliased JOINs
12001215

12011216
select * from

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy