diff options
Diffstat (limited to 'src/backend/optimizer/util/var.c')
-rw-r--r-- | src/backend/optimizer/util/var.c | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index e307d6fbb07..e57c3aa1244 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -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) + 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 */ } } |