Revise searching of subplan target lists to use something more efficient

than tlist_member calls.  Building a large join tlist is still O(N^2),
but with a much smaller constant factor than before.
This commit is contained in:
Tom Lane 2005-06-10 00:28:54 +00:00
parent 0725065b37
commit 39cee73889
1 changed files with 248 additions and 194 deletions

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.110 2005/05/22 22:30:19 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.111 2005/06/10 00:28:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -25,20 +25,34 @@
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
typedef struct
{
Index varno; /* RT index of Var */
AttrNumber varattno; /* attr number of Var */
AttrNumber resno; /* TLE position of Var */
} tlist_vinfo;
typedef struct
{
List *tlist; /* underlying target list */
int num_vars; /* number of plain Var tlist entries */
bool has_non_vars; /* are there non-plain-Var entries? */
/* array of num_vars entries: */
tlist_vinfo vars[1]; /* VARIABLE LENGTH ARRAY */
} indexed_tlist; /* VARIABLE LENGTH STRUCT */
typedef struct typedef struct
{ {
List *rtable; List *rtable;
List *outer_tlist; indexed_tlist *outer_itlist;
List *inner_tlist; indexed_tlist *inner_itlist;
Index acceptable_rel; Index acceptable_rel;
bool tlists_have_non_vars;
} join_references_context; } join_references_context;
typedef struct typedef struct
{ {
indexed_tlist *subplan_itlist;
Index subvarno; Index subvarno;
List *subplan_targetlist;
bool tlist_has_non_vars;
} replace_vars_with_subplan_refs_context; } replace_vars_with_subplan_refs_context;
static Plan *set_subqueryscan_references(SubqueryScan *plan, List *rtable); static Plan *set_subqueryscan_references(SubqueryScan *plan, List *rtable);
@ -51,22 +65,25 @@ static bool fix_expr_references_walker(Node *node, void *context);
static void set_join_references(Join *join, List *rtable); static void set_join_references(Join *join, List *rtable);
static void set_inner_join_references(Plan *inner_plan, static void set_inner_join_references(Plan *inner_plan,
List *rtable, List *rtable,
List *outer_tlist, indexed_tlist *outer_itlist);
bool tlists_have_non_vars);
static void set_uppernode_references(Plan *plan, Index subvarno); static void set_uppernode_references(Plan *plan, Index subvarno);
static bool targetlist_has_non_vars(List *tlist); static indexed_tlist *build_tlist_index(List *tlist);
static Var *search_indexed_tlist_for_var(Var *var,
indexed_tlist *itlist,
Index newvarno);
static Var *search_indexed_tlist_for_non_var(Node *node,
indexed_tlist *itlist,
Index newvarno);
static List *join_references(List *clauses, static List *join_references(List *clauses,
List *rtable, List *rtable,
List *outer_tlist, indexed_tlist *outer_itlist,
List *inner_tlist, indexed_tlist *inner_itlist,
Index acceptable_rel, Index acceptable_rel);
bool tlists_have_non_vars);
static Node *join_references_mutator(Node *node, static Node *join_references_mutator(Node *node,
join_references_context *context); join_references_context *context);
static Node *replace_vars_with_subplan_refs(Node *node, static Node *replace_vars_with_subplan_refs(Node *node,
Index subvarno, indexed_tlist *subplan_itlist,
List *subplan_targetlist, Index subvarno);
bool tlist_has_non_vars);
static Node *replace_vars_with_subplan_refs_mutator(Node *node, static Node *replace_vars_with_subplan_refs_mutator(Node *node,
replace_vars_with_subplan_refs_context *context); replace_vars_with_subplan_refs_context *context);
static bool fix_opfuncids_walker(Node *node, void *context); static bool fix_opfuncids_walker(Node *node, void *context);
@ -689,32 +706,28 @@ set_join_references(Join *join, List *rtable)
{ {
Plan *outer_plan = join->plan.lefttree; Plan *outer_plan = join->plan.lefttree;
Plan *inner_plan = join->plan.righttree; Plan *inner_plan = join->plan.righttree;
List *outer_tlist = outer_plan->targetlist; indexed_tlist *outer_itlist;
List *inner_tlist = inner_plan->targetlist; indexed_tlist *inner_itlist;
bool tlists_have_non_vars;
tlists_have_non_vars = targetlist_has_non_vars(outer_tlist) || outer_itlist = build_tlist_index(outer_plan->targetlist);
targetlist_has_non_vars(inner_tlist); inner_itlist = build_tlist_index(inner_plan->targetlist);
/* All join plans have tlist, qual, and joinqual */ /* All join plans have tlist, qual, and joinqual */
join->plan.targetlist = join_references(join->plan.targetlist, join->plan.targetlist = join_references(join->plan.targetlist,
rtable, rtable,
outer_tlist, outer_itlist,
inner_tlist, inner_itlist,
(Index) 0, (Index) 0);
tlists_have_non_vars);
join->plan.qual = join_references(join->plan.qual, join->plan.qual = join_references(join->plan.qual,
rtable, rtable,
outer_tlist, outer_itlist,
inner_tlist, inner_itlist,
(Index) 0, (Index) 0);
tlists_have_non_vars);
join->joinqual = join_references(join->joinqual, join->joinqual = join_references(join->joinqual,
rtable, rtable,
outer_tlist, outer_itlist,
inner_tlist, inner_itlist,
(Index) 0, (Index) 0);
tlists_have_non_vars);
/* Now do join-type-specific stuff */ /* Now do join-type-specific stuff */
if (IsA(join, NestLoop)) if (IsA(join, NestLoop))
@ -722,8 +735,7 @@ set_join_references(Join *join, List *rtable)
/* This processing is split out to handle possible recursion */ /* This processing is split out to handle possible recursion */
set_inner_join_references(inner_plan, set_inner_join_references(inner_plan,
rtable, rtable,
outer_tlist, outer_itlist);
tlists_have_non_vars);
} }
else if (IsA(join, MergeJoin)) else if (IsA(join, MergeJoin))
{ {
@ -731,10 +743,9 @@ set_join_references(Join *join, List *rtable)
mj->mergeclauses = join_references(mj->mergeclauses, mj->mergeclauses = join_references(mj->mergeclauses,
rtable, rtable,
outer_tlist, outer_itlist,
inner_tlist, inner_itlist,
(Index) 0, (Index) 0);
tlists_have_non_vars);
} }
else if (IsA(join, HashJoin)) else if (IsA(join, HashJoin))
{ {
@ -742,11 +753,13 @@ set_join_references(Join *join, List *rtable)
hj->hashclauses = join_references(hj->hashclauses, hj->hashclauses = join_references(hj->hashclauses,
rtable, rtable,
outer_tlist, outer_itlist,
inner_tlist, inner_itlist,
(Index) 0, (Index) 0);
tlists_have_non_vars);
} }
pfree(outer_itlist);
pfree(inner_itlist);
} }
/* /*
@ -760,8 +773,7 @@ set_join_references(Join *join, List *rtable)
static void static void
set_inner_join_references(Plan *inner_plan, set_inner_join_references(Plan *inner_plan,
List *rtable, List *rtable,
List *outer_tlist, indexed_tlist *outer_itlist)
bool tlists_have_non_vars)
{ {
if (IsA(inner_plan, IndexScan)) if (IsA(inner_plan, IndexScan))
{ {
@ -782,16 +794,14 @@ set_inner_join_references(Plan *inner_plan,
/* only refs to outer vars get changed in the inner qual */ /* only refs to outer vars get changed in the inner qual */
innerscan->indexqualorig = join_references(indexqualorig, innerscan->indexqualorig = join_references(indexqualorig,
rtable, rtable,
outer_tlist, outer_itlist,
NIL, NULL,
innerrel, innerrel);
tlists_have_non_vars);
innerscan->indexqual = join_references(innerscan->indexqual, innerscan->indexqual = join_references(innerscan->indexqual,
rtable, rtable,
outer_tlist, outer_itlist,
NIL, NULL,
innerrel, innerrel);
tlists_have_non_vars);
/* /*
* We must fix the inner qpqual too, if it has join * We must fix the inner qpqual too, if it has join
@ -801,10 +811,9 @@ set_inner_join_references(Plan *inner_plan,
if (NumRelids((Node *) inner_plan->qual) > 1) if (NumRelids((Node *) inner_plan->qual) > 1)
inner_plan->qual = join_references(inner_plan->qual, inner_plan->qual = join_references(inner_plan->qual,
rtable, rtable,
outer_tlist, outer_itlist,
NIL, NULL,
innerrel, innerrel);
tlists_have_non_vars);
} }
} }
else if (IsA(inner_plan, BitmapIndexScan)) else if (IsA(inner_plan, BitmapIndexScan))
@ -823,16 +832,14 @@ set_inner_join_references(Plan *inner_plan,
/* only refs to outer vars get changed in the inner qual */ /* only refs to outer vars get changed in the inner qual */
innerscan->indexqualorig = join_references(indexqualorig, innerscan->indexqualorig = join_references(indexqualorig,
rtable, rtable,
outer_tlist, outer_itlist,
NIL, NULL,
innerrel, innerrel);
tlists_have_non_vars);
innerscan->indexqual = join_references(innerscan->indexqual, innerscan->indexqual = join_references(innerscan->indexqual,
rtable, rtable,
outer_tlist, outer_itlist,
NIL, NULL,
innerrel, innerrel);
tlists_have_non_vars);
/* no need to fix inner qpqual */ /* no need to fix inner qpqual */
Assert(inner_plan->qual == NIL); Assert(inner_plan->qual == NIL);
} }
@ -854,10 +861,9 @@ set_inner_join_references(Plan *inner_plan,
/* only refs to outer vars get changed in the inner qual */ /* only refs to outer vars get changed in the inner qual */
innerscan->bitmapqualorig = join_references(bitmapqualorig, innerscan->bitmapqualorig = join_references(bitmapqualorig,
rtable, rtable,
outer_tlist, outer_itlist,
NIL, NULL,
innerrel, innerrel);
tlists_have_non_vars);
/* /*
* We must fix the inner qpqual too, if it has join * We must fix the inner qpqual too, if it has join
@ -867,16 +873,14 @@ set_inner_join_references(Plan *inner_plan,
if (NumRelids((Node *) inner_plan->qual) > 1) if (NumRelids((Node *) inner_plan->qual) > 1)
inner_plan->qual = join_references(inner_plan->qual, inner_plan->qual = join_references(inner_plan->qual,
rtable, rtable,
outer_tlist, outer_itlist,
NIL, NULL,
innerrel, innerrel);
tlists_have_non_vars);
/* Now recurse */ /* Now recurse */
set_inner_join_references(inner_plan->lefttree, set_inner_join_references(inner_plan->lefttree,
rtable, rtable,
outer_tlist, outer_itlist);
tlists_have_non_vars);
} }
} }
else if (IsA(inner_plan, BitmapAnd)) else if (IsA(inner_plan, BitmapAnd))
@ -889,8 +893,7 @@ set_inner_join_references(Plan *inner_plan,
{ {
set_inner_join_references((Plan *) lfirst(l), set_inner_join_references((Plan *) lfirst(l),
rtable, rtable,
outer_tlist, outer_itlist);
tlists_have_non_vars);
} }
} }
else if (IsA(inner_plan, BitmapOr)) else if (IsA(inner_plan, BitmapOr))
@ -903,8 +906,7 @@ set_inner_join_references(Plan *inner_plan,
{ {
set_inner_join_references((Plan *) lfirst(l), set_inner_join_references((Plan *) lfirst(l),
rtable, rtable,
outer_tlist, outer_itlist);
tlists_have_non_vars);
} }
} }
else if (IsA(inner_plan, TidScan)) else if (IsA(inner_plan, TidScan))
@ -914,10 +916,9 @@ set_inner_join_references(Plan *inner_plan,
innerscan->tideval = join_references(innerscan->tideval, innerscan->tideval = join_references(innerscan->tideval,
rtable, rtable,
outer_tlist, outer_itlist,
NIL, NULL,
innerrel, innerrel);
tlists_have_non_vars);
} }
} }
@ -941,17 +942,14 @@ static void
set_uppernode_references(Plan *plan, Index subvarno) set_uppernode_references(Plan *plan, Index subvarno)
{ {
Plan *subplan = plan->lefttree; Plan *subplan = plan->lefttree;
List *subplan_targetlist, indexed_tlist *subplan_itlist;
*output_targetlist; List *output_targetlist;
ListCell *l; ListCell *l;
bool tlist_has_non_vars;
if (subplan != NULL) if (subplan != NULL)
subplan_targetlist = subplan->targetlist; subplan_itlist = build_tlist_index(subplan->targetlist);
else else
subplan_targetlist = NIL; subplan_itlist = build_tlist_index(NIL);
tlist_has_non_vars = targetlist_has_non_vars(subplan_targetlist);
output_targetlist = NIL; output_targetlist = NIL;
foreach(l, plan->targetlist) foreach(l, plan->targetlist)
@ -960,9 +958,8 @@ set_uppernode_references(Plan *plan, Index subvarno)
Node *newexpr; Node *newexpr;
newexpr = replace_vars_with_subplan_refs((Node *) tle->expr, newexpr = replace_vars_with_subplan_refs((Node *) tle->expr,
subvarno, subplan_itlist,
subplan_targetlist, subvarno);
tlist_has_non_vars);
tle = flatCopyTargetEntry(tle); tle = flatCopyTargetEntry(tle);
tle->expr = (Expr *) newexpr; tle->expr = (Expr *) newexpr;
output_targetlist = lappend(output_targetlist, tle); output_targetlist = lappend(output_targetlist, tle);
@ -971,30 +968,127 @@ set_uppernode_references(Plan *plan, Index subvarno)
plan->qual = (List *) plan->qual = (List *)
replace_vars_with_subplan_refs((Node *) plan->qual, replace_vars_with_subplan_refs((Node *) plan->qual,
subvarno, subplan_itlist,
subplan_targetlist, subvarno);
tlist_has_non_vars);
pfree(subplan_itlist);
} }
/* /*
* targetlist_has_non_vars --- are there any non-Var entries in tlist? * build_tlist_index --- build an index data structure for a child tlist
* *
* In most cases, subplan tlists will be "flat" tlists with only Vars. * In most cases, subplan tlists will be "flat" tlists with only Vars,
* Checking for this allows us to save comparisons in common cases. * so we try to optimize that case by extracting information about Vars
* in advance. Matching a parent tlist to a child is still an O(N^2)
* operation, but at least with a much smaller constant factor than plain
* tlist_member() searches.
*
* The result of this function is an indexed_tlist struct to pass to
* search_indexed_tlist_for_var() or search_indexed_tlist_for_non_var().
* When done, the indexed_tlist may be freed with a single pfree().
*/ */
static bool static indexed_tlist *
targetlist_has_non_vars(List *tlist) build_tlist_index(List *tlist)
{ {
indexed_tlist *itlist;
tlist_vinfo *vinfo;
ListCell *l; ListCell *l;
/* Create data structure with enough slots for all tlist entries */
itlist = (indexed_tlist *)
palloc(offsetof(indexed_tlist, vars) +
list_length(tlist) * sizeof(tlist_vinfo));
itlist->tlist = tlist;
itlist->has_non_vars = false;
/* Find the Vars and fill in the index array */
vinfo = itlist->vars;
foreach(l, tlist) foreach(l, tlist)
{ {
TargetEntry *tle = (TargetEntry *) lfirst(l); TargetEntry *tle = (TargetEntry *) lfirst(l);
if (tle->expr && !IsA(tle->expr, Var)) if (tle->expr && IsA(tle->expr, Var))
return true; {
Var *var = (Var *) tle->expr;
vinfo->varno = var->varno;
vinfo->varattno = var->varattno;
vinfo->resno = tle->resno;
vinfo++;
}
else
itlist->has_non_vars = true;
} }
return false;
itlist->num_vars = (vinfo - itlist->vars);
return itlist;
}
/*
* search_indexed_tlist_for_var --- find a Var in an indexed tlist
*
* If a match is found, return a copy of the given Var with suitably
* modified varno/varattno (to wit, newvarno and the resno of the TLE entry).
* If no match, return NULL.
*/
static Var *
search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, Index newvarno)
{
Index varno = var->varno;
AttrNumber varattno = var->varattno;
tlist_vinfo *vinfo;
int i;
vinfo = itlist->vars;
i = itlist->num_vars;
while (i-- > 0)
{
if (vinfo->varno == varno && vinfo->varattno == varattno)
{
/* Found a match */
Var *newvar = (Var *) copyObject(var);
newvar->varno = newvarno;
newvar->varattno = vinfo->resno;
return newvar;
}
vinfo++;
}
return NULL; /* no match */
}
/*
* search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist
*
* If a match is found, return a Var constructed to reference the tlist item.
* If no match, return NULL.
*
* NOTE: it is a waste of time to call this if !itlist->has_non_vars
*/
static Var *
search_indexed_tlist_for_non_var(Node *node,
indexed_tlist *itlist, Index newvarno)
{
TargetEntry *tle;
tle = tlist_member(node, itlist->tlist);
if (tle)
{
/* Found a matching subplan output expression */
Var *newvar;
newvar = makeVar(newvarno,
tle->resno,
exprType((Node *) tle->expr),
exprTypmod((Node *) tle->expr),
0);
newvar->varnoold = 0; /* wasn't ever a plain Var */
newvar->varoattno = 0;
return newvar;
}
return NULL; /* no match */
} }
/* /*
@ -1012,12 +1106,13 @@ targetlist_has_non_vars(List *tlist)
* *
* For a normal join, acceptable_rel should be zero so that any failure to * For a normal join, acceptable_rel should be zero so that any failure to
* match a Var will be reported as an error. For the indexscan case, * match a Var will be reported as an error. For the indexscan case,
* pass inner_tlist = NIL and acceptable_rel = the ID of the inner relation. * pass inner_itlist = NULL and acceptable_rel = the ID of the inner relation.
* *
* 'clauses' is the targetlist or list of join clauses * 'clauses' is the targetlist or list of join clauses
* 'rtable' is the current range table * 'rtable' is the current range table
* 'outer_tlist' is the target list of the outer join relation * 'outer_itlist' is the indexed target list of the outer join relation
* 'inner_tlist' is the target list of the inner join relation, or NIL * 'inner_itlist' is the indexed target list of the inner join relation,
* or NULL
* 'acceptable_rel' is either zero or the rangetable index of a relation * 'acceptable_rel' is either zero or the rangetable index of a relation
* whose Vars may appear in the clause without provoking an error. * whose Vars may appear in the clause without provoking an error.
* *
@ -1027,18 +1122,16 @@ targetlist_has_non_vars(List *tlist)
static List * static List *
join_references(List *clauses, join_references(List *clauses,
List *rtable, List *rtable,
List *outer_tlist, indexed_tlist *outer_itlist,
List *inner_tlist, indexed_tlist *inner_itlist,
Index acceptable_rel, Index acceptable_rel)
bool tlists_have_non_vars)
{ {
join_references_context context; join_references_context context;
context.rtable = rtable; context.rtable = rtable;
context.outer_tlist = outer_tlist; context.outer_itlist = outer_itlist;
context.inner_tlist = inner_tlist; context.inner_itlist = inner_itlist;
context.acceptable_rel = acceptable_rel; context.acceptable_rel = acceptable_rel;
context.tlists_have_non_vars = tlists_have_non_vars;
return (List *) join_references_mutator((Node *) clauses, &context); return (List *) join_references_mutator((Node *) clauses, &context);
} }
@ -1046,31 +1139,27 @@ static Node *
join_references_mutator(Node *node, join_references_mutator(Node *node,
join_references_context *context) join_references_context *context)
{ {
Var *newvar;
if (node == NULL) if (node == NULL)
return NULL; return NULL;
if (IsA(node, Var)) if (IsA(node, Var))
{ {
Var *var = (Var *) node; Var *var = (Var *) node;
TargetEntry *tle;
/* First look for the var in the input tlists */ /* First look for the var in the input tlists */
tle = tlist_member((Node *) var, context->outer_tlist); newvar = search_indexed_tlist_for_var(var,
if (tle) context->outer_itlist,
{ OUTER);
Var *newvar = (Var *) copyObject(var); if (newvar)
newvar->varno = OUTER;
newvar->varattno = tle->resno;
return (Node *) newvar; return (Node *) newvar;
} if (context->inner_itlist)
tle = tlist_member((Node *) var, context->inner_tlist);
if (tle)
{ {
Var *newvar = (Var *) copyObject(var); newvar = search_indexed_tlist_for_var(var,
context->inner_itlist,
newvar->varno = INNER; INNER);
newvar->varattno = tle->resno; if (newvar)
return (Node *) newvar; return (Node *) newvar;
} }
/* Return the Var unmodified, if it's for acceptable_rel */ /* Return the Var unmodified, if it's for acceptable_rel */
@ -1081,40 +1170,21 @@ join_references_mutator(Node *node,
elog(ERROR, "variable not found in subplan target lists"); elog(ERROR, "variable not found in subplan target lists");
} }
/* Try matching more complex expressions too, if tlists have any */ /* Try matching more complex expressions too, if tlists have any */
if (context->tlists_have_non_vars) if (context->outer_itlist->has_non_vars)
{ {
TargetEntry *tle; newvar = search_indexed_tlist_for_non_var(node,
context->outer_itlist,
tle = tlist_member(node, context->outer_tlist); OUTER);
if (tle) if (newvar)
{
/* Found a matching subplan output expression */
Var *newvar;
newvar = makeVar(OUTER,
tle->resno,
exprType((Node *) tle->expr),
exprTypmod((Node *) tle->expr),
0);
newvar->varnoold = 0; /* wasn't ever a plain Var */
newvar->varoattno = 0;
return (Node *) newvar; return (Node *) newvar;
} }
tle = tlist_member(node, context->inner_tlist); if (context->inner_itlist && context->inner_itlist->has_non_vars)
if (tle) {
{ newvar = search_indexed_tlist_for_non_var(node,
/* Found a matching subplan output expression */ context->inner_itlist,
Var *newvar; INNER);
if (newvar)
newvar = makeVar(INNER,
tle->resno,
exprType((Node *) tle->expr),
exprTypmod((Node *) tle->expr),
0);
newvar->varnoold = 0; /* wasn't ever a plain Var */
newvar->varoattno = 0;
return (Node *) newvar; return (Node *) newvar;
}
} }
return expression_tree_mutator(node, return expression_tree_mutator(node,
join_references_mutator, join_references_mutator,
@ -1131,16 +1201,15 @@ join_references_mutator(Node *node,
* --- so this routine should only be applied to nodes whose subplans' * --- so this routine should only be applied to nodes whose subplans'
* targetlists were generated via flatten_tlist() or some such method. * targetlists were generated via flatten_tlist() or some such method.
* *
* If tlist_has_non_vars is true, then we try to match whole subexpressions * If itlist->has_non_vars is true, then we try to match whole subexpressions
* against elements of the subplan tlist, so that we can avoid recomputing * against elements of the subplan tlist, so that we can avoid recomputing
* expressions that were already computed by the subplan. (This is relatively * expressions that were already computed by the subplan. (This is relatively
* expensive, so we don't want to try it in the common case where the * expensive, so we don't want to try it in the common case where the
* subplan tlist is just a flattened list of Vars.) * subplan tlist is just a flattened list of Vars.)
* *
* 'node': the tree to be fixed (a target item or qual) * 'node': the tree to be fixed (a target item or qual)
* 'subplan_itlist': indexed target list for subplan
* 'subvarno': varno to be assigned to all Vars * 'subvarno': varno to be assigned to all Vars
* 'subplan_targetlist': target list for subplan
* 'tlist_has_non_vars': true if subplan_targetlist contains non-Var exprs
* *
* The resulting tree is a copy of the original in which all Var nodes have * The resulting tree is a copy of the original in which all Var nodes have
* varno = subvarno, varattno = resno of corresponding subplan target. * varno = subvarno, varattno = resno of corresponding subplan target.
@ -1148,15 +1217,13 @@ join_references_mutator(Node *node,
*/ */
static Node * static Node *
replace_vars_with_subplan_refs(Node *node, replace_vars_with_subplan_refs(Node *node,
Index subvarno, indexed_tlist *subplan_itlist,
List *subplan_targetlist, Index subvarno)
bool tlist_has_non_vars)
{ {
replace_vars_with_subplan_refs_context context; replace_vars_with_subplan_refs_context context;
context.subplan_itlist = subplan_itlist;
context.subvarno = subvarno; context.subvarno = subvarno;
context.subplan_targetlist = subplan_targetlist;
context.tlist_has_non_vars = tlist_has_non_vars;
return replace_vars_with_subplan_refs_mutator(node, &context); return replace_vars_with_subplan_refs_mutator(node, &context);
} }
@ -1164,42 +1231,29 @@ static Node *
replace_vars_with_subplan_refs_mutator(Node *node, replace_vars_with_subplan_refs_mutator(Node *node,
replace_vars_with_subplan_refs_context *context) replace_vars_with_subplan_refs_context *context)
{ {
Var *newvar;
if (node == NULL) if (node == NULL)
return NULL; return NULL;
if (IsA(node, Var)) if (IsA(node, Var))
{ {
Var *var = (Var *) node; Var *var = (Var *) node;
TargetEntry *tle;
Var *newvar;
tle = tlist_member((Node *) var, context->subplan_targetlist); newvar = search_indexed_tlist_for_var(var,
if (!tle) context->subplan_itlist,
context->subvarno);
if (!newvar)
elog(ERROR, "variable not found in subplan target list"); elog(ERROR, "variable not found in subplan target list");
newvar = (Var *) copyObject(var);
newvar->varno = context->subvarno;
newvar->varattno = tle->resno;
return (Node *) newvar; return (Node *) newvar;
} }
/* Try matching more complex expressions too, if tlist has any */ /* Try matching more complex expressions too, if tlist has any */
if (context->tlist_has_non_vars) if (context->subplan_itlist->has_non_vars)
{ {
TargetEntry *tle; newvar = search_indexed_tlist_for_non_var(node,
context->subplan_itlist,
tle = tlist_member(node, context->subplan_targetlist); context->subvarno);
if (tle) if (newvar)
{
/* Found a matching subplan output expression */
Var *newvar;
newvar = makeVar(context->subvarno,
tle->resno,
exprType((Node *) tle->expr),
exprTypmod((Node *) tle->expr),
0);
newvar->varnoold = 0; /* wasn't ever a plain Var */
newvar->varoattno = 0;
return (Node *) newvar; return (Node *) newvar;
}
} }
return expression_tree_mutator(node, return expression_tree_mutator(node,
replace_vars_with_subplan_refs_mutator, replace_vars_with_subplan_refs_mutator,