diff options
Diffstat (limited to 'src/backend/optimizer/prep/prepjointree.c')
-rw-r--r-- | src/backend/optimizer/prep/prepjointree.c | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index f5deed4bc82..d72c78f8db4 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -89,6 +89,8 @@ static Node *pullup_replace_vars(Node *expr, pullup_replace_vars_context *context); static Node *pullup_replace_vars_callback(Var *var, replace_rte_variables_context *context); +static Query *pullup_replace_vars_subquery(Query *query, + pullup_replace_vars_context *context); static reduce_outer_joins_state *reduce_outer_joins_pass1(Node *jtnode); static void reduce_outer_joins_pass2(Node *jtnode, reduce_outer_joins_state *state, @@ -1472,7 +1474,50 @@ replace_vars_in_jointree(Node *jtnode, return; if (IsA(jtnode, RangeTblRef)) { - /* nothing to do here */ + /* + * If the RangeTblRef refers to a LATERAL subquery (that isn't the + * same subquery we're pulling up), it might contain references to the + * target subquery, which we must replace. We drive this from the + * jointree scan, rather than a scan of the rtable, for a couple of + * reasons: we can avoid processing no-longer-referenced RTEs, and we + * can use the appropriate setting of need_phvs depending on whether + * the RTE is above possibly-nulling outer joins or not. + */ + int varno = ((RangeTblRef *) jtnode)->rtindex; + + if (varno != context->varno) /* ignore target subquery itself */ + { + RangeTblEntry *rte = rt_fetch(varno, context->root->parse->rtable); + + Assert(rte != context->target_rte); + if (rte->lateral) + { + switch (rte->rtekind) + { + case RTE_SUBQUERY: + rte->subquery = + pullup_replace_vars_subquery(rte->subquery, + context); + break; + case RTE_FUNCTION: + rte->funcexpr = + pullup_replace_vars(rte->funcexpr, + context); + break; + case RTE_VALUES: + rte->values_lists = (List *) + pullup_replace_vars((Node *) rte->values_lists, + context); + break; + case RTE_RELATION: + case RTE_JOIN: + case RTE_CTE: + /* these shouldn't be marked LATERAL */ + Assert(false); + break; + } + } + } } else if (IsA(jtnode, FromExpr)) { @@ -1695,6 +1740,25 @@ pullup_replace_vars_callback(Var *var, return newnode; } +/* + * Apply pullup variable replacement to a subquery + * + * This needs to be different from pullup_replace_vars() because + * replace_rte_variables will think that it shouldn't increment sublevels_up + * before entering the Query; so we need to call it with sublevels_up == 1. + */ +static Query * +pullup_replace_vars_subquery(Query *query, + pullup_replace_vars_context *context) +{ + Assert(IsA(query, Query)); + return (Query *) replace_rte_variables((Node *) query, + context->varno, 1, + pullup_replace_vars_callback, + (void *) context, + NULL); +} + /* * flatten_simple_union_all |