1
0
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:
Tom Lane
2021-09-17 15:41:16 -04:00
parent cddcf7842c
commit a21049fd3f
3 changed files with 83 additions and 4 deletions

View File

@@ -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 */
}
}