]> granicus.if.org Git - postgresql/commitdiff
Revise searching of subplan target lists to use something more efficient
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Jun 2005 00:28:54 +0000 (00:28 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Jun 2005 00:28:54 +0000 (00:28 +0000)
than tlist_member calls.  Building a large join tlist is still O(N^2),
but with a much smaller constant factor than before.

src/backend/optimizer/plan/setrefs.c

index c3eb36bcfc4815d0d12b12c9dd5040bc10fd4630..5f6e8301fc326a781e9f673f39dad33a3748ebe7 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 #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
 {
        List       *rtable;
-       List       *outer_tlist;
-       List       *inner_tlist;
+       indexed_tlist *outer_itlist;
+       indexed_tlist *inner_itlist;
        Index           acceptable_rel;
-       bool            tlists_have_non_vars;
 } join_references_context;
 
 typedef struct
 {
+       indexed_tlist *subplan_itlist;
        Index           subvarno;
-       List       *subplan_targetlist;
-       bool            tlist_has_non_vars;
 } replace_vars_with_subplan_refs_context;
 
 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_inner_join_references(Plan *inner_plan,
                                                                          List *rtable,
-                                                                         List *outer_tlist,
-                                                                         bool tlists_have_non_vars);
+                                                                         indexed_tlist *outer_itlist);
 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,
-                               List *rtable,
-                               List *outer_tlist,
-                               List *inner_tlist,
-                               Index acceptable_rel,
-                               bool tlists_have_non_vars);
+                                                        List *rtable,
+                                                        indexed_tlist *outer_itlist,
+                                                        indexed_tlist *inner_itlist,
+                                                        Index acceptable_rel);
 static Node *join_references_mutator(Node *node,
                                                join_references_context *context);
 static Node *replace_vars_with_subplan_refs(Node *node,
-                                                          Index subvarno,
-                                                          List *subplan_targetlist,
-                                                          bool tlist_has_non_vars);
+                                                                                       indexed_tlist *subplan_itlist,
+                                                                                       Index subvarno);
 static Node *replace_vars_with_subplan_refs_mutator(Node *node,
                                                replace_vars_with_subplan_refs_context *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       *inner_plan = join->plan.righttree;
-       List       *outer_tlist = outer_plan->targetlist;
-       List       *inner_tlist = inner_plan->targetlist;
-       bool            tlists_have_non_vars;
+       indexed_tlist *outer_itlist;
+       indexed_tlist *inner_itlist;
 
-       tlists_have_non_vars = targetlist_has_non_vars(outer_tlist) ||
-               targetlist_has_non_vars(inner_tlist);
+       outer_itlist = build_tlist_index(outer_plan->targetlist);
+       inner_itlist = build_tlist_index(inner_plan->targetlist);
 
        /* All join plans have tlist, qual, and joinqual */
        join->plan.targetlist = join_references(join->plan.targetlist,
                                                                                        rtable,
-                                                                                       outer_tlist,
-                                                                                       inner_tlist,
-                                                                                       (Index) 0,
-                                                                                       tlists_have_non_vars);
+                                                                                       outer_itlist,
+                                                                                       inner_itlist,
+                                                                                       (Index) 0);
        join->plan.qual = join_references(join->plan.qual,
                                                                          rtable,
-                                                                         outer_tlist,
-                                                                         inner_tlist,
-                                                                         (Index) 0,
-                                                                         tlists_have_non_vars);
+                                                                         outer_itlist,
+                                                                         inner_itlist,
+                                                                         (Index) 0);
        join->joinqual = join_references(join->joinqual,
                                                                         rtable,
-                                                                        outer_tlist,
-                                                                        inner_tlist,
-                                                                        (Index) 0,
-                                                                        tlists_have_non_vars);
+                                                                        outer_itlist,
+                                                                        inner_itlist,
+                                                                        (Index) 0);
 
        /* Now do join-type-specific stuff */
        if (IsA(join, NestLoop))
