Fix oversight in outer join removal.
A placeholder that references the outer join's relid in ph_eval_at is logically "above" the join, and therefore we can't remove its PlaceHolderInfo: it might still be used somewhere in the query. This was not an issue pre-v16 because we failed to remove the join at all in such cases. The new outer-join-aware-Var infrastructure permits deducing that it's okay to remove the join, but then we have to clean up correctly afterwards. Report and fix by Richard Guo Discussion: https://postgr.es/m/CAMbWs4_tuVn9EwwMcggGiZJWWstdXX_ci8FeEU17vs+4nLgw3w@mail.gmail.com
This commit is contained in:
parent
fbf80421ea
commit
9a2dbc614e
@ -425,7 +425,8 @@ remove_rel_from_query(PlannerInfo *root, int relid, SpecialJoinInfo *sjinfo)
|
|||||||
|
|
||||||
Assert(!bms_is_member(relid, phinfo->ph_lateral));
|
Assert(!bms_is_member(relid, phinfo->ph_lateral));
|
||||||
if (bms_is_subset(phinfo->ph_needed, joinrelids) &&
|
if (bms_is_subset(phinfo->ph_needed, joinrelids) &&
|
||||||
bms_is_member(relid, phinfo->ph_eval_at))
|
bms_is_member(relid, phinfo->ph_eval_at) &&
|
||||||
|
!bms_is_member(ojrelid, phinfo->ph_eval_at))
|
||||||
{
|
{
|
||||||
root->placeholder_list = foreach_delete_current(root->placeholder_list,
|
root->placeholder_list = foreach_delete_current(root->placeholder_list,
|
||||||
l);
|
l);
|
||||||
|
@ -5842,6 +5842,63 @@ where ss.stringu2 !~* ss.case1;
|
|||||||
doh!
|
doh!
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
-- test cases where we can remove a join, but not a PHV computed at it
|
||||||
|
begin;
|
||||||
|
create temp table t (a int unique, b int);
|
||||||
|
insert into t values (1,1), (2,2);
|
||||||
|
explain (costs off)
|
||||||
|
select 1
|
||||||
|
from t t1
|
||||||
|
left join (select t2.a, 1 as c
|
||||||
|
from t t2 left join t t3 on t2.a = t3.a) s
|
||||||
|
on true
|
||||||
|
left join t t4 on true
|
||||||
|
where s.a < s.c;
|
||||||
|
QUERY PLAN
|
||||||
|
-------------------------------------
|
||||||
|
Nested Loop Left Join
|
||||||
|
-> Nested Loop
|
||||||
|
-> Seq Scan on t t1
|
||||||
|
-> Materialize
|
||||||
|
-> Seq Scan on t t2
|
||||||
|
Filter: (a < 1)
|
||||||
|
-> Materialize
|
||||||
|
-> Seq Scan on t t4
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
|
explain (costs off)
|
||||||
|
select t1.a, s.*
|
||||||
|
from t t1
|
||||||
|
left join lateral (select t2.a, coalesce(t1.a, 1) as c
|
||||||
|
from t t2 left join t t3 on t2.a = t3.a) s
|
||||||
|
on true
|
||||||
|
left join t t4 on true
|
||||||
|
where s.a < s.c;
|
||||||
|
QUERY PLAN
|
||||||
|
-----------------------------------------------
|
||||||
|
Nested Loop Left Join
|
||||||
|
-> Nested Loop
|
||||||
|
-> Seq Scan on t t1
|
||||||
|
-> Seq Scan on t t2
|
||||||
|
Filter: (a < COALESCE(t1.a, 1))
|
||||||
|
-> Materialize
|
||||||
|
-> Seq Scan on t t4
|
||||||
|
(7 rows)
|
||||||
|
|
||||||
|
select t1.a, s.*
|
||||||
|
from t t1
|
||||||
|
left join lateral (select t2.a, coalesce(t1.a, 1) as c
|
||||||
|
from t t2 left join t t3 on t2.a = t3.a) s
|
||||||
|
on true
|
||||||
|
left join t t4 on true
|
||||||
|
where s.a < s.c;
|
||||||
|
a | a | c
|
||||||
|
---+---+---
|
||||||
|
2 | 1 | 2
|
||||||
|
2 | 1 | 2
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
rollback;
|
rollback;
|
||||||
-- test case to expose miscomputation of required relid set for a PHV
|
-- test case to expose miscomputation of required relid set for a PHV
|
||||||
explain (verbose, costs off)
|
explain (verbose, costs off)
|
||||||
|
@ -2153,6 +2153,40 @@ where ss.stringu2 !~* ss.case1;
|
|||||||
|
|
||||||
rollback;
|
rollback;
|
||||||
|
|
||||||
|
-- test cases where we can remove a join, but not a PHV computed at it
|
||||||
|
begin;
|
||||||
|
|
||||||
|
create temp table t (a int unique, b int);
|
||||||
|
insert into t values (1,1), (2,2);
|
||||||
|
|
||||||
|
explain (costs off)
|
||||||
|
select 1
|
||||||
|
from t t1
|
||||||
|
left join (select t2.a, 1 as c
|
||||||
|
from t t2 left join t t3 on t2.a = t3.a) s
|
||||||
|
on true
|
||||||
|
left join t t4 on true
|
||||||
|
where s.a < s.c;
|
||||||
|
|
||||||
|
explain (costs off)
|
||||||
|
select t1.a, s.*
|
||||||
|
from t t1
|
||||||
|
left join lateral (select t2.a, coalesce(t1.a, 1) as c
|
||||||
|
from t t2 left join t t3 on t2.a = t3.a) s
|
||||||
|
on true
|
||||||
|
left join t t4 on true
|
||||||
|
where s.a < s.c;
|
||||||
|
|
||||||
|
select t1.a, s.*
|
||||||
|
from t t1
|
||||||
|
left join lateral (select t2.a, coalesce(t1.a, 1) as c
|
||||||
|
from t t2 left join t t3 on t2.a = t3.a) s
|
||||||
|
on true
|
||||||
|
left join t t4 on true
|
||||||
|
where s.a < s.c;
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
|
||||||
-- test case to expose miscomputation of required relid set for a PHV
|
-- test case to expose miscomputation of required relid set for a PHV
|
||||||
explain (verbose, costs off)
|
explain (verbose, costs off)
|
||||||
select i8.*, ss.v, t.unique2
|
select i8.*, ss.v, t.unique2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user