aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/prep/prepjointree.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/prep/prepjointree.c')
-rw-r--r--src/backend/optimizer/prep/prepjointree.c36
1 files changed, 23 insertions, 13 deletions
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index aeaae8c8d87..8bb011b7116 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -784,22 +784,15 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
parse->havingQual = pullup_replace_vars(parse->havingQual, &rvcontext);
/*
- * Replace references in the translated_vars lists of appendrels. When
- * pulling up an appendrel member, we do not need PHVs in the list of the
- * parent appendrel --- there isn't any outer join between. Elsewhere, use
- * PHVs for safety. (This analysis could be made tighter but it seems
- * unlikely to be worth much trouble.)
+ * Replace references in the translated_vars lists of appendrels, too.
+ * We do it this way because we must preserve the AppendRelInfo structs.
*/
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
- bool save_need_phvs = rvcontext.need_phvs;
- if (appinfo == containing_appendrel)
- rvcontext.need_phvs = false;
appinfo->translated_vars = (List *)
pullup_replace_vars((Node *) appinfo->translated_vars, &rvcontext);
- rvcontext.need_phvs = save_need_phvs;
}
/*
@@ -1407,14 +1400,31 @@ pullup_replace_vars_callback(Var *var,
if (newnode && IsA(newnode, Var) &&
((Var *) newnode)->varlevelsup == 0)
{
- /* Simple Vars always escape being wrapped */
- wrap = false;
+ /*
+ * Simple Vars normally escape being wrapped. However, in
+ * wrap_non_vars mode (ie, we are dealing with an appendrel
+ * member), we must ensure that each tlist entry expands to a
+ * distinct expression, else we may have problems with
+ * improperly placing identical entries into different
+ * EquivalenceClasses. Therefore, we wrap a Var in a
+ * PlaceHolderVar if it duplicates any earlier entry in the
+ * tlist (ie, we've got "SELECT x, x, ..."). Since each PHV
+ * is distinct, this fixes the ambiguity. We can use
+ * tlist_member to detect whether there's an earlier
+ * duplicate.
+ */
+ wrap = (rcon->wrap_non_vars &&
+ tlist_member(newnode, rcon->targetlist) != tle);
}
else if (newnode && IsA(newnode, PlaceHolderVar) &&
((PlaceHolderVar *) newnode)->phlevelsup == 0)
{
- /* No need to wrap a PlaceHolderVar with another one, either */
- wrap = false;
+ /*
+ * No need to directly wrap a PlaceHolderVar with another one,
+ * either, unless we need to prevent duplication.
+ */
+ wrap = (rcon->wrap_non_vars &&
+ tlist_member(newnode, rcon->targetlist) != tle);
}
else if (rcon->wrap_non_vars)
{