@@ -722,8 +735,7 @@ set_join_references(Join *join, List *rtable)
                /* This processing is split out to handle possible recursion */
                set_inner_join_references(inner_plan,
                                                                  rtable,
-                                                                 outer_tlist,
-                                                                 tlists_have_non_vars);
+                                                                 outer_itlist);
        }
        else if (IsA(join, MergeJoin))
        {
@@ -731,10 +743,9 @@ set_join_references(Join *join, List *rtable)
 
                mj->mergeclauses = join_references(mj->mergeclauses,
                                                                                   rtable,
-                                                                                  outer_tlist,
-                                                                                  inner_tlist,
-                                                                                  (Index) 0,
-                                                                                  tlists_have_non_vars);
+                                                                                  outer_itlist,
+                                                                                  inner_itlist,
+                                                                                  (Index) 0);
        }
        else if (IsA(join, HashJoin))
        {
@@ -742,11 +753,13 @@ set_join_references(Join *join, List *rtable)
 
                hj->hashclauses = join_references(hj->hashclauses,
                                                                                  rtable,
-                                                                                 outer_tlist,
-                                                                                 inner_tlist,
-                                                                                 (Index) 0,
-                                                                                 tlists_have_non_vars);
+                                                                                 outer_itlist,
+                                                                                 inner_itlist,
+                                                                                 (Index) 0);
        }
+
+       pfree(outer_itlist);
+       pfree(inner_itlist);
 }
 
 /*
@@ -760,8 +773,7 @@ set_join_references(Join *join, List *rtable)
 static void
 set_inner_join_references(Plan *inner_plan,
                                                  List *rtable,
-                                                 List *outer_tlist,
-                                                 bool tlists_have_non_vars)
+                                                 indexed_tlist *outer_itlist)
 {
        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 */
                        innerscan->indexqualorig = join_references(indexqualorig,
                                                                                                           rtable,
-                                                                                                          outer_tlist,
-                                                                                                          NIL,
-                                                                                                          innerrel,
-                                                                                                          tlists_have_non_vars);
+                                                                                                          outer_itlist,
+                                                                                                          NULL,
+                                                                                                          innerrel);
                        innerscan->indexqual = join_references(innerscan->indexqual,
                                                                                                   rtable,
-                                                                                                  outer_tlist,
-                                                                                                  NIL,
-                                                                                                  innerrel,
-                                                                                                  tlists_have_non_vars);
+                                                                                                  outer_itlist,
+                                                                                                  NULL,
+                                                                                                  innerrel);
 
                        /*
                         * 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)
                                inner_plan->qual = join_references(inner_plan->qual,
                                                                                                   rtable,
-                                                                                                  outer_tlist,
-                                                                                                  NIL,
-                                                                                                  innerrel,
-                                                                                                  tlists_have_non_vars);
+                                                                                                  outer_itlist,
+                                                                                                  NULL,
+                                                                                                  innerrel);
                }
        }
        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 */
                        innerscan->indexqualorig = join_references(indexqualorig,
                                                                                                           rtable,
-                                                                                                          outer_tlist,
-                                                                                                          NIL,
-                                                                                                          innerrel,
-                                                                                                          tlists_have_non_vars);
+                                                                                                          outer_itlist,
+                                                                                                          NULL,
+                                                                                                          innerrel);
                        innerscan->indexqual = join_references(innerscan->indexqual,
                                                                                                   rtable,
-                                                                                                  outer_tlist,
-                                                                                                  NIL,
-                                                                                                  innerrel,
-                                                                                                  tlists_have_non_vars);
+                                                                                                  outer_itlist,
+                                                                                                  NULL,
+                                                                                                  innerrel);
                        /* no need to fix inner qpqual */
                        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 */
                        innerscan->bitmapqualorig = join_references(bitmapqualorig,
                                                                                                          rtable,
-                                                                                                         outer_tlist,
-                                                                                                         NIL,
-                                                                                                         innerrel,
-                                                                                                         tlists_have_non_vars);
+                                                                                                         outer_itlist,
+                                                                                                         NULL,
+                                                                                                         innerrel);
 
                        /*
                         * 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)
                                inner_plan->qual = join_references(inner_plan->qual,
                                                                                                   rtable,
-                                                                                                  outer_tlist,
-                                                                                                  NIL,
-                                                                                                  innerrel,
-                                                                                                  tlists_have_non_vars);
+                                                                                                  outer_itlist,
+                                                                                                  NULL,
+                                                                                                  innerrel);
 
                        /* Now recurse */
                        set_inner_join_references(inner_plan->lefttree,
                                                                          rtable,
-                                                                         outer_tlist,
-                                                                         tlists_have_non_vars);
+                                                                         outer_itlist);
                }
        }
        else if (IsA(inner_plan, BitmapAnd))
@@ -889,8 +893,7 @@ set_inner_join_references(Plan *inner_plan,
                {
                        set_inner_join_references((Plan *) lfirst(l),
                                                                          rtable,
-                                                                         outer_tlist,
-                                                                         tlists_have_non_vars);
+                                                                         outer_itlist);
                }
        }
        else if (IsA(inner_plan, BitmapOr))
