mirror of
https://github.com/postgres/postgres.git
synced 2025-11-06 07:49:08 +03:00
Another round of planner fixes for LATERAL.
Formerly, subquery pullup had no need to examine other entries in the range table, since they could not contain any references to the subquery being pulled up. That's no longer true with LATERAL, so now we need to be able to visit rangetable subexpressions to replace Vars referencing the pulled-up subquery. Also, this means that extract_lateral_references must be unsurprised at encountering lateral PlaceHolderVars, since such might be created when pulling up a subquery that's underneath an outer join with respect to the lateral reference.
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user