From febe013cad5992ba8994db309cd1b7d85062c6d3 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 17 Sep 2021 15:41:16 -0400 Subject: 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 --- src/backend/optimizer/util/var.c | 41 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) (limited to 'src/backend/optimizer/util/var.c') diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 58d093c1c11..101b56d03f8 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -200,6 +200,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; @@ -215,12 +225,37 @@ pull_varnos_walker(Node *node, pull_varnos_context *context) phinfo = NULL; } } - if (phinfo != NULL) + 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 - context->varnos = bms_add_members(context->varnos, - phv->phrels); + { + /* 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 */ } } -- cgit v1.2.3