@@ -903,8 +906,7 @@ set_inner_join_references(Plan *inner_plan,
                {
                        set_inner_join_references((Plan *) lfirst(l),
                                                                          rtable,
-                                                                         outer_tlist,
-                                                                         tlists_have_non_vars);
+                                                                         outer_itlist);
                }
        }
        else if (IsA(inner_plan, TidScan))
@@ -914,10 +916,9 @@ set_inner_join_references(Plan *inner_plan,
 
                innerscan->tideval = join_references(innerscan->tideval,
                                                                                         rtable,
-                                                                                        outer_tlist,
-                                                                                        NIL,
-                                                                                        innerrel,
-                                                                                        tlists_have_non_vars);
+                                                                                        outer_itlist,
+                                                                                        NULL,
+                                                                                        innerrel);
        }
 }
 
@@ -941,17 +942,14 @@ static void
 set_uppernode_references(Plan *plan, Index subvarno)
 {
        Plan       *subplan = plan->lefttree;
-       List       *subplan_targetlist,
-                          *output_targetlist;
+       indexed_tlist *subplan_itlist;
+       List       *output_targetlist;
        ListCell   *l;
-       bool            tlist_has_non_vars;
 
        if (subplan != NULL)
-               subplan_targetlist = subplan->targetlist;
+               subplan_itlist = build_tlist_index(subplan->targetlist);
        else
-               subplan_targetlist = NIL;
-
-       tlist_has_non_vars = targetlist_has_non_vars(subplan_targetlist);
+               subplan_itlist = build_tlist_index(NIL);
 
        output_targetlist = NIL;
        foreach(l, plan->targetlist)
@@ -960,9 +958,8 @@ set_uppernode_references(Plan *plan, Index subvarno)
                Node       *newexpr;
 
                newexpr = replace_vars_with_subplan_refs((Node *) tle->expr,
-                                                                                                subvarno,
-                                                                                                subplan_targetlist,
-                                                                                                tlist_has_non_vars);
+                                                                                                subplan_itlist,
+                                                                                                subvarno);
                tle = flatCopyTargetEntry(tle);
                tle->expr = (Expr *) newexpr;
                output_targetlist = lappend(output_targetlist, tle);
@@ -971,30 +968,127 @@ set_uppernode_references(Plan *plan, Index subvarno)
 
        plan->qual = (List *)
                replace_vars_with_subplan_refs((Node *) plan->qual,
-                                                                          subvarno,
-                                                                          subplan_targetlist,
-                                                                          tlist_has_non_vars);
+                                                                          subplan_itlist,
+                                                                          subvarno);
+
+       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.
- * Checking for this allows us to save comparisons in common cases.
+ * In most cases, subplan tlists will be "flat" tlists with only Vars,
+ * 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
-targetlist_has_non_vars(List *tlist)
+static indexed_tlist *
+build_tlist_index(List *tlist)
 {
+       indexed_tlist *itlist;
+       tlist_vinfo *vinfo;
        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)
        {
                TargetEntry *tle = (TargetEntry *) lfirst(l);
 
-               if (tle->expr && !IsA(tle->expr, Var))
-                       return true;
+               if (tle->expr && IsA(tle->expr, Var))
+               {
+                       Var        *var = (Var *) tle->expr;
+
+                       vinfo->varno = var->varno;
+                       vinfo->varattno = var->varattno;
+                       vinfo->resno = tle->resno;
+                       vinfo++;
+               }
+               else
+                       itlist->has_non_vars = true;
+       }
+
+       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 false;
+       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
  * 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
  * 'rtable' is the current range table
- * 'outer_tlist' is the target list of the outer join relation
- * 'inner_tlist' is the target list of the inner join relation, or NIL
+ * 'outer_itlist' is the indexed target list of the outer join relation
+ * '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
  *             whose Vars may appear in the clause without provoking an error.
  *
@@ -1027,18 +1122,16 @@ targetlist_has_non_vars(List *tlist)
 static List *
 join_references(List *clauses,
                                List *rtable,
-                               List *outer_tlist,
-                               List *inner_tlist,
-                               Index acceptable_rel,
-                               bool tlists_have_non_vars)
+                               indexed_tlist *outer_itlist,
+                               indexed_tlist *inner_itlist,
+                               Index acceptable_rel)
 {
        join_references_context context;
 
        context.rtable = rtable;
-       context.outer_tlist = outer_tlist;
-       context.inner_tlist = inner_tlist;
+       context.outer_itlist = outer_itlist;
+       context.inner_itlist = inner_itlist;
        context.acceptable_rel = acceptable_rel;
-       context.tlists_have_non_vars = tlists_have_non_vars;
        return (List *) join_references_mutator((Node *) clauses, &context);
 }
 
