1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-19 15:49:24 +03:00

Disallow removing placeholders during Self-Join Elimination.

fc069a3a63 implements Self-Join Elimination (SJE), which can remove base
relations when appropriate.  However, regressions tests for SJE only cover
the case when placeholder variables (PHVs) are evaluated and needed only
in a single base rel.  If this baserel is removed due to SJE, its clauses,
including PHVs, will be transferred to the keeping relation.  Removing these
PHVs may trigger an error on plan creation -- thanks to the b3ff6c742f for
detecting that.

This commit skips removal of PHVs during SJE.  This might also happen that
we skip the removal of some PHVs that could be removed.  However, the overhead
of extra PHVs is small compared to the complexity of analysis needed to remove
them.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Alena Rybakina <a.rybakina@postgrespro.ru>
Author: Andrei Lepikhov <lepihov@gmail.com>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Reviewed-by: Richard Guo <guofenglinux@gmail.com>
This commit is contained in:
Alexander Korotkov
2025-04-28 01:40:42 +03:00
parent 2f5b056203
commit 1aa7cf9eb8
3 changed files with 69 additions and 5 deletions

View File

@@ -403,7 +403,12 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
/*
* Likewise remove references from PlaceHolderVar data structures,
* removing any no-longer-needed placeholders entirely.
* removing any no-longer-needed placeholders entirely. We remove PHV
* only for left-join removal. With self-join elimination, PHVs already
* get moved to the remaining relation, where they might still be needed.
* It might also happen that we skip the removal of some PHVs that could
* be removed. However, the overhead of extra PHVs is small compared to
* the complexity of analysis needed to remove them.
*
* Removal is a bit trickier than it might seem: we can remove PHVs that
* are used at the target rel and/or in the join qual, but not those that
@@ -420,10 +425,16 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l);
Assert(sjinfo == NULL || !bms_is_member(relid, phinfo->ph_lateral));
if (bms_is_subset(phinfo->ph_needed, joinrelids) &&
if (sjinfo != NULL &&
bms_is_subset(phinfo->ph_needed, joinrelids) &&
bms_is_member(relid, phinfo->ph_eval_at) &&
(sjinfo == NULL || !bms_is_member(sjinfo->ojrelid, phinfo->ph_eval_at)))
!bms_is_member(sjinfo->ojrelid, phinfo->ph_eval_at))
{
/*
* This code shouldn't be executed if one relation is substituted
* with another: in this case, the placeholder may be employed in
* a filter inside the scan node the SJE removes.
*/
root->placeholder_list = foreach_delete_current(root->placeholder_list,
l);
root->placeholder_array[phinfo->phid] = NULL;