aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-09-17 15:41:16 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-09-17 15:41:16 -0400
commita21049fd3f64518c8a7227cf07c56f2543241db2 (patch)
tree77bf24d154b3884faea705820e1919e9d66ba767 /src/backend
parentcddcf7842c31b4d07ca75439f6b4ddacaadbbd0d (diff)
downloadpostgresql-a21049fd3f64518c8a7227cf07c56f2543241db2.tar.gz
postgresql-a21049fd3f64518c8a7227cf07c56f2543241db2.zip
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
Diffstat (limited to 'src/backend')
-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 */
}
}