@@ -1046,31 +1139,27 @@ static Node *
 join_references_mutator(Node *node,
                                                join_references_context *context)
 {
+       Var                *newvar;
+
        if (node == NULL)
                return NULL;
        if (IsA(node, Var))
        {
                Var                *var = (Var *) node;
-               TargetEntry *tle;
 
                /* First look for the var in the input tlists */
-               tle = tlist_member((Node *) var, context->outer_tlist);
-               if (tle)
-               {
-                       Var                *newvar = (Var *) copyObject(var);
-
-                       newvar->varno = OUTER;
-                       newvar->varattno = tle->resno;
+               newvar = search_indexed_tlist_for_var(var,
+                                                                                         context->outer_itlist,
+                                                                                         OUTER);
+               if (newvar)
                        return (Node *) newvar;
-               }
-               tle = tlist_member((Node *) var, context->inner_tlist);
-               if (tle)
+               if (context->inner_itlist)
                {
-                       Var                *newvar = (Var *) copyObject(var);
-
-                       newvar->varno = INNER;
-                       newvar->varattno = tle->resno;
-                       return (Node *) newvar;
+                       newvar = search_indexed_tlist_for_var(var,
+                                                                                                 context->inner_itlist,
+                                                                                                 INNER);
+                       if (newvar)
+                               return (Node *) newvar;
                }
 
                /* 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");
        }
        /* 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;
-
-               tle = tlist_member(node, context->outer_tlist);
-               if (tle)
-               {
-                       /* 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;
+               newvar = search_indexed_tlist_for_non_var(node,
+                                                                                                 context->outer_itlist,
+                                                                                                 OUTER);
+               if (newvar)
                        return (Node *) newvar;
-               }
-               tle = tlist_member(node, context->inner_tlist);
-               if (tle)
-               {
-                       /* Found a matching subplan output expression */
-                       Var                *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;
+       }
+       if (context->inner_itlist && context->inner_itlist->has_non_vars)
+       {
+               newvar = search_indexed_tlist_for_non_var(node,
+                                                                                                 context->inner_itlist,
+                                                                                                 INNER);
+               if (newvar)
                        return (Node *) newvar;
-               }
        }
        return expression_tree_mutator(node,
                                                                   join_references_mutator,
@@ -1131,16 +1201,15 @@ join_references_mutator(Node *node,
  * --- so this routine should only be applied to nodes whose subplans'
  * 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
  * 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
  * subplan tlist is just a flattened list of Vars.)
  *
  * '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
- * '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
  * varno = subvarno, varattno = resno of corresponding subplan target.
@@ -1148,15 +1217,13 @@ join_references_mutator(Node *node,
  */
 static Node *
 replace_vars_with_subplan_refs(Node *node,
-                                                          Index subvarno,
-                                                          List *subplan_targetlist,
-                                                          bool tlist_has_non_vars)
+                                                          indexed_tlist *subplan_itlist,
+                                                          Index subvarno)
 {
        replace_vars_with_subplan_refs_context context;
 
+       context.subplan_itlist = subplan_itlist;
        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);
 }
 
@@ -1164,42 +1231,29 @@ static Node *
 replace_vars_with_subplan_refs_mutator(Node *node,
                                                 replace_vars_with_subplan_refs_context *context)
 {
+       Var                *newvar;
+
        if (node == NULL)
                return NULL;
        if (IsA(node, Var))
        {
                Var                *var = (Var *) node;
-               TargetEntry *tle;
-               Var                *newvar;
 
-               tle = tlist_member((Node *) var, context->subplan_targetlist);
-               if (!tle)
+               newvar = search_indexed_tlist_for_var(var,
+                                                                                         context->subplan_itlist,
+                                                                                         context->subvarno);
+               if (!newvar)
                        elog(ERROR, "variable not found in subplan target list");
-               newvar = (Var *) copyObject(var);
-               newvar->varno = context->subvarno;
-               newvar->varattno = tle->resno;
                return (Node *) newvar;
        }
        /* 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;
-
-               tle = tlist_member(node, context->subplan_targetlist);
-               if (tle)
-               {
-                       /* 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;
+               newvar = search_indexed_tlist_for_non_var(node,
+                                                                                                 context->subplan_itlist,
+                                                                                                 context->subvarno);
+               if (newvar)
                        return (Node *) newvar;
-               }
        }
        return expression_tree_mutator(node,
                                                                   replace_vars_with_subplan_refs_mutator,