Fix 'negative bitmapset member' error

When removing a useless join, we'd remove PHVs that are not used at join
partner rels or above the join.  A PHV that references the join's relid
in ph_eval_at is logically "above" the join and thus should not be
removed.  We have the following check for that:

    !bms_is_member(ojrelid, phinfo->ph_eval_at)

However, in the case of SJE removing a useless inner join, 'ojrelid' is
set to -1, which would trigger the "negative bitmapset member not
allowed" error in bms_is_member().

Fix it by skipping examining ojrelid for inner joins in this check.

Reported-by: Zuming Jiang
Bug: #18260
Discussion: https://postgr.es/m/18260-1b6a0c4ae311b837%40postgresql.org
Author: Richard Guo
Reviewed-by: Andrei Lepikhov
This commit is contained in:
Alexander Korotkov 2024-01-15 17:45:16 +02:00
parent aa817c7496
commit fe093994db
3 changed files with 29 additions and 1 deletions

View File

@ -456,7 +456,7 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
Assert(sjinfo == NULL || !bms_is_member(relid, phinfo->ph_lateral));
if (bms_is_subset(phinfo->ph_needed, joinrelids) &&
bms_is_member(relid, phinfo->ph_eval_at) &&
!bms_is_member(ojrelid, phinfo->ph_eval_at))
(sjinfo == NULL || !bms_is_member(ojrelid, phinfo->ph_eval_at)))
{
root->placeholder_list = foreach_delete_current(root->placeholder_list,
l);

View File

@ -6821,6 +6821,26 @@ on true;
Filter: (id IS NOT NULL)
(8 rows)
-- Check that SJE removes the whole PHVs correctly
explain (verbose, costs off)
select 1 from emp1 t1 left join
((select 1 as x, * from emp1 t2) s1 inner join
(select * from emp1 t3) s2 on s1.id = s2.id)
on true
where s1.x = 1;
QUERY PLAN
---------------------------------------------------------
Nested Loop
Output: 1
-> Seq Scan on public.emp1 t1
Output: t1.id, t1.code
-> Materialize
Output: t3.id
-> Seq Scan on public.emp1 t3
Output: t3.id
Filter: ((t3.id IS NOT NULL) AND (1 = 1))
(9 rows)
-- Check that PHVs do not impose any constraints on removing self joins
explain (verbose, costs off)
select * from emp1 t1 join emp1 t2 on t1.id = t2.id left join

View File

@ -2600,6 +2600,14 @@ select * from emp1 t1 left join
on true)
on true;
-- Check that SJE removes the whole PHVs correctly
explain (verbose, costs off)
select 1 from emp1 t1 left join
((select 1 as x, * from emp1 t2) s1 inner join
(select * from emp1 t3) s2 on s1.id = s2.id)
on true
where s1.x = 1;
-- Check that PHVs do not impose any constraints on removing self joins
explain (verbose, costs off)
select * from emp1 t1 join emp1 t2 on t1.id = t2.id left join