aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/var.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/var.c')
-rw-r--r--src/backend/optimizer/util/var.c41
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 */
}
}