mirror of
https://github.com/postgres/postgres.git
synced 2025-08-27 07:42:10 +03:00
Fix pull_varnos to cope with translated PlaceHolderVars.
Commit 55dc86eca
changed pull_varnos to use (if possible) the associated
ph_eval_at for a PlaceHolderVar. I missed a fine point though: we might
be looking at a PHV in the quals or tlist of a child appendrel, in which
case we need to compute a ph_eval_at value that's been translated in the
same way that the PHV itself has been (cf. adjust_appendrel_attrs).
Fortunately, enough info is available in the PlaceHolderInfo to make
such translation possible without additional outside data, so we don't
need another round of uglification of planner APIs. This is a little
bit complicated, but since it's a hard-to-hit corner case, I'm not much
worried about adding cycles here.
Per report from Jaime Casanova. Back-patch to v12, like the previous
commit.
Discussion: https://postgr.es/m/20210915230959.GB17635@ahch-to
This commit is contained in:
@@ -188,6 +188,16 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
|
||||
* join that forces delay of evaluation of a given qual clause
|
||||
* will be processed before we examine that clause here, so the
|
||||
* ph_eval_at value should have been updated to include it.
|
||||
*
|
||||
* Another problem is that a PlaceHolderVar can appear in quals or
|
||||
* tlists that have been translated for use in a child appendrel.
|
||||
* Typically such a PHV is a parameter expression sourced by some
|
||||
* other relation, so that the translation from parent appendrel
|
||||
* to child doesn't change its phrels, and we should still take
|
||||
* ph_eval_at at face value. But in corner cases, the PHV's
|
||||
* original phrels can include the parent appendrel itself, in
|
||||
* which case the translated PHV will have the child appendrel in
|
||||
* phrels, and we must translate ph_eval_at to match.
|
||||
*/
|
||||
PlaceHolderInfo *phinfo = NULL;
|
||||
|
||||
@@ -203,12 +213,37 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
|
||||
phinfo = NULL;
|
||||
}
|
||||
}
|
||||
if (phinfo != NULL)
|
||||
context->varnos = bms_add_members(context->varnos,
|
||||
phinfo->ph_eval_at);
|
||||
else
|
||||
if (phinfo == NULL)
|
||||
{
|
||||
/* No PlaceHolderInfo yet, use phrels */
|
||||
context->varnos = bms_add_members(context->varnos,
|
||||
phv->phrels);
|
||||
}
|
||||
else if (bms_equal(phv->phrels, phinfo->ph_var->phrels))
|
||||
{
|
||||
/* Normal case: use ph_eval_at */
|
||||
context->varnos = bms_add_members(context->varnos,
|
||||
phinfo->ph_eval_at);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Translated PlaceHolderVar: translate ph_eval_at to match */
|
||||
Relids newevalat,
|
||||
delta;
|
||||
|
||||
/* remove what was removed from phv->phrels ... */
|
||||
delta = bms_difference(phinfo->ph_var->phrels, phv->phrels);
|
||||
newevalat = bms_difference(phinfo->ph_eval_at, delta);
|
||||
/* ... then if that was in fact part of ph_eval_at ... */
|
||||
if (!bms_equal(newevalat, phinfo->ph_eval_at))
|
||||
{
|
||||
/* ... add what was added */
|
||||
delta = bms_difference(phv->phrels, phinfo->ph_var->phrels);
|
||||
newevalat = bms_join(newevalat, delta);
|
||||
}
|
||||
context->varnos = bms_join(context->varnos,
|
||||
newevalat);
|
||||
}
|
||||
return false; /* don't recurse into expression */
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user