]> granicus.if.org Git - postgresql/commitdiff
Turn the rangetable used by the executor into a flat list, and avoid storing
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 22 Feb 2007 22:00:26 +0000 (22:00 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 22 Feb 2007 22:00:26 +0000 (22:00 +0000)
useless substructure for its RangeTblEntry nodes.  (I chose to keep using the
same struct node type and just zero out the link fields for unneeded info,
rather than making a separate ExecRangeTblEntry type --- it seemed too
fragile to have two different rangetable representations.)

Along the way, put subplans into a list in the toplevel PlannedStmt node,
and have SubPlan nodes refer to them by list index instead of direct pointers.
Vadim wanted to do that years ago, but I never understood what he was on about
until now.  It makes things a *whole* lot more robust, because we can stop
worrying about duplicate processing of subplans during expression tree
traversals.  That's been a constant source of bugs, and it's finally gone.

There are some consequent simplifications yet to be made, like not using
a separate EState for subplans in the executor, but I'll tackle that later.

32 files changed:
doc/src/sgml/indexam.sgml
src/backend/commands/explain.c
src/backend/executor/execMain.c
src/backend/executor/execUtils.c
src/backend/executor/nodeFunctionscan.c
src/backend/executor/nodeSubplan.c
src/backend/executor/nodeSubqueryscan.c
src/backend/executor/nodeValuesscan.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/print.c
src/backend/optimizer/path/allpaths.c
src/backend/optimizer/path/costsize.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/planagg.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/setrefs.c
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/relnode.c
src/backend/parser/parse_expr.c
src/backend/utils/adt/selfuncs.c
src/include/executor/executor.h
src/include/nodes/execnodes.h
src/include/nodes/plannodes.h
src/include/nodes/primnodes.h
src/include/nodes/print.h
src/include/nodes/relation.h
src/include/optimizer/cost.h
src/include/optimizer/planmain.h

index d559be0b6eb5bada5f380a22228ff960edbfcbe3..247f7f48cbef4568fbcff47c6b4a0953d03ed527 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.21 2007/01/31 20:56:17 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.22 2007/02/22 22:00:22 tgl Exp $ -->
 
 <chapter id="indexam">
  <title>Index Access Method Interface Definition</title>
@@ -903,7 +903,7 @@ amcostestimate (PlannerInfo *root,
      * Also, we charge for evaluation of the indexquals at each index row.
      * All the costs are assumed to be paid incrementally during the scan.
      */
-    cost_qual_eval(&amp;index_qual_cost, indexQuals);
+    cost_qual_eval(&amp;index_qual_cost, indexQuals, root);
     *indexStartupCost = index_qual_cost.startup;
     *indexTotalCost = seq_page_cost * numIndexPages +
         (cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;
index 58b7e6ded9a48b1a74b344a45022fba02159e298..34784eb078e8d47306d0ea21247b729df52ca7bb 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.156 2007/02/20 17:32:14 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.157 2007/02/22 22:00:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -37,6 +37,7 @@ typedef struct ExplainState
        bool            printNodes;             /* do nodeToString() too */
        bool            printAnalyze;   /* print actual times */
        /* other states */
+       PlannedStmt *pstmt;                     /* top of plan */
        List       *rtable;                     /* range table */
 } ExplainState;
 
@@ -260,6 +261,7 @@ ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
 
        es->printNodes = stmt->verbose;
        es->printAnalyze = stmt->analyze;
+       es->pstmt = queryDesc->plannedstmt;
        es->rtable = queryDesc->plannedstmt->rtable;
 
        if (es->printNodes)
@@ -858,7 +860,6 @@ explain_outNode(StringInfo str,
        /* initPlan-s */
        if (plan->initPlan)
        {
-               List       *saved_rtable = es->rtable;
                ListCell   *lst;
 
                for (i = 0; i < indent; i++)
@@ -869,16 +870,15 @@ explain_outNode(StringInfo str,
                        SubPlanState *sps = (SubPlanState *) lfirst(lst);
                        SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
 
-                       es->rtable = sp->rtable;
                        for (i = 0; i < indent; i++)
                                appendStringInfo(str, "  ");
                        appendStringInfo(str, "    ->  ");
-                       explain_outNode(str, sp->plan,
+                       explain_outNode(str,
+                                                       exec_subplan_get_plan(es->pstmt, sp),
                                                        sps->planstate,
                                                        NULL,
                                                        indent + 4, es);
                }
-               es->rtable = saved_rtable;
        }
 
        /* lefttree */
@@ -994,12 +994,6 @@ explain_outNode(StringInfo str,
                SubqueryScan *subqueryscan = (SubqueryScan *) plan;
                SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
                Plan       *subnode = subqueryscan->subplan;
-               RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
-                                                                         es->rtable);
-               List       *saved_rtable = es->rtable;
-
-               Assert(rte->rtekind == RTE_SUBQUERY);
-               es->rtable = rte->subquery->rtable;
 
                for (i = 0; i < indent; i++)
                        appendStringInfo(str, "  ");
@@ -1009,14 +1003,11 @@ explain_outNode(StringInfo str,
                                                subquerystate->subplan,
                                                NULL,
                                                indent + 3, es);
-
-               es->rtable = saved_rtable;
        }
 
        /* subPlan-s */
        if (planstate->subPlan)
        {
-               List       *saved_rtable = es->rtable;
                ListCell   *lst;
 
                for (i = 0; i < indent; i++)
@@ -1027,16 +1018,15 @@ explain_outNode(StringInfo str,
                        SubPlanState *sps = (SubPlanState *) lfirst(lst);
                        SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
 
-                       es->rtable = sp->rtable;
                        for (i = 0; i < indent; i++)
                                appendStringInfo(str, "  ");
                        appendStringInfo(str, "    ->  ");
-                       explain_outNode(str, sp->plan,
+                       explain_outNode(str,
+                                                       exec_subplan_get_plan(es->pstmt, sp),
                                                        sps->planstate,
                                                        NULL,
                                                        indent + 4, es);
                }
-               es->rtable = saved_rtable;
        }
 }
 
index 405b58f9fd6b087ec18ecda7541f7b1a98e63c9c..d0df0ea6f472f28e48f822234b6cab7bfa85ba8c 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.287 2007/02/20 17:32:14 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.288 2007/02/22 22:00:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -92,9 +92,9 @@ static void ExecProcessReturning(ProjectionInfo *projectReturning,
                                         DestReceiver *dest);
 static TupleTableSlot *EvalPlanQualNext(EState *estate);
 static void EndEvalPlanQual(EState *estate);
+static void ExecCheckRTPerms(List *rangeTable);
 static void ExecCheckRTEPerms(RangeTblEntry *rte);
 static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt);
-static void ExecCheckRangeTblReadOnly(List *rtable);
 static void EvalPlanQualStart(evalPlanQual *epq, EState *estate,
                                  evalPlanQual *priorepq);
 static void EvalPlanQualStop(evalPlanQual *epq);
@@ -348,16 +348,14 @@ ExecutorRewind(QueryDesc *queryDesc)
  * ExecCheckRTPerms
  *             Check access permissions for all relations listed in a range table.
  */
-void
+static void
 ExecCheckRTPerms(List *rangeTable)
 {
        ListCell   *l;
 
        foreach(l, rangeTable)
        {
-               RangeTblEntry *rte = lfirst(l);
-
-               ExecCheckRTEPerms(rte);
+               ExecCheckRTEPerms((RangeTblEntry *) lfirst(l));
        }
 }
 
@@ -373,12 +371,9 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
        Oid                     userid;
 
        /*
-        * Only plain-relation RTEs need to be checked here.  Subquery RTEs are
-        * checked by ExecInitSubqueryScan if the subquery is still a separate
-        * subquery --- if it's been pulled up into our query level then the RTEs
-        * are in our rangetable and will be checked here. Function RTEs are
+        * Only plain-relation RTEs need to be checked here.  Function RTEs are
         * checked by init_fcache when the function is prepared for execution.
-        * Join and special RTEs need no checks.
+        * Join, subquery, and special RTEs need no checks.
         */
        if (rte->rtekind != RTE_RELATION)
                return;
@@ -417,6 +412,8 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
 static void
 ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
 {
+       ListCell   *l;
+
        /*
         * CREATE TABLE AS or SELECT INTO?
         *
@@ -426,32 +423,9 @@ ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
                goto fail;
 
        /* Fail if write permissions are requested on any non-temp table */
-       ExecCheckRangeTblReadOnly(plannedstmt->rtable);
-
-       return;
-
-fail:
-       ereport(ERROR,
-                       (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
-                        errmsg("transaction is read-only")));
-}
-
-static void
-ExecCheckRangeTblReadOnly(List *rtable)
-{
-       ListCell   *l;
-
-       /* Fail if write permissions are requested on any non-temp table */
-       foreach(l, rtable)
+       foreach(l, plannedstmt->rtable)
        {
-               RangeTblEntry *rte = lfirst(l);
-
-               if (rte->rtekind == RTE_SUBQUERY)
-               {
-                       Assert(!rte->subquery->into);
-                       ExecCheckRangeTblReadOnly(rte->subquery->rtable);
-                       continue;
-               }
+               RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
 
                if (rte->rtekind != RTE_RELATION)
                        continue;
@@ -494,9 +468,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
        ListCell   *l;
 
        /*
-        * Do permissions checks.  It's sufficient to examine the query's top
-        * rangetable here --- subplan RTEs will be checked during
-        * ExecInitSubPlan().
+        * Do permissions checks
         */
        ExecCheckRTPerms(rangeTable);
 
index d9957573883b3bf909c44f2a5ef775feec3f5b77..d188a38489d1e470202e306d2a9fc1dc82f7e841 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.145 2007/02/20 17:32:14 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.146 2007/02/22 22:00:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -847,7 +847,6 @@ ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
 Relation
 ExecOpenScanRelation(EState *estate, Index scanrelid)
 {
-       RangeTblEntry *rtentry;
        Oid                     reloid;
        LOCKMODE        lockmode;
        ResultRelInfo *resultRelInfos;
@@ -885,8 +884,7 @@ ExecOpenScanRelation(EState *estate, Index scanrelid)
        }
 
        /* OK, open the relation and acquire lock as needed */
-       rtentry = rt_fetch(scanrelid, estate->es_range_table);
-       reloid = rtentry->relid;
+       reloid = getrelid(scanrelid, estate->es_range_table);
 
        return heap_open(reloid, lockmode);
 }
index d3d9886e3c3aee128500537974eec19cf7893b27..87ac754a1e37e556282a78ed1edcf469bf05f52b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.43 2007/02/19 02:23:11 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.44 2007/02/22 22:00:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,7 +24,6 @@
 
 #include "executor/nodeFunctionscan.h"
 #include "funcapi.h"
-#include "parser/parsetree.h"
 #include "utils/builtins.h"
 
 
index 32167a94efbff491b18797034acac2422c90ad5d..9bc96921f416fcd77736707e71f2142cbb88f779 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.85 2007/02/06 02:59:11 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.86 2007/02/22 22:00:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -637,13 +637,9 @@ void
 ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
 {
        SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
+       Plan       *plan = exec_subplan_get_plan(estate->es_plannedstmt, subplan);
        EState     *sp_estate;
 
-       /*
-        * Do access checking on the rangetable entries in the subquery.
-        */
-       ExecCheckRTPerms(subplan->rtable);
-
        /*
         * initialize my state
         */
@@ -668,18 +664,21 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
         * shares our Param ID space and es_query_cxt, however.  XXX if rangetable
         * access were done differently, the subquery could share our EState,
         * which would eliminate some thrashing about in this module...
+        *
+        * XXX make that happen!
         */
        sp_estate = CreateSubExecutorState(estate);
        node->sub_estate = sp_estate;
 
-       sp_estate->es_range_table = subplan->rtable;
+       sp_estate->es_range_table = estate->es_range_table;
        sp_estate->es_param_list_info = estate->es_param_list_info;
        sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
        sp_estate->es_tupleTable =
-               ExecCreateTupleTable(ExecCountSlotsNode(subplan->plan) + 10);
+               ExecCreateTupleTable(ExecCountSlotsNode(plan) + 10);
        sp_estate->es_snapshot = estate->es_snapshot;
        sp_estate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot;
        sp_estate->es_instrument = estate->es_instrument;
+       sp_estate->es_plannedstmt = estate->es_plannedstmt;
 
        /*
         * Start up the subplan (this is a very cut-down form of InitPlan())
@@ -692,7 +691,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
        if (subplan->parParam == NIL && subplan->setParam == NIL)
                eflags |= EXEC_FLAG_REWIND;
 
-       node->planstate = ExecInitNode(subplan->plan, sp_estate, eflags);
+       node->planstate = ExecInitNode(plan, sp_estate, eflags);
 
        node->needShutdown = true;      /* now we need to shutdown the subplan */
 
index 24d470d8edd1f914698ecc312eb3705d6c7ae86c..6d58a8cad4e63b92b273dde8f6fabb934a473099 100644 (file)
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.35 2007/01/05 22:19:28 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.36 2007/02/22 22:00:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,7 +29,6 @@
 
 #include "executor/execdebug.h"
 #include "executor/nodeSubqueryscan.h"
-#include "parser/parsetree.h"
 
 static TupleTableSlot *SubqueryNext(SubqueryScanState *node);
 
@@ -104,17 +103,18 @@ SubqueryScanState *
 ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
 {
        SubqueryScanState *subquerystate;
-       RangeTblEntry *rte;
        EState     *sp_estate;
 
        /* check for unsupported flags */
        Assert(!(eflags & EXEC_FLAG_MARK));
 
        /*
-        * SubqueryScan should not have any "normal" children.
+        * SubqueryScan should not have any "normal" children.  Also, if planner
+        * left anything in subrtable, it's fishy.
         */
        Assert(outerPlan(node) == NULL);
        Assert(innerPlan(node) == NULL);
+       Assert(node->subrtable == NIL);
 
        /*
         * create state structure
@@ -152,25 +152,18 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
         * initialize subquery
         *
         * This should agree with ExecInitSubPlan
-        */
-       rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
-       Assert(rte->rtekind == RTE_SUBQUERY);
-
-       /*
-        * Do access checking on the rangetable entries in the subquery.
-        */
-       ExecCheckRTPerms(rte->subquery->rtable);
-
-       /*
+        *
         * The subquery needs its own EState because it has its own rangetable. It
         * shares our Param ID space and es_query_cxt, however.  XXX if rangetable
         * access were done differently, the subquery could share our EState,
         * which would eliminate some thrashing about in this module...
+        *
+        * XXX make that happen!
         */
        sp_estate = CreateSubExecutorState(estate);
        subquerystate->sss_SubEState = sp_estate;
 
-       sp_estate->es_range_table = rte->subquery->rtable;
+       sp_estate->es_range_table = estate->es_range_table;
        sp_estate->es_param_list_info = estate->es_param_list_info;
        sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
        sp_estate->es_tupleTable =
@@ -178,6 +171,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
        sp_estate->es_snapshot = estate->es_snapshot;
        sp_estate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot;
        sp_estate->es_instrument = estate->es_instrument;
+       sp_estate->es_plannedstmt = estate->es_plannedstmt;
 
        /*
         * Start up the subplan (this is a very cut-down form of InitPlan())
index 96e4b98a4e25cd947c30d2b5f16ca85796264810..bfd837e0985900937723c7b6abbbeaa707cfb3c2 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.6 2007/02/19 02:23:11 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.7 2007/02/22 22:00:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,7 +25,6 @@
 
 #include "executor/executor.h"
 #include "executor/nodeValuesscan.h"
-#include "parser/parsetree.h"
 #include "utils/memutils.h"
 
 
index 4d10afc022db95447f238c1fc51894d048fb9bf0..efa1f86945337a9857df0cb0b6fc8f5b6d4d88ba 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.367 2007/02/20 17:32:15 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.368 2007/02/22 22:00:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -78,6 +78,7 @@ _copyPlannedStmt(PlannedStmt *from)
        COPY_NODE_FIELD(rtable);
        COPY_NODE_FIELD(resultRelations);
        COPY_NODE_FIELD(into);
+       COPY_NODE_FIELD(subplans);
        COPY_NODE_FIELD(returningLists);
        COPY_NODE_FIELD(rowMarks);
        COPY_SCALAR_FIELD(nParamExec);
@@ -366,6 +367,7 @@ _copySubqueryScan(SubqueryScan *from)
         * copy remainder of node
         */
        COPY_NODE_FIELD(subplan);
+       COPY_NODE_FIELD(subrtable);
 
        return newnode;
 }
@@ -957,9 +959,8 @@ _copySubPlan(SubPlan *from)
        COPY_SCALAR_FIELD(subLinkType);
        COPY_NODE_FIELD(testexpr);
        COPY_NODE_FIELD(paramIds);
-       COPY_NODE_FIELD(plan);
        COPY_SCALAR_FIELD(plan_id);
-       COPY_NODE_FIELD(rtable);
+       COPY_SCALAR_FIELD(firstColType);
        COPY_SCALAR_FIELD(useHashTable);
        COPY_SCALAR_FIELD(unknownEqFalse);
        COPY_NODE_FIELD(setParam);
index dafa15f0287dcd849e36d1a8e3222a1de9acd5b6..1007930814ac36694122856b47582bb99621fd0e 100644 (file)
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.299 2007/02/20 17:32:15 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.300 2007/02/22 22:00:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -306,9 +306,8 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
        COMPARE_SCALAR_FIELD(subLinkType);
        COMPARE_NODE_FIELD(testexpr);
        COMPARE_NODE_FIELD(paramIds);
-       /* should compare plans, but have to settle for comparing plan IDs */
        COMPARE_SCALAR_FIELD(plan_id);
-       COMPARE_NODE_FIELD(rtable);
+       COMPARE_SCALAR_FIELD(firstColType);
        COMPARE_SCALAR_FIELD(useHashTable);
        COMPARE_SCALAR_FIELD(unknownEqFalse);
        COMPARE_NODE_FIELD(setParam);
index c8cc25abb1330ce9c8cc25d8dd90375bafbf0f6c..64f235201d0def2ba1d63eeae6d7b5b029d729b8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.300 2007/02/20 17:32:15 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.301 2007/02/22 22:00:23 tgl Exp $
  *
  * NOTES
  *       Every node type that can appear in stored rules' parsetrees *must*
@@ -245,6 +245,7 @@ _outPlannedStmt(StringInfo str, PlannedStmt *node)
        WRITE_NODE_FIELD(rtable);
        WRITE_NODE_FIELD(resultRelations);
        WRITE_NODE_FIELD(into);
+       WRITE_NODE_FIELD(subplans);
        WRITE_NODE_FIELD(returningLists);
        WRITE_NODE_FIELD(rowMarks);
        WRITE_INT_FIELD(nParamExec);
@@ -415,6 +416,7 @@ _outSubqueryScan(StringInfo str, SubqueryScan *node)
        _outScanInfo(str, (Scan *) node);
 
        WRITE_NODE_FIELD(subplan);
+       WRITE_NODE_FIELD(subrtable);
 }
 
 static void
@@ -823,9 +825,8 @@ _outSubPlan(StringInfo str, SubPlan *node)
        WRITE_ENUM_FIELD(subLinkType, SubLinkType);
        WRITE_NODE_FIELD(testexpr);
        WRITE_NODE_FIELD(paramIds);
-       WRITE_NODE_FIELD(plan);
        WRITE_INT_FIELD(plan_id);
-       WRITE_NODE_FIELD(rtable);
+       WRITE_OID_FIELD(firstColType);
        WRITE_BOOL_FIELD(useHashTable);
        WRITE_BOOL_FIELD(unknownEqFalse);
        WRITE_NODE_FIELD(setParam);
@@ -1259,7 +1260,9 @@ _outPlannerGlobal(StringInfo str, PlannerGlobal *node)
 
        /* NB: this isn't a complete set of fields */
        WRITE_NODE_FIELD(paramlist);
-       WRITE_INT_FIELD(next_plan_id);
+       WRITE_NODE_FIELD(subplans);
+       WRITE_NODE_FIELD(subrtables);
+       WRITE_NODE_FIELD(finalrtable);
 }
 
 static void
@@ -1317,6 +1320,7 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node)
        WRITE_UINT_FIELD(pages);
        WRITE_FLOAT_FIELD(tuples, "%.0f");
        WRITE_NODE_FIELD(subplan);
+       WRITE_NODE_FIELD(subrtable);
        WRITE_NODE_FIELD(baserestrictinfo);
        WRITE_NODE_FIELD(joininfo);
        WRITE_BOOL_FIELD(has_eclass_joins);
index 06d28b56b21641c959e113c50ede6915dba6594d..c6edfbed8a054d465d55b01c8d35eb4e54a72127 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.84 2007/02/10 14:58:54 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.85 2007/02/22 22:00:23 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -25,7 +25,6 @@
 #include "parser/parsetree.h"
 #include "utils/lsyscache.h"
 
-static char *plannode_type(Plan *p);
 
 /*
  * print
@@ -488,171 +487,3 @@ print_slot(TupleTableSlot *slot)
 
        debugtup(slot, NULL);
 }
-
-static char *
-plannode_type(Plan *p)
-{
-       switch (nodeTag(p))
-       {
-               case T_Plan:
-                       return "PLAN";
-               case T_Result:
-                       return "RESULT";
-               case T_Append:
-                       return "APPEND";
-               case T_BitmapAnd:
-                       return "BITMAPAND";
-               case T_BitmapOr:
-                       return "BITMAPOR";
-               case T_Scan:
-                       return "SCAN";
-               case T_SeqScan:
-                       return "SEQSCAN";
-               case T_IndexScan:
-                       return "INDEXSCAN";
-               case T_BitmapIndexScan:
-                       return "BITMAPINDEXSCAN";
-               case T_BitmapHeapScan:
-                       return "BITMAPHEAPSCAN";
-               case T_TidScan:
-                       return "TIDSCAN";
-               case T_SubqueryScan:
-                       return "SUBQUERYSCAN";
-               case T_FunctionScan:
-                       return "FUNCTIONSCAN";
-               case T_ValuesScan:
-                       return "VALUESSCAN";
-               case T_Join:
-                       return "JOIN";
-               case T_NestLoop:
-                       return "NESTLOOP";
-               case T_MergeJoin:
-                       return "MERGEJOIN";
-               case T_HashJoin:
-                       return "HASHJOIN";
-               case T_Material:
-                       return "MATERIAL";
-               case T_Sort:
-                       return "SORT";
-               case T_Agg:
-                       return "AGG";
-               case T_Unique:
-                       return "UNIQUE";
-               case T_SetOp:
-                       return "SETOP";
-               case T_Limit:
-                       return "LIMIT";
-               case T_Hash:
-                       return "HASH";
-               case T_Group:
-                       return "GROUP";
-               default:
-                       return "UNKNOWN";
-       }
-}
-
-/*
- * Recursively prints a simple text description of the plan tree
- */
-void
-print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
-{
-       int                     i;
-       char            extraInfo[NAMEDATALEN + 100];
-
-       if (!p)
-               return;
-       for (i = 0; i < indentLevel; i++)
-               printf(" ");
-       printf("%s%s :c=%.2f..%.2f :r=%.0f :w=%d ", label, plannode_type(p),
-                  p->startup_cost, p->total_cost,
-                  p->plan_rows, p->plan_width);
-       if (IsA(p, Scan) ||
-               IsA(p, SeqScan) ||
-               IsA(p, BitmapHeapScan))
-       {
-               RangeTblEntry *rte;
-
-               rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable);
-               strlcpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
-       }
-       else if (IsA(p, IndexScan))
-       {
-               RangeTblEntry *rte;
-
-               rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable);
-               strlcpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
-       }
-       else if (IsA(p, FunctionScan))
-       {
-               RangeTblEntry *rte;
-
-               rte = rt_fetch(((FunctionScan *) p)->scan.scanrelid, parsetree->rtable);
-               strlcpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
-       }
-       else if (IsA(p, ValuesScan))
-       {
-               RangeTblEntry *rte;
-
-               rte = rt_fetch(((ValuesScan *) p)->scan.scanrelid, parsetree->rtable);
-               strlcpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
-       }
-       else
-               extraInfo[0] = '\0';
-       if (extraInfo[0] != '\0')
-               printf(" ( %s )\n", extraInfo);
-       else
-               printf("\n");
-       print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
-       print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
-
-       if (IsA(p, Append))
-       {
-               ListCell   *l;
-               Append     *appendplan = (Append *) p;
-
-               foreach(l, appendplan->appendplans)
-               {
-                       Plan       *subnode = (Plan *) lfirst(l);
-
-                       print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
-               }
-       }
-
-       if (IsA(p, BitmapAnd))
-       {
-               ListCell   *l;
-               BitmapAnd  *bitmapandplan = (BitmapAnd *) p;
-
-               foreach(l, bitmapandplan->bitmapplans)
-               {
-                       Plan       *subnode = (Plan *) lfirst(l);
-
-                       print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
-               }
-       }
-
-       if (IsA(p, BitmapOr))
-       {
-               ListCell   *l;
-               BitmapOr   *bitmaporplan = (BitmapOr *) p;
-
-               foreach(l, bitmaporplan->bitmapplans)
-               {
-                       Plan       *subnode = (Plan *) lfirst(l);
-
-                       print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
-               }
-       }
-}
-
-/*
- * print_plan
- *
- * prints just the plan node types
- */
-void
-print_plan(Plan *p, Query *parsetree)
-{
-       print_plan_recursive(p, parsetree, 0, "");
-}
index 6c6e80071c1ccfc12bbeed1a9d0c92373a750bb4..7aa2bd7e6fb2c050aefce6853fe93da4ea5ddee9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.160 2007/02/20 17:32:15 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.161 2007/02/22 22:00:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -521,6 +521,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
                                                                        root->query_level + 1,
                                                                        tuple_fraction,
                                                                        &subroot);
+       rel->subrtable = subroot->parse->rtable;
 
        /* Copy number of output rows from subplan */
        rel->tuples = rel->subplan->plan_rows;
index 422ef9232226ad82dd22d73f2d712b5eb80a0c90..3dbb3bd802dbd8cd7cef7b14d27c8eb62f97a604 100644 (file)
@@ -54,7 +54,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.177 2007/01/22 20:00:39 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.178 2007/02/22 22:00:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -107,11 +107,16 @@ bool              enable_nestloop = true;
 bool           enable_mergejoin = true;
 bool           enable_hashjoin = true;
 
+typedef struct
+{
+       PlannerInfo *root;
+       QualCost        total;
+} cost_qual_eval_context;
 
 static MergeScanSelCache *cached_scansel(PlannerInfo *root,
                                                                                 RestrictInfo *rinfo,
                                                                                 PathKey *pathkey);
-static bool cost_qual_eval_walker(Node *node, QualCost *total);
+static bool cost_qual_eval_walker(Node *node, cost_qual_eval_context *context);
 static Selectivity approx_selectivity(PlannerInfo *root, List *quals,
                                   JoinType jointype);
 static Selectivity join_in_selectivity(JoinPath *path, PlannerInfo *root);
@@ -362,7 +367,7 @@ cost_index(IndexPath *path, PlannerInfo *root,
        {
                QualCost        index_qual_cost;
 
-               cost_qual_eval(&index_qual_cost, indexQuals);
+               cost_qual_eval(&index_qual_cost, indexQuals, root);
                /* any startup cost still has to be paid ... */
                cpu_per_tuple -= index_qual_cost.per_tuple;
        }
@@ -855,7 +860,7 @@ cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel)
        Assert(rte->rtekind == RTE_FUNCTION);
 
        /* Estimate costs of executing the function expression */
-       cost_qual_eval_node(&exprcost, rte->funcexpr);
+       cost_qual_eval_node(&exprcost, rte->funcexpr, root);
 
        startup_cost += exprcost.startup;
        cpu_per_tuple = exprcost.per_tuple;
@@ -1241,7 +1246,7 @@ cost_nestloop(NestPath *path, PlannerInfo *root)
        ntuples = outer_path_rows * inner_path_rows * joininfactor;
 
        /* CPU costs */
-       cost_qual_eval(&restrict_qual_cost, path->joinrestrictinfo);
+       cost_qual_eval(&restrict_qual_cost, path->joinrestrictinfo, root);
        startup_cost += restrict_qual_cost.startup;
        cpu_per_tuple = cpu_tuple_cost + restrict_qual_cost.per_tuple;
        run_cost += cpu_per_tuple * ntuples;
@@ -1301,8 +1306,8 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
         */
        merge_selec = approx_selectivity(root, mergeclauses,
                                                                         path->jpath.jointype);
-       cost_qual_eval(&merge_qual_cost, mergeclauses);
-       cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo);
+       cost_qual_eval(&merge_qual_cost, mergeclauses, root);
+       cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo, root);
        qp_qual_cost.startup -= merge_qual_cost.startup;
        qp_qual_cost.per_tuple -= merge_qual_cost.per_tuple;
 
@@ -1587,8 +1592,8 @@ cost_hashjoin(HashPath *path, PlannerInfo *root)
         */
        hash_selec = approx_selectivity(root, hashclauses,
                                                                        path->jpath.jointype);
-       cost_qual_eval(&hash_qual_cost, hashclauses);
-       cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo);
+       cost_qual_eval(&hash_qual_cost, hashclauses, root);
+       cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo, root);
        qp_qual_cost.startup -= hash_qual_cost.startup;
        qp_qual_cost.per_tuple -= hash_qual_cost.per_tuple;
 
@@ -1756,12 +1761,14 @@ cost_hashjoin(HashPath *path, PlannerInfo *root)
  *             and a per-evaluation component.
  */
 void
-cost_qual_eval(QualCost *cost, List *quals)
+cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
 {
+       cost_qual_eval_context context;
        ListCell   *l;
 
-       cost->startup = 0;
-       cost->per_tuple = 0;
+       context.root = root;
+       context.total.startup = 0;
+       context.total.per_tuple = 0;
 
        /* We don't charge any cost for the implicit ANDing at top level ... */
 
@@ -1769,8 +1776,10 @@ cost_qual_eval(QualCost *cost, List *quals)
        {
                Node       *qual = (Node *) lfirst(l);
 
-               cost_qual_eval_walker(qual, cost);
+               cost_qual_eval_walker(qual, &context);
        }
+
+       *cost = context.total;
 }
 
 /*
@@ -1778,15 +1787,21 @@ cost_qual_eval(QualCost *cost, List *quals)
  *             As above, for a single RestrictInfo or expression.
  */
 void
-cost_qual_eval_node(QualCost *cost, Node *qual)
+cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
 {
-       cost->startup = 0;
-       cost->per_tuple = 0;
-       cost_qual_eval_walker(qual, cost);
+       cost_qual_eval_context context;
+
+       context.root = root;
+       context.total.startup = 0;
+       context.total.per_tuple = 0;
+
+       cost_qual_eval_walker(qual, &context);
+
+       *cost = context.total;
 }
 
 static bool
-cost_qual_eval_walker(Node *node, QualCost *total)
+cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
 {
        if (node == NULL)
                return false;
@@ -1803,18 +1818,19 @@ cost_qual_eval_walker(Node *node, QualCost *total)
 
                if (rinfo->eval_cost.startup < 0)
                {
-                       rinfo->eval_cost.startup = 0;
-                       rinfo->eval_cost.per_tuple = 0;
+                       cost_qual_eval_context locContext;
+
+                       locContext.root = context->root;
+                       locContext.total.startup = 0;
+                       locContext.total.per_tuple = 0;
                        /*
                         * For an OR clause, recurse into the marked-up tree so that
                         * we set the eval_cost for contained RestrictInfos too.
                         */
                        if (rinfo->orclause)
-                               cost_qual_eval_walker((Node *) rinfo->orclause,
-                                                                         &rinfo->eval_cost);
+                               cost_qual_eval_walker((Node *) rinfo->orclause, &locContext);
                        else
-                               cost_qual_eval_walker((Node *) rinfo->clause,
-                                                                         &rinfo->eval_cost);
+                               cost_qual_eval_walker((Node *) rinfo->clause, &locContext);
                        /*
                         * If the RestrictInfo is marked pseudoconstant, it will be tested
                         * only once, so treat its cost as all startup cost.
@@ -1822,12 +1838,13 @@ cost_qual_eval_walker(Node *node, QualCost *total)
                        if (rinfo->pseudoconstant)
                        {
                                /* count one execution during startup */
-                               rinfo->eval_cost.startup += rinfo->eval_cost.per_tuple;
-                               rinfo->eval_cost.per_tuple = 0;
+                               locContext.total.startup += locContext.total.per_tuple;
+                               locContext.total.per_tuple = 0;
                        }
+                       rinfo->eval_cost = locContext.total;
                }
-               total->startup += rinfo->eval_cost.startup;
-               total->per_tuple += rinfo->eval_cost.per_tuple;
+               context->total.startup += rinfo->eval_cost.startup;
+               context->total.per_tuple += rinfo->eval_cost.per_tuple;
                /* do NOT recurse into children */
                return false;
        }
@@ -1849,8 +1866,8 @@ cost_qual_eval_walker(Node *node, QualCost *total)
         */
        if (IsA(node, FuncExpr))
        {
-               total->per_tuple += get_func_cost(((FuncExpr *) node)->funcid) *
-                       cpu_operator_cost;
+               context->total.per_tuple +=
+                       get_func_cost(((FuncExpr *) node)->funcid) * cpu_operator_cost;
        }
        else if (IsA(node, OpExpr) ||
                         IsA(node, DistinctExpr) ||
@@ -1858,8 +1875,8 @@ cost_qual_eval_walker(Node *node, QualCost *total)
        {
                /* rely on struct equivalence to treat these all alike */
                set_opfuncid((OpExpr *) node);
-               total->per_tuple += get_func_cost(((OpExpr *) node)->opfuncid) *
-                       cpu_operator_cost;
+               context->total.per_tuple +=
+                       get_func_cost(((OpExpr *) node)->opfuncid) * cpu_operator_cost;
        }
        else if (IsA(node, ScalarArrayOpExpr))
        {
@@ -1871,7 +1888,7 @@ cost_qual_eval_walker(Node *node, QualCost *total)
                Node       *arraynode = (Node *) lsecond(saop->args);
 
                set_sa_opfuncid(saop);
-               total->per_tuple += get_func_cost(saop->opfuncid) *
+               context->total.per_tuple += get_func_cost(saop->opfuncid) *
                        cpu_operator_cost * estimate_array_length(arraynode) * 0.5;
        }
        else if (IsA(node, RowCompareExpr))
@@ -1884,7 +1901,7 @@ cost_qual_eval_walker(Node *node, QualCost *total)
                {
                        Oid             opid = lfirst_oid(lc);
 
-                       total->per_tuple += get_func_cost(get_opcode(opid)) *
+                       context->total.per_tuple += get_func_cost(get_opcode(opid)) *
                                cpu_operator_cost;
                }
        }
@@ -1905,7 +1922,7 @@ cost_qual_eval_walker(Node *node, QualCost *total)
                 * subplan by hashing.
                 */
                SubPlan    *subplan = (SubPlan *) node;
-               Plan       *plan = subplan->plan;
+               Plan       *plan = planner_subplan_get_plan(context->root, subplan);
 
                if (subplan->useHashTable)
                {
@@ -1915,7 +1932,7 @@ cost_qual_eval_walker(Node *node, QualCost *total)
                         * cpu_operator_cost per tuple for the work of loading the
                         * hashtable, too.
                         */
-                       total->startup += plan->total_cost +
+                       context->total.startup += plan->total_cost +
                                cpu_operator_cost * plan->plan_rows;
 
                        /*
@@ -1941,20 +1958,21 @@ cost_qual_eval_walker(Node *node, QualCost *total)
                        if (subplan->subLinkType == EXISTS_SUBLINK)
                        {
                                /* we only need to fetch 1 tuple */
-                               total->per_tuple += plan_run_cost / plan->plan_rows;
+                               context->total.per_tuple += plan_run_cost / plan->plan_rows;
                        }
                        else if (subplan->subLinkType == ALL_SUBLINK ||
                                         subplan->subLinkType == ANY_SUBLINK)
                        {
                                /* assume we need 50% of the tuples */
-                               total->per_tuple += 0.50 * plan_run_cost;
+                               context->total.per_tuple += 0.50 * plan_run_cost;
                                /* also charge a cpu_operator_cost per row examined */
-                               total->per_tuple += 0.50 * plan->plan_rows * cpu_operator_cost;
+                               context->total.per_tuple +=
+                                       0.50 * plan->plan_rows * cpu_operator_cost;
                        }
                        else
                        {
                                /* assume we need all tuples */
-                               total->per_tuple += plan_run_cost;
+                               context->total.per_tuple += plan_run_cost;
                        }
 
                        /*
@@ -1967,15 +1985,15 @@ cost_qual_eval_walker(Node *node, QualCost *total)
                        if (subplan->parParam == NIL &&
                                (IsA(plan, Sort) ||
                                 IsA(plan, Material)))
-                               total->startup += plan->startup_cost;
+                               context->total.startup += plan->startup_cost;
                        else
-                               total->per_tuple += plan->startup_cost;
+                               context->total.per_tuple += plan->startup_cost;
                }
        }
 
        /* recurse into children */
        return expression_tree_walker(node, cost_qual_eval_walker,
-                                                                 (void *) total);
+                                                                 (void *) context);
 }
 
 
@@ -2042,7 +2060,7 @@ set_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel)
 
        rel->rows = clamp_row_est(nrows);
 
-       cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo);
+       cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo, root);
 
        set_rel_width(root, rel);
 }
index 4d3d926a167fa58b1d2f06af0ae60013cbba26a3..dbfa2c4e58e415981f8b538a7ef535580dea9697 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.225 2007/02/19 02:23:12 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.226 2007/02/22 22:00:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -128,12 +128,12 @@ static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
  * create_plan
  *       Creates the access plan for a query by tracing backwards through the
  *       desired chain of pathnodes, starting at the node 'best_path'.  For
- *       every pathnode found:
- *       (1) Create a corresponding plan node containing appropriate id,
- *               target list, and qualification information.
- *       (2) Modify qual clauses of join nodes so that subplan attributes are
- *               referenced using relative values.
- *       (3) Target lists are not modified, but will be in setrefs.c.
+ *       every pathnode found, we create a corresponding plan node containing
+ *       appropriate id, target list, and qualification information.
+ *
+ *       The tlists and quals in the plan tree are still in planner format,
+ *       ie, Vars still correspond to the parser's numbering.  This will be
+ *       fixed later by setrefs.c.
  *
  *       best_path is the best access path
  *
@@ -421,7 +421,8 @@ create_gating_plan(PlannerInfo *root, Plan *plan, List *quals)
        if (!pseudoconstants)
                return plan;
 
-       return (Plan *) make_result((List *) copyObject(plan->targetlist),
+       return (Plan *) make_result(root,
+                                                               plan->targetlist,
                                                                (Node *) pseudoconstants,
                                                                plan);
 }
@@ -519,7 +520,8 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
        if (best_path->subpaths == NIL)
        {
                /* Generate a Result plan with constant-FALSE gating qual */
-               return (Plan *) make_result(tlist,
+               return (Plan *) make_result(root,
+                                                                       tlist,
                                                                        (Node *) list_make1(makeBoolConst(false,
                                                                                                                                          false)),
                                                                        NULL);
@@ -559,7 +561,7 @@ create_result_plan(PlannerInfo *root, ResultPath *best_path)
 
        quals = order_qual_clauses(root, best_path->quals);
 
-       return make_result(tlist, (Node *) quals, NULL);
+       return make_result(root, tlist, (Node *) quals, NULL);
 }
 
 /*
@@ -682,7 +684,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
                 * node to help it along.
                 */
                if (!is_projection_capable_plan(subplan))
-                       subplan = (Plan *) make_result(newtlist, NULL, subplan);
+                       subplan = (Plan *) make_result(root, newtlist, NULL, subplan);
                else
                        subplan->targetlist = newtlist;
        }
@@ -1065,12 +1067,6 @@ create_bitmap_scan_plan(PlannerInfo *root,
         */
        bitmapqualorig = list_difference_ptr(bitmapqualorig, qpqual);
 
-       /*
-        * Copy the finished bitmapqualorig to make sure we have an independent
-        * copy --- needed in case there are subplans in the index quals
-        */
-       bitmapqualorig = copyObject(bitmapqualorig);
-
        /* Finally ready to build the plan node */
        scan_plan = make_bitmap_heapscan(tlist,
                                                                         qpqual,
@@ -1333,7 +1329,8 @@ create_subqueryscan_plan(PlannerInfo *root, Path *best_path,
        scan_plan = make_subqueryscan(tlist,
                                                                  scan_clauses,
                                                                  scan_relid,
-                                                                 best_path->parent->subplan);
+                                                                 best_path->parent->subplan,
+                                                                 best_path->parent->subrtable);
 
        copy_path_costsize(&scan_plan->scan.plan, best_path);
 
@@ -2115,7 +2112,7 @@ order_qual_clauses(PlannerInfo *root, List *clauses)
                Node       *clause = (Node *) lfirst(lc);
                QualCost        qcost;
 
-               cost_qual_eval_node(&qcost, clause);
+               cost_qual_eval_node(&qcost, clause, root);
                items[i].clause = clause;
                items[i].cost = qcost.per_tuple;
                i++;
@@ -2326,7 +2323,8 @@ SubqueryScan *
 make_subqueryscan(List *qptlist,
                                  List *qpqual,
                                  Index scanrelid,
-                                 Plan *subplan)
+                                 Plan *subplan,
+                                 List *subrtable)
 {
        SubqueryScan *node = makeNode(SubqueryScan);
        Plan       *plan = &node->scan.plan;
@@ -2345,6 +2343,7 @@ make_subqueryscan(List *qptlist,
        plan->righttree = NULL;
        node->scan.scanrelid = scanrelid;
        node->subplan = subplan;
+       node->subrtable = subrtable;
 
        return node;
 }
@@ -2524,7 +2523,7 @@ make_hash(Plan *lefttree)
         * plan; this only affects EXPLAIN display not decisions.
         */
        plan->startup_cost = plan->total_cost;
-       plan->targetlist = copyObject(lefttree->targetlist);
+       plan->targetlist = lefttree->targetlist;
        plan->qual = NIL;
        plan->lefttree = lefttree;
        plan->righttree = NULL;
@@ -2583,7 +2582,7 @@ make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
                          lefttree->plan_width);
        plan->startup_cost = sort_path.startup_cost;
        plan->total_cost = sort_path.total_cost;
-       plan->targetlist = copyObject(lefttree->targetlist);
+       plan->targetlist = lefttree->targetlist;
        plan->qual = NIL;
        plan->lefttree = lefttree;
        plan->righttree = NULL;
@@ -2741,10 +2740,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys)
                         * Do we need to insert a Result node?
                         */
                        if (!is_projection_capable_plan(lefttree))
-                       {
-                               tlist = copyObject(tlist);
-                               lefttree = (Plan *) make_result(tlist, NULL, lefttree);
-                       }
+                               lefttree = (Plan *) make_result(root, tlist, NULL, lefttree);
 
                        /*
                         * Add resjunk entry to input's tlist
@@ -2905,7 +2901,7 @@ make_material(Plan *lefttree)
        Plan       *plan = &node->plan;
 
        /* cost should be inserted by caller */
-       plan->targetlist = copyObject(lefttree->targetlist);
+       plan->targetlist = lefttree->targetlist;
        plan->qual = NIL;
        plan->lefttree = lefttree;
        plan->righttree = NULL;
@@ -2996,12 +2992,12 @@ make_agg(PlannerInfo *root, List *tlist, List *qual,
         */
        if (qual)
        {
-               cost_qual_eval(&qual_cost, qual);
+               cost_qual_eval(&qual_cost, qual, root);
                plan->startup_cost += qual_cost.startup;
                plan->total_cost += qual_cost.startup;
                plan->total_cost += qual_cost.per_tuple * plan->plan_rows;
        }
-       cost_qual_eval(&qual_cost, tlist);
+       cost_qual_eval(&qual_cost, tlist, root);
        plan->startup_cost += qual_cost.startup;
        plan->total_cost += qual_cost.startup;
        plan->total_cost += qual_cost.per_tuple * plan->plan_rows;
@@ -3059,12 +3055,12 @@ make_group(PlannerInfo *root,
         */
        if (qual)
        {
-               cost_qual_eval(&qual_cost, qual);
+               cost_qual_eval(&qual_cost, qual, root);
                plan->startup_cost += qual_cost.startup;
                plan->total_cost += qual_cost.startup;
                plan->total_cost += qual_cost.per_tuple * plan->plan_rows;
        }
-       cost_qual_eval(&qual_cost, tlist);
+       cost_qual_eval(&qual_cost, tlist, root);
        plan->startup_cost += qual_cost.startup;
        plan->total_cost += qual_cost.startup;
        plan->total_cost += qual_cost.per_tuple * plan->plan_rows;
@@ -3108,7 +3104,7 @@ make_unique(Plan *lefttree, List *distinctList)
         * has a better idea.
         */
 
-       plan->targetlist = copyObject(lefttree->targetlist);
+       plan->targetlist = lefttree->targetlist;
        plan->qual = NIL;
        plan->lefttree = lefttree;
        plan->righttree = NULL;
@@ -3174,7 +3170,7 @@ make_setop(SetOpCmd cmd, Plan *lefttree,
        if (plan->plan_rows < 1)
                plan->plan_rows = 1;
 
-       plan->targetlist = copyObject(lefttree->targetlist);
+       plan->targetlist = lefttree->targetlist;
        plan->qual = NIL;
        plan->lefttree = lefttree;
        plan->righttree = NULL;
@@ -3272,7 +3268,7 @@ make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount,
                        plan->plan_rows = 1;
        }
 
-       plan->targetlist = copyObject(lefttree->targetlist);
+       plan->targetlist = lefttree->targetlist;
        plan->qual = NIL;
        plan->lefttree = lefttree;
        plan->righttree = NULL;
@@ -3293,7 +3289,8 @@ make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount,
  * cost.  In either case, tlist eval cost is not to be included here.
  */
 Result *
-make_result(List *tlist,
+make_result(PlannerInfo *root,
+                       List *tlist,
                        Node *resconstantqual,
                        Plan *subplan)
 {
@@ -3312,7 +3309,7 @@ make_result(List *tlist,
                {
                        QualCost        qual_cost;
 
-                       cost_qual_eval(&qual_cost, (List *) resconstantqual);
+                       cost_qual_eval(&qual_cost, (List *) resconstantqual, root);
                        /* resconstantqual is evaluated once at startup */
                        plan->startup_cost += qual_cost.startup + qual_cost.per_tuple;
                        plan->total_cost += qual_cost.startup + qual_cost.per_tuple;
index 406cc9dd49665845ef9d889565dbd1226c72b236..5411072b8dbb5f15e2c365f874b817ebc21bd197 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.28 2007/02/20 17:32:15 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.29 2007/02/22 22:00:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -188,10 +188,10 @@ optimize_minmax_aggregates(PlannerInfo *root, List *tlist, Path *best_path)
        /*
         * Generate the output plan --- basically just a Result
         */
-       plan = (Plan *) make_result(tlist, hqual, NULL);
+       plan = (Plan *) make_result(root, tlist, hqual, NULL);
 
        /* Account for evaluation cost of the tlist (make_result did the rest) */
-       cost_qual_eval(&tlist_cost, tlist);
+       cost_qual_eval(&tlist_cost, tlist, root);
        plan->startup_cost += tlist_cost.startup;
        plan->total_cost += tlist_cost.startup + tlist_cost.per_tuple;
 
index 3bb603a0f614bb53ff4cbb0eebefee770afbd819..b45288dc5b8faafe9a827aacb56fbcccd69c6a0c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.214 2007/02/20 17:32:15 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.215 2007/02/22 22:00:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,6 +88,8 @@ planner(Query *parse, bool isCursor, int cursorOptions,
        double          tuple_fraction;
        PlannerInfo *root;
        Plan       *top_plan;
+       ListCell   *lp,
+                          *lr;
 
        /*
         * Set up global state for this planner invocation.  This data is needed
@@ -99,7 +101,9 @@ planner(Query *parse, bool isCursor, int cursorOptions,
 
        glob->boundParams = boundParams;
        glob->paramlist = NIL;
-       glob->next_plan_id = 0;
+       glob->subplans = NIL;
+       glob->subrtables = NIL;
+       glob->finalrtable = NIL;
 
        /* Determine what fraction of the plan is likely to be scanned */
        if (isCursor)
@@ -132,7 +136,17 @@ planner(Query *parse, bool isCursor, int cursorOptions,
        }
 
        /* final cleanup of the plan */
-       top_plan = set_plan_references(top_plan, parse->rtable);
+       Assert(glob->finalrtable == NIL);
+       top_plan = set_plan_references(glob, top_plan, root->parse->rtable);
+       /* ... and the subplans (both regular subplans and initplans) */
+       Assert(list_length(glob->subplans) == list_length(glob->subrtables));
+       forboth(lp, glob->subplans, lr, glob->subrtables)
+       {
+               Plan   *subplan = (Plan *) lfirst(lp);
+               List   *subrtable = (List *) lfirst(lr);
+
+               lfirst(lp) = set_plan_references(glob, subplan, subrtable);
+       }
 
        /* build the PlannedStmt result */
        result = makeNode(PlannedStmt);
@@ -140,9 +154,10 @@ planner(Query *parse, bool isCursor, int cursorOptions,
        result->commandType = parse->commandType;
        result->canSetTag = parse->canSetTag;
        result->planTree = top_plan;
-       result->rtable = parse->rtable;
+       result->rtable = glob->finalrtable;
        result->resultRelations = root->resultRelations;
        result->into = parse->into;
+       result->subplans = glob->subplans;
        result->returningLists = root->returningLists;
        result->rowMarks = parse->rowMarks;
        result->nParamExec = list_length(glob->paramlist);
@@ -182,7 +197,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
                                 Index level, double tuple_fraction,
                                 PlannerInfo **subroot)
 {
-       int                     saved_plan_id = glob->next_plan_id;
+       int                     num_old_subplans = list_length(glob->subplans);
        PlannerInfo *root;
        Plan       *plan;
        List       *newHaving;
@@ -384,7 +399,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
         * initPlan list and extParam/allParam sets for plan nodes, and attach the
         * initPlans to the top plan node.
         */
-       if (root->glob->next_plan_id != saved_plan_id || root->query_level > 1)
+       if (list_length(glob->subplans) != num_old_subplans ||
+               root->query_level > 1)
                SS_finalize_plan(root, plan);
 
        /* Return internal info if caller wants it */
@@ -621,7 +637,8 @@ inheritance_planner(PlannerInfo *root)
         * If we managed to exclude every child rel, return a dummy plan
         */
        if (subplans == NIL)
-               return (Plan *) make_result(tlist,
+               return (Plan *) make_result(root,
+                                                                       tlist,
                                                                        (Node *) list_make1(makeBoolConst(false,
                                                                                                                                          false)),
                                                                        NULL);
@@ -639,6 +656,10 @@ inheritance_planner(PlannerInfo *root)
         */
        parse->rtable = rtable;
 
+       /* Suppress Append if there's only one surviving child rel */
+       if (list_length(subplans) == 1)
+               return (Plan *) linitial(subplans);
+
        return (Plan *) make_append(subplans, true, tlist);
 }
 
@@ -897,7 +918,9 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                 */
                                if (!is_projection_capable_plan(result_plan))
                                {
-                                       result_plan = (Plan *) make_result(sub_tlist, NULL,
+                                       result_plan = (Plan *) make_result(root,
+                                                                                                          sub_tlist,
+                                                                                                          NULL,
                                                                                                           result_plan);
                                }
                                else
@@ -928,7 +951,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                 * tuples) --- so make_agg() and make_group() are responsible
                                 * for computing the added cost.
                                 */
-                               cost_qual_eval(&tlist_cost, sub_tlist);
+                               cost_qual_eval(&tlist_cost, sub_tlist, root);
                                result_plan->startup_cost += tlist_cost.startup;
                                result_plan->total_cost += tlist_cost.startup +
                                        tlist_cost.per_tuple * result_plan->plan_rows;
@@ -1051,7 +1074,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                 * this routine to avoid having to generate the plan in the
                                 * first place.
                                 */
-                               result_plan = (Plan *) make_result(tlist,
+                               result_plan = (Plan *) make_result(root,
+                                                                                                  tlist,
                                                                                                   parse->havingQual,
                                                                                                   NULL);
                        }
@@ -1110,6 +1134,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
        {
                List       *rlist;
 
+               Assert(parse->resultRelation);
                rlist = set_returning_clause_references(parse->returningList,
                                                                                                result_plan,
                                                                                                parse->resultRelation);
@@ -1544,7 +1569,7 @@ choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
  * pass down only c,d,a+b, but it's not really worth the trouble to
  * eliminate simple var references from the subplan.  We will avoid doing
  * the extra computation to recompute a+b at the outer level; see
- * replace_vars_with_subplan_refs() in setrefs.c.)
+ * fix_upper_expr() in setrefs.c.)
  *
  * If we are grouping or aggregating, *and* there are no non-Var grouping
  * expressions, then the returned tlist is effectively dummy; we do not
index 3d9f5486bccfce75f312eee1be38fb6b7ec90a75..aaa383742e7bdb2b798f72920a934aaec2176dff 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.130 2007/02/19 02:23:12 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.131 2007/02/22 22:00:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,48 +40,60 @@ typedef struct
        tlist_vinfo vars[1];            /* VARIABLE LENGTH ARRAY */
 } indexed_tlist;                               /* VARIABLE LENGTH STRUCT */
 
+typedef struct
+{
+       int                     rtoffset;
+} fix_scan_expr_context;
+
 typedef struct
 {
        indexed_tlist *outer_itlist;
        indexed_tlist *inner_itlist;
        Index           acceptable_rel;
-} join_references_context;
+       int                     rtoffset;
+} fix_join_expr_context;
 
 typedef struct
 {
        indexed_tlist *subplan_itlist;
        Index           subvarno;
-} replace_vars_with_subplan_refs_context;
+       int                     rtoffset;
+} fix_upper_expr_context;
+
+#define fix_scan_list(lst, rtoffset) \
+       ((List *) fix_scan_expr((Node *) (lst), rtoffset))
 
-static Plan *set_subqueryscan_references(SubqueryScan *plan, List *rtable);
+static Plan *set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset);
+static Plan *set_subqueryscan_references(PlannerGlobal *glob,
+                                                                                SubqueryScan *plan,
+                                                                                int rtoffset);
 static bool trivial_subqueryscan(SubqueryScan *plan);
-static void adjust_plan_varnos(Plan *plan, int rtoffset);
-static void adjust_expr_varnos(Node *node, int rtoffset);
-static bool adjust_expr_varnos_walker(Node *node, int *context);
-static void fix_expr_references(Plan *plan, Node *node);
-static bool fix_expr_references_walker(Node *node, void *context);
-static void set_join_references(Join *join);
+static Node *fix_scan_expr(Node *node, int rtoffset);
+static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
+static void set_join_references(Join *join, int rtoffset);
 static void set_inner_join_references(Plan *inner_plan,
                                                  indexed_tlist *outer_itlist);
-static void set_uppernode_references(Plan *plan, Index subvarno);
+static void set_upper_references(Plan *plan, Index subvarno, int rtoffset);
 static indexed_tlist *build_tlist_index(List *tlist);
 static Var *search_indexed_tlist_for_var(Var *var,
                                                         indexed_tlist *itlist,
-                                                        Index newvarno);
+                                                        Index newvarno,
+                                                        int rtoffset);
 static Var *search_indexed_tlist_for_non_var(Node *node,
                                                                 indexed_tlist *itlist,
                                                                 Index newvarno);
-static List *join_references(List *clauses,
-                               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,
-                                                          indexed_tlist *subplan_itlist,
-                                                          Index subvarno);
-static Node *replace_vars_with_subplan_refs_mutator(Node *node,
-                                                       replace_vars_with_subplan_refs_context *context);
+static List *fix_join_expr(List *clauses,
+                                                  indexed_tlist *outer_itlist,
+                                                  indexed_tlist *inner_itlist,
+                                                  Index acceptable_rel, int rtoffset);
+static Node *fix_join_expr_mutator(Node *node,
+                                                                  fix_join_expr_context *context);
+static Node *fix_upper_expr(Node *node,
+                                                       indexed_tlist *subplan_itlist,
+                                                       Index subvarno,
+                                                       int rtoffset);
+static Node *fix_upper_expr_mutator(Node *node,
+                                                                       fix_upper_expr_context *context);
 static bool fix_opfuncids_walker(Node *node, void *context);
 
 
@@ -96,34 +108,87 @@ static bool fix_opfuncids_walker(Node *node, void *context);
  *
  * This is the final processing pass of the planner/optimizer. The plan
  * tree is complete; we just have to adjust some representational details
- * for the convenience of the executor.  We update Vars in upper plan nodes
- * to refer to the outputs of their subplans, and we compute regproc OIDs
- * for operators (ie, we look up the function that implements each op).
+ * for the convenience of the executor:
+ *
+ * 1. We flatten the various subquery rangetables into a single list, and
+ * zero out RangeTblEntry fields that are not useful to the executor.
+ *
+ * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable.
+ *
+ * 3. We adjust Vars in upper plan nodes to refer to the outputs of their
+ * subplans.
+ *
+ * 4. We compute regproc OIDs for operators (ie, we look up the function
+ * that implements each op).
  *
  * We also perform one final optimization step, which is to delete
  * SubqueryScan plan nodes that aren't doing anything useful (ie, have
  * no qual and a no-op targetlist).  The reason for doing this last is that
  * it can't readily be done before set_plan_references, because it would
- * break set_uppernode_references: the Vars in the subquery's top tlist
- * won't match up with the Vars in the outer plan tree.  The SubqueryScan
+ * break set_upper_references: the Vars in the subquery's top tlist
+ * wouldn't match up with the Vars in the outer plan tree.  The SubqueryScan
  * serves a necessary function as a buffer between outer query and subquery
- * variable numbering ... but the executor doesn't care about that, only the
- * planner.
+ * variable numbering ... but after we've flattened the rangetable this is
+ * no longer a problem, since there's only one rtindex namespace.
  *
  * set_plan_references recursively traverses the whole plan tree.
  *
+ * Inputs:
+ *     glob: global data for planner run
+ *     plan: the topmost node of the plan
+ *     rtable: the rangetable for the current subquery
+ *
  * The return value is normally the same Plan node passed in, but can be
  * different when the passed-in Plan is a SubqueryScan we decide isn't needed.
  *
- * Note: to delete a SubqueryScan, we have to renumber Vars in its child nodes
- * and append the modified subquery rangetable to the outer rangetable.
- * Therefore "rtable" is an in/out argument and really should be declared
- * "List **".  But in the interest of notational simplicity we don't do that.
- * (Since rtable can't be NIL if there's a SubqueryScan, the list header
- * address won't change when we append a subquery rangetable.)
+ * The flattened rangetable entries are appended to glob->finalrtable.
+ *
+ * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
+ * to process targetlist and qual expressions.  We can assume that the Plan
+ * nodes were just built by the planner and are not multiply referenced, but
+ * it's not so safe to assume that for expression tree nodes.
  */
 Plan *
-set_plan_references(Plan *plan, List *rtable)
+set_plan_references(PlannerGlobal *glob, Plan *plan, List *rtable)
+{
+       int                     rtoffset = list_length(glob->finalrtable);
+       ListCell   *lc;
+
+       /*
+        * In the flat rangetable, we zero out substructure pointers that are
+        * not needed by the executor; this reduces the storage space and
+        * copying cost for cached plans.
+        */
+       foreach(lc, rtable)
+       {
+               RangeTblEntry  *rte = (RangeTblEntry *) lfirst(lc);
+               RangeTblEntry  *newrte;
+
+               /* flat copy to duplicate all the scalar fields */
+               newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
+               memcpy(newrte, rte, sizeof(RangeTblEntry));
+
+               /* zap unneeded sub-structure (we keep only the eref Alias) */
+               newrte->subquery = NULL;
+               newrte->funcexpr = NULL;
+               newrte->funccoltypes = NIL;
+               newrte->funccoltypmods = NIL;
+               newrte->values_lists = NIL;
+               newrte->joinaliasvars = NIL;
+               newrte->alias = NULL;
+
+               glob->finalrtable = lappend(glob->finalrtable, newrte);
+       }
+
+       /* Now fix the Plan tree */
+       return set_plan_refs(glob, plan, rtoffset);
+}
+
+/*
+ * set_plan_refs: recurse through the Plan nodes of a single subquery level
+ */
+static Plan *
+set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 {
        ListCell   *l;
 
@@ -136,73 +201,109 @@ set_plan_references(Plan *plan, List *rtable)
        switch (nodeTag(plan))
        {
                case T_SeqScan:
-                       fix_expr_references(plan, (Node *) plan->targetlist);
-                       fix_expr_references(plan, (Node *) plan->qual);
+                       {
+                               SeqScan *splan = (SeqScan *) plan;
+
+                               splan->scanrelid += rtoffset;
+                               splan->plan.targetlist =
+                                       fix_scan_list(splan->plan.targetlist, rtoffset);
+                               splan->plan.qual =
+                                       fix_scan_list(splan->plan.qual, rtoffset);
+                       }
                        break;
                case T_IndexScan:
-                       fix_expr_references(plan, (Node *) plan->targetlist);
-                       fix_expr_references(plan, (Node *) plan->qual);
-                       fix_expr_references(plan,
-                                                               (Node *) ((IndexScan *) plan)->indexqual);
-                       fix_expr_references(plan,
-                                                               (Node *) ((IndexScan *) plan)->indexqualorig);
+                       {
+                               IndexScan *splan = (IndexScan *) plan;
+
+                               splan->scan.scanrelid += rtoffset;
+                               splan->scan.plan.targetlist =
+                                       fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+                               splan->scan.plan.qual =
+                                       fix_scan_list(splan->scan.plan.qual, rtoffset);
+                               splan->indexqual =
+                                       fix_scan_list(splan->indexqual, rtoffset);
+                               splan->indexqualorig =
+                                       fix_scan_list(splan->indexqualorig, rtoffset);
+                       }
                        break;
                case T_BitmapIndexScan:
-                       /* no need to fix targetlist and qual */
-                       Assert(plan->targetlist == NIL);
-                       Assert(plan->qual == NIL);
-                       fix_expr_references(plan,
-                                                        (Node *) ((BitmapIndexScan *) plan)->indexqual);
-                       fix_expr_references(plan,
-                                                (Node *) ((BitmapIndexScan *) plan)->indexqualorig);
+                       {
+                               BitmapIndexScan *splan = (BitmapIndexScan *) plan;
+
+                               splan->scan.scanrelid += rtoffset;
+                               /* no need to fix targetlist and qual */
+                               Assert(splan->scan.plan.targetlist == NIL);
+                               Assert(splan->scan.plan.qual == NIL);
+                               splan->indexqual =
+                                       fix_scan_list(splan->indexqual, rtoffset);
+                               splan->indexqualorig =
+                                       fix_scan_list(splan->indexqualorig, rtoffset);
+                       }
                        break;
                case T_BitmapHeapScan:
-                       fix_expr_references(plan, (Node *) plan->targetlist);
-                       fix_expr_references(plan, (Node *) plan->qual);
-                       fix_expr_references(plan,
-                                                (Node *) ((BitmapHeapScan *) plan)->bitmapqualorig);
+                       {
+                               BitmapHeapScan *splan = (BitmapHeapScan *) plan;
+
+                               splan->scan.scanrelid += rtoffset;
+                               splan->scan.plan.targetlist =
+                                       fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+                               splan->scan.plan.qual =
+                                       fix_scan_list(splan->scan.plan.qual, rtoffset);
+                               splan->bitmapqualorig =
+                                       fix_scan_list(splan->bitmapqualorig, rtoffset);
+                       }
                        break;
                case T_TidScan:
-                       fix_expr_references(plan, (Node *) plan->targetlist);
-                       fix_expr_references(plan, (Node *) plan->qual);
-                       fix_expr_references(plan, (Node *) ((TidScan *) plan)->tidquals);
+                       {
+                               TidScan *splan = (TidScan *) plan;
+
+                               splan->scan.scanrelid += rtoffset;
+                               splan->scan.plan.targetlist =
+                                       fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+                               splan->scan.plan.qual =
+                                       fix_scan_list(splan->scan.plan.qual, rtoffset);
+                               splan->tidquals =
+                                       fix_scan_list(splan->tidquals, rtoffset);
+                       }
                        break;
                case T_SubqueryScan:
                        /* Needs special treatment, see comments below */
-                       return set_subqueryscan_references((SubqueryScan *) plan, rtable);
+                       return set_subqueryscan_references(glob,
+                                                                                          (SubqueryScan *) plan,
+                                                                                          rtoffset);
                case T_FunctionScan:
-                       fix_expr_references(plan, (Node *) plan->targetlist);
-                       fix_expr_references(plan, (Node *) plan->qual);
-                       fix_expr_references(plan, ((FunctionScan *) plan)->funcexpr);
+                       {
+                               FunctionScan *splan = (FunctionScan *) plan;
+
+                               splan->scan.scanrelid += rtoffset;
+                               splan->scan.plan.targetlist =
+                                       fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+                               splan->scan.plan.qual =
+                                       fix_scan_list(splan->scan.plan.qual, rtoffset);
+                               splan->funcexpr =
+                                       fix_scan_expr(splan->funcexpr, rtoffset);
+                       }
                        break;
                case T_ValuesScan:
-                       fix_expr_references(plan, (Node *) plan->targetlist);
-                       fix_expr_references(plan, (Node *) plan->qual);
-                       fix_expr_references(plan,
-                                                               (Node *) ((ValuesScan *) plan)->values_lists);
+                       {
+                               ValuesScan *splan = (ValuesScan *) plan;
+
+                               splan->scan.scanrelid += rtoffset;
+                               splan->scan.plan.targetlist =
+                                       fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+                               splan->scan.plan.qual =
+                                       fix_scan_list(splan->scan.plan.qual, rtoffset);
+                               splan->values_lists =
+                                       fix_scan_list(splan->values_lists, rtoffset);
+                       }
                        break;
+
                case T_NestLoop:
-                       set_join_references((Join *) plan);
-                       fix_expr_references(plan, (Node *) plan->targetlist);
-                       fix_expr_references(plan, (Node *) plan->qual);
-                       fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
-                       break;
                case T_MergeJoin:
-                       set_join_references((Join *) plan);
-                       fix_expr_references(plan, (Node *) plan->targetlist);
-                       fix_expr_references(plan, (Node *) plan->qual);
-                       fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
-                       fix_expr_references(plan,
-                                                               (Node *) ((MergeJoin *) plan)->mergeclauses);
-                       break;
                case T_HashJoin:
-                       set_join_references((Join *) plan);
-                       fix_expr_references(plan, (Node *) plan->targetlist);
-                       fix_expr_references(plan, (Node *) plan->qual);
-                       fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
-                       fix_expr_references(plan,
-                                                               (Node *) ((HashJoin *) plan)->hashclauses);
+                       set_join_references((Join *) plan, rtoffset);
                        break;
+
                case T_Hash:
                case T_Material:
                case T_Sort:
@@ -211,75 +312,113 @@ set_plan_references(Plan *plan, List *rtable)
 
                        /*
                         * These plan types don't actually bother to evaluate their
-                        * targetlists (because they just return their unmodified input
-                        * tuples).  The optimizer is lazy about creating really valid
-                        * targetlists for them --- it tends to just put in a pointer to
-                        * the child plan node's tlist.  Hence, we leave the tlist alone.
-                        * In particular, we do not want to process subplans in the tlist,
-                        * since we will likely end up reprocessing subplans that also
-                        * appear in lower levels of the plan tree!
-                        *
+                        * targetlistsbecause they just return their unmodified input
+                        * tuples.  Even though the targetlist won't be used by the
+                        * executor, we fix it up for possible use by EXPLAIN (not to
+                        * mention ease of debugging --- wrong varnos are very confusing).
+                        */
+                       plan->targetlist =
+                               fix_scan_list(plan->targetlist, rtoffset);
+                       /*
                         * Since these plan types don't check quals either, we should not
                         * find any qual expression attached to them.
                         */
                        Assert(plan->qual == NIL);
                        break;
                case T_Limit:
-
-                       /*
-                        * Like the plan types above, Limit doesn't evaluate its tlist or
-                        * quals.  It does have live expressions for limit/offset,
-                        * however.
-                        */
-                       Assert(plan->qual == NIL);
-                       fix_expr_references(plan, ((Limit *) plan)->limitOffset);
-                       fix_expr_references(plan, ((Limit *) plan)->limitCount);
+                       {
+                               Limit *splan = (Limit *) plan;
+
+                               /*
+                                * Like the plan types above, Limit doesn't evaluate its tlist
+                                * or quals.  It does have live expressions for limit/offset,
+                                * however.
+                                */
+                               splan->plan.targetlist =
+                                       fix_scan_list(splan->plan.targetlist, rtoffset);
+                               Assert(splan->plan.qual == NIL);
+                               splan->limitOffset =
+                                       fix_scan_expr(splan->limitOffset, rtoffset);
+                               splan->limitCount =
+                                       fix_scan_expr(splan->limitCount, rtoffset);
+                       }
                        break;
                case T_Agg:
                case T_Group:
-                       set_uppernode_references(plan, (Index) 0);
-                       fix_expr_references(plan, (Node *) plan->targetlist);
-                       fix_expr_references(plan, (Node *) plan->qual);
+                       set_upper_references(plan, (Index) 0, rtoffset);
                        break;
                case T_Result:
-
-                       /*
-                        * Result may or may not have a subplan; no need to fix up subplan
-                        * references if it hasn't got one...
-                        *
-                        * XXX why does Result use a different subvarno from Agg/Group?
-                        */
-                       if (plan->lefttree != NULL)
-                               set_uppernode_references(plan, (Index) OUTER);
-                       fix_expr_references(plan, (Node *) plan->targetlist);
-                       fix_expr_references(plan, (Node *) plan->qual);
-                       fix_expr_references(plan, ((Result *) plan)->resconstantqual);
+                       {
+                               Result *splan = (Result *) plan;
+
+                               /*
+                                * Result may or may not have a subplan; if not, it's more
+                                * like a scan node than an upper node.
+                                *
+                                * XXX why does Result use a different subvarno from Agg/Group?
+                                */
+                               if (splan->plan.lefttree != NULL)
+                                       set_upper_references(plan, (Index) OUTER, rtoffset);
+                               else
+                               {
+                                       splan->plan.targetlist =
+                                               fix_scan_list(splan->plan.targetlist, rtoffset);
+                                       splan->plan.qual =
+                                               fix_scan_list(splan->plan.qual, rtoffset);
+                               }
+                               /* resconstantqual can't contain any subplan variable refs */
+                               splan->resconstantqual =
+                                       fix_scan_expr(splan->resconstantqual, rtoffset);
+                       }
                        break;
                case T_Append:
-
-                       /*
-                        * Append, like Sort et al, doesn't actually evaluate its
-                        * targetlist or check quals, and we haven't bothered to give it
-                        * its own tlist copy. So, don't fix targetlist/qual. But do
-                        * recurse into child plans.
-                        */
-                       Assert(plan->qual == NIL);
-                       foreach(l, ((Append *) plan)->appendplans)
-                               lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);
+                       {
+                               Append *splan = (Append *) plan;
+
+                               /*
+                                * Append, like Sort et al, doesn't actually evaluate its
+                                * targetlist or check quals.
+                                */
+                               splan->plan.targetlist =
+                                       fix_scan_list(splan->plan.targetlist, rtoffset);
+                               Assert(splan->plan.qual == NIL);
+                               foreach(l, splan->appendplans)
+                               {
+                                       lfirst(l) = set_plan_refs(glob,
+                                                                                         (Plan *) lfirst(l),
+                                                                                         rtoffset);
+                               }
+                       }
                        break;
                case T_BitmapAnd:
-                       /* BitmapAnd works like Append, but has no tlist */
-                       Assert(plan->targetlist == NIL);
-                       Assert(plan->qual == NIL);
-                       foreach(l, ((BitmapAnd *) plan)->bitmapplans)
-                               lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);
+                       {
+                               BitmapAnd *splan = (BitmapAnd *) plan;
+
+                               /* BitmapAnd works like Append, but has no tlist */
+                               Assert(splan->plan.targetlist == NIL);
+                               Assert(splan->plan.qual == NIL);
+                               foreach(l, splan->bitmapplans)
+                               {
+                                       lfirst(l) = set_plan_refs(glob,
+                                                                                         (Plan *) lfirst(l),
+                                                                                         rtoffset);
+                               }
+                       }
                        break;
                case T_BitmapOr:
-                       /* BitmapOr works like Append, but has no tlist */
-                       Assert(plan->targetlist == NIL);
-                       Assert(plan->qual == NIL);
-                       foreach(l, ((BitmapOr *) plan)->bitmapplans)
-                               lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);
+                       {
+                               BitmapOr *splan = (BitmapOr *) plan;
+
+                               /* BitmapOr works like Append, but has no tlist */
+                               Assert(splan->plan.targetlist == NIL);
+                               Assert(splan->plan.qual == NIL);
+                               foreach(l, splan->bitmapplans)
+                               {
+                                       lfirst(l) = set_plan_refs(glob,
+                                                                                         (Plan *) lfirst(l),
+                                                                                         rtoffset);
+                               }
+                       }
                        break;
                default:
                        elog(ERROR, "unrecognized node type: %d",
@@ -288,25 +427,15 @@ set_plan_references(Plan *plan, List *rtable)
        }
 
        /*
-        * Now recurse into child plans and initplans, if any
+        * Now recurse into child plans, if any
         *
         * NOTE: it is essential that we recurse into child plans AFTER we set
         * subplan references in this plan's tlist and quals.  If we did the
         * reference-adjustments bottom-up, then we would fail to match this
         * plan's var nodes against the already-modified nodes of the children.
-        * Fortunately, that consideration doesn't apply to SubPlan nodes; else
-        * we'd need two passes over the expression trees.
         */
-       plan->lefttree = set_plan_references(plan->lefttree, rtable);
-       plan->righttree = set_plan_references(plan->righttree, rtable);
-
-       foreach(l, plan->initPlan)
-       {
-               SubPlan    *sp = (SubPlan *) lfirst(l);
-
-               Assert(IsA(sp, SubPlan));
-               sp->plan = set_plan_references(sp->plan, sp->rtable);
-       }
+       plan->lefttree = set_plan_refs(glob, plan->lefttree, rtoffset);
+       plan->righttree = set_plan_refs(glob, plan->righttree, rtoffset);
 
        return plan;
 }
@@ -319,54 +448,29 @@ set_plan_references(Plan *plan, List *rtable)
  * to do the normal processing on it.
  */
 static Plan *
-set_subqueryscan_references(SubqueryScan *plan, List *rtable)
+set_subqueryscan_references(PlannerGlobal *glob,
+                                                       SubqueryScan *plan,
+                                                       int rtoffset)
 {
        Plan       *result;
-       RangeTblEntry *rte;
-       ListCell   *l;
 
        /* First, recursively process the subplan */
-       rte = rt_fetch(plan->scan.scanrelid, rtable);
-       Assert(rte->rtekind == RTE_SUBQUERY);
-       plan->subplan = set_plan_references(plan->subplan,
-                                                                               rte->subquery->rtable);
-
-       /*
-        * We have to process any initplans too; set_plan_references can't do it
-        * for us because of the possibility of double-processing.
-        */
-       foreach(l, plan->scan.plan.initPlan)
-       {
-               SubPlan    *sp = (SubPlan *) lfirst(l);
+       plan->subplan = set_plan_references(glob, plan->subplan, plan->subrtable);
 
-               Assert(IsA(sp, SubPlan));
-               sp->plan = set_plan_references(sp->plan, sp->rtable);
-       }
+       /* subrtable is no longer needed in the plan tree */
+       plan->subrtable = NIL;
 
        if (trivial_subqueryscan(plan))
        {
                /*
-                * We can omit the SubqueryScan node and just pull up the subplan. We
-                * have to merge its rtable into the outer rtable, which means
-                * adjusting varnos throughout the subtree.
+                * We can omit the SubqueryScan node and just pull up the subplan.
                 */
-               int                     rtoffset = list_length(rtable);
-               List       *sub_rtable;
                ListCell   *lp,
                                   *lc;
 
-               sub_rtable = copyObject(rte->subquery->rtable);
-               rtable = list_concat(rtable, sub_rtable);
-
-               /*
-                * we have to copy the subplan to make sure there are no duplicately
-                * linked nodes in it, else adjust_plan_varnos might increment some
-                * varnos twice
-                */
-               result = copyObject(plan->subplan);
-
-               adjust_plan_varnos(result, rtoffset);
+               result = plan->subplan;
 
+               /* We have to be sure we don't lose any initplans */
                result->initPlan = list_concat(plan->scan.plan.initPlan,
                                                                           result->initPlan);
 
@@ -391,14 +495,17 @@ set_subqueryscan_references(SubqueryScan *plan, List *rtable)
                /*
                 * Keep the SubqueryScan node.  We have to do the processing that
                 * set_plan_references would otherwise have done on it.  Notice we do
-                * not do set_uppernode_references() here, because a SubqueryScan will
+                * not do set_upper_references() here, because a SubqueryScan will
                 * always have been created with correct references to its subplan's
                 * outputs to begin with.
                 */
-               result = (Plan *) plan;
+               plan->scan.scanrelid += rtoffset;
+               plan->scan.plan.targetlist =
+                       fix_scan_list(plan->scan.plan.targetlist, rtoffset);
+               plan->scan.plan.qual =
+                       fix_scan_list(plan->scan.plan.qual, rtoffset);
 
-               fix_expr_references(result, (Node *) result->targetlist);
-               fix_expr_references(result, (Node *) result->qual);
+               result = (Plan *) plan;
        }
 
        return result;
@@ -463,261 +570,72 @@ trivial_subqueryscan(SubqueryScan *plan)
 }
 
 /*
- * adjust_plan_varnos
- *             Offset varnos and other rangetable indexes in a plan tree by rtoffset.
- */
-static void
-adjust_plan_varnos(Plan *plan, int rtoffset)
-{
-       ListCell   *l;
-
-       if (plan == NULL)
-               return;
-
-       /*
-        * Plan-type-specific fixes
-        */
-       switch (nodeTag(plan))
-       {
-               case T_SeqScan:
-                       ((SeqScan *) plan)->scanrelid += rtoffset;
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       break;
-               case T_IndexScan:
-                       ((IndexScan *) plan)->scan.scanrelid += rtoffset;
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       adjust_expr_varnos((Node *) ((IndexScan *) plan)->indexqual,
-                                                          rtoffset);
-                       adjust_expr_varnos((Node *) ((IndexScan *) plan)->indexqualorig,
-                                                          rtoffset);
-                       break;
-               case T_BitmapIndexScan:
-                       ((BitmapIndexScan *) plan)->scan.scanrelid += rtoffset;
-                       /* no need to fix targetlist and qual */
-                       Assert(plan->targetlist == NIL);
-                       Assert(plan->qual == NIL);
-                       adjust_expr_varnos((Node *) ((BitmapIndexScan *) plan)->indexqual,
-                                                          rtoffset);
-                       adjust_expr_varnos((Node *) ((BitmapIndexScan *) plan)->indexqualorig,
-                                                          rtoffset);
-                       break;
-               case T_BitmapHeapScan:
-                       ((BitmapHeapScan *) plan)->scan.scanrelid += rtoffset;
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       adjust_expr_varnos((Node *) ((BitmapHeapScan *) plan)->bitmapqualorig,
-                                                          rtoffset);
-                       break;
-               case T_TidScan:
-                       ((TidScan *) plan)->scan.scanrelid += rtoffset;
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       adjust_expr_varnos((Node *) ((TidScan *) plan)->tidquals,
-                                                          rtoffset);
-                       break;
-               case T_SubqueryScan:
-                       ((SubqueryScan *) plan)->scan.scanrelid += rtoffset;
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       /* we should not recurse into the subquery! */
-                       break;
-               case T_FunctionScan:
-                       ((FunctionScan *) plan)->scan.scanrelid += rtoffset;
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       adjust_expr_varnos(((FunctionScan *) plan)->funcexpr,
-                                                          rtoffset);
-                       break;
-               case T_ValuesScan:
-                       ((ValuesScan *) plan)->scan.scanrelid += rtoffset;
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       adjust_expr_varnos((Node *) ((ValuesScan *) plan)->values_lists,
-                                                          rtoffset);
-                       break;
-               case T_NestLoop:
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       adjust_expr_varnos((Node *) ((Join *) plan)->joinqual, rtoffset);
-                       break;
-               case T_MergeJoin:
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       adjust_expr_varnos((Node *) ((Join *) plan)->joinqual, rtoffset);
-                       adjust_expr_varnos((Node *) ((MergeJoin *) plan)->mergeclauses,
-                                                          rtoffset);
-                       break;
-               case T_HashJoin:
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       adjust_expr_varnos((Node *) ((Join *) plan)->joinqual, rtoffset);
-                       adjust_expr_varnos((Node *) ((HashJoin *) plan)->hashclauses,
-                                                          rtoffset);
-                       break;
-               case T_Hash:
-               case T_Material:
-               case T_Sort:
-               case T_Unique:
-               case T_SetOp:
-
-                       /*
-                        * Even though the targetlist won't be used by the executor, we
-                        * fix it up for possible use by EXPLAIN (not to mention ease of
-                        * debugging --- wrong varnos are very confusing).
-                        */
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       Assert(plan->qual == NIL);
-                       break;
-               case T_Limit:
-
-                       /*
-                        * Like the plan types above, Limit doesn't evaluate its tlist or
-                        * quals.  It does have live expressions for limit/offset,
-                        * however.
-                        */
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       Assert(plan->qual == NIL);
-                       adjust_expr_varnos(((Limit *) plan)->limitOffset, rtoffset);
-                       adjust_expr_varnos(((Limit *) plan)->limitCount, rtoffset);
-                       break;
-               case T_Agg:
-               case T_Group:
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       break;
-               case T_Result:
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       adjust_expr_varnos((Node *) plan->qual, rtoffset);
-                       adjust_expr_varnos(((Result *) plan)->resconstantqual, rtoffset);
-                       break;
-               case T_Append:
-                       adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
-                       Assert(plan->qual == NIL);
-                       foreach(l, ((Append *) plan)->appendplans)
-                               adjust_plan_varnos((Plan *) lfirst(l), rtoffset);
-                       break;
-               case T_BitmapAnd:
-                       /* BitmapAnd works like Append, but has no tlist */
-                       Assert(plan->targetlist == NIL);
-                       Assert(plan->qual == NIL);
-                       foreach(l, ((BitmapAnd *) plan)->bitmapplans)
-                               adjust_plan_varnos((Plan *) lfirst(l), rtoffset);
-                       break;
-               case T_BitmapOr:
-                       /* BitmapOr works like Append, but has no tlist */
-                       Assert(plan->targetlist == NIL);
-                       Assert(plan->qual == NIL);
-                       foreach(l, ((BitmapOr *) plan)->bitmapplans)
-                               adjust_plan_varnos((Plan *) lfirst(l), rtoffset);
-                       break;
-               default:
-                       elog(ERROR, "unrecognized node type: %d",
-                                (int) nodeTag(plan));
-                       break;
-       }
-
-       /*
-        * Now recurse into child plans.
-        *
-        * We don't need to (and in fact mustn't) recurse into subqueries, so no
-        * need to examine initPlan list.
-        */
-       adjust_plan_varnos(plan->lefttree, rtoffset);
-       adjust_plan_varnos(plan->righttree, rtoffset);
-}
-
-/*
- * adjust_expr_varnos
- *             Offset varnos of Vars in an expression by rtoffset.
+ * fix_scan_expr
+ *             Do set_plan_references processing on a scan-level expression
  *
- * This is different from the rewriter's OffsetVarNodes in that it has to
- * work on an already-planned expression tree; in particular, we should not
- * disturb INNER and OUTER references. On the other hand, we don't have to
- * recurse into subqueries nor deal with outer-level Vars, so it's pretty
- * simple.
+ * This consists of incrementing all Vars' varnos by rtoffset and
+ * looking up operator opcode info for OpExpr and related nodes.
  */
-static void
-adjust_expr_varnos(Node *node, int rtoffset)
+static Node *
+fix_scan_expr(Node *node, int rtoffset)
 {
-       /* This tree walk requires no special setup, so away we go... */
-       adjust_expr_varnos_walker(node, &rtoffset);
+       fix_scan_expr_context context;
+
+       context.rtoffset = rtoffset;
+       return fix_scan_expr_mutator(node, &context);
 }
 
-static bool
-adjust_expr_varnos_walker(Node *node, int *context)
+static Node *
+fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
 {
        if (node == NULL)
-               return false;
+               return NULL;
        if (IsA(node, Var))
        {
-               Var                *var = (Var *) node;
+               Var                *var = (Var *) copyObject(node);
 
                Assert(var->varlevelsup == 0);
-               if (var->varno > 0 && var->varno != INNER && var->varno != OUTER)
-                       var->varno += *context;
+               /*
+                * We should not see any Vars marked INNER, but in a nestloop inner
+                * scan there could be OUTER Vars.  Leave them alone.
+                */
+               Assert(var->varno != INNER);
+               if (var->varno > 0 && var->varno != OUTER)
+                       var->varno += context->rtoffset;
                if (var->varnoold > 0)
-                       var->varnoold += *context;
-               return false;
+                       var->varnoold += context->rtoffset;
+               return (Node *) var;
        }
-       return expression_tree_walker(node, adjust_expr_varnos_walker,
-                                                                 (void *) context);
-}
-
-/*
- * fix_expr_references
- *       Do final cleanup on expressions (targetlists or quals).
- *
- * This consists of looking up operator opcode info for OpExpr nodes
- * and recursively performing set_plan_references on subplans.
- *
- * The Plan argument is currently unused, but might be needed again someday.
- */
-static void
-fix_expr_references(Plan *plan, Node *node)
-{
-       /* This tree walk requires no special setup, so away we go... */
-       fix_expr_references_walker(node, NULL);
-}
-
-static bool
-fix_expr_references_walker(Node *node, void *context)
-{
-       if (node == NULL)
-               return false;
+       /*
+        * Since we update opcode info in-place, this part could possibly
+        * scribble on the planner's input data structures, but it's OK.
+        */
        if (IsA(node, OpExpr))
                set_opfuncid((OpExpr *) node);
        else if (IsA(node, DistinctExpr))
                set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
-       else if (IsA(node, ScalarArrayOpExpr))
-               set_sa_opfuncid((ScalarArrayOpExpr *) node);
        else if (IsA(node, NullIfExpr))
                set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
-       else if (IsA(node, SubPlan))
-       {
-               SubPlan    *sp = (SubPlan *) node;
-
-               sp->plan = set_plan_references(sp->plan, sp->rtable);
-       }
-       return expression_tree_walker(node, fix_expr_references_walker, context);
+       else if (IsA(node, ScalarArrayOpExpr))
+               set_sa_opfuncid((ScalarArrayOpExpr *) node);
+       return expression_tree_mutator(node, fix_scan_expr_mutator,
+                                                                  (void *) context);
 }
 
 /*
  * set_join_references
- *       Modifies the target list and quals of a join node to reference its
+ *       Modify the target list and quals of a join node to reference its
  *       subplans, by setting the varnos to OUTER or INNER and setting attno
  *       values to the result domain number of either the corresponding outer
- *       or inner join tuple item.
+ *       or inner join tuple item.  Also perform opcode lookup for these
+ *       expressions.
  *
  * In the case of a nestloop with inner indexscan, we will also need to
  * apply the same transformation to any outer vars appearing in the
  * quals of the child indexscan.  set_inner_join_references does that.
- *
- *     'join' is a join plan node
  */
 static void
-set_join_references(Join *join)
+set_join_references(Join *join, int rtoffset)
 {
        Plan       *outer_plan = join->plan.lefttree;
        Plan       *inner_plan = join->plan.righttree;
@@ -728,43 +646,47 @@ set_join_references(Join *join)
        inner_itlist = build_tlist_index(inner_plan->targetlist);
 
        /* All join plans have tlist, qual, and joinqual */
-       join->plan.targetlist = join_references(join->plan.targetlist,
-                                                                                       outer_itlist,
-                                                                                       inner_itlist,
-                                                                                       (Index) 0);
-       join->plan.qual = join_references(join->plan.qual,
-                                                                         outer_itlist,
-                                                                         inner_itlist,
-                                                                         (Index) 0);
-       join->joinqual = join_references(join->joinqual,
-                                                                        outer_itlist,
-                                                                        inner_itlist,
-                                                                        (Index) 0);
+       join->plan.targetlist = fix_join_expr(join->plan.targetlist,
+                                                                                 outer_itlist,
+                                                                                 inner_itlist,
+                                                                                 (Index) 0,
+                                                                                 rtoffset);
+       join->plan.qual = fix_join_expr(join->plan.qual,
+                                                                       outer_itlist,
+                                                                       inner_itlist,
+                                                                       (Index) 0,
+                                                                       rtoffset);
+       join->joinqual = fix_join_expr(join->joinqual,
+                                                                  outer_itlist,
+                                                                  inner_itlist,
+                                                                  (Index) 0,
+                                                                  rtoffset);
 
        /* Now do join-type-specific stuff */
        if (IsA(join, NestLoop))
        {
                /* This processing is split out to handle possible recursion */
-               set_inner_join_references(inner_plan,
-                                                                 outer_itlist);
+               set_inner_join_references(inner_plan, outer_itlist);
        }
        else if (IsA(join, MergeJoin))
        {
                MergeJoin  *mj = (MergeJoin *) join;
 
-               mj->mergeclauses = join_references(mj->mergeclauses,
-                                                                                  outer_itlist,
-                                                                                  inner_itlist,
-                                                                                  (Index) 0);
+               mj->mergeclauses = fix_join_expr(mj->mergeclauses,
+                                                                                outer_itlist,
+                                                                                inner_itlist,
+                                                                                (Index) 0,
+                                                                                rtoffset);
        }
        else if (IsA(join, HashJoin))
        {
                HashJoin   *hj = (HashJoin *) join;
 
-               hj->hashclauses = join_references(hj->hashclauses,
-                                                                                 outer_itlist,
-                                                                                 inner_itlist,
-                                                                                 (Index) 0);
+               hj->hashclauses = fix_join_expr(hj->hashclauses,
+                                                                               outer_itlist,
+                                                                               inner_itlist,
+                                                                               (Index) 0,
+                                                                               rtoffset);
        }
 
        pfree(outer_itlist);
@@ -779,6 +701,10 @@ set_join_references(Join *join)
  * to the bottom BitmapIndexScan nodes; likewise, appendrel indexscans
  * require recursing through Append nodes.     This is split out as a separate
  * function so that it can recurse.
+ *
+ * Note we do *not* apply any rtoffset for non-join Vars; this is because
+ * the quals will be processed again by fix_scan_expr when the set_plan_refs
+ * recursion reaches the inner indexscan, and so we'd have done it twice.
  */
 static void
 set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
@@ -800,14 +726,16 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
                        Index           innerrel = innerscan->scan.scanrelid;
 
                        /* only refs to outer vars get changed in the inner qual */
-                       innerscan->indexqualorig = join_references(indexqualorig,
-                                                                                                          outer_itlist,
-                                                                                                          NULL,
-                                                                                                          innerrel);
-                       innerscan->indexqual = join_references(innerscan->indexqual,
-                                                                                                  outer_itlist,
-                                                                                                  NULL,
-                                                                                                  innerrel);
+                       innerscan->indexqualorig = fix_join_expr(indexqualorig,
+                                                                                                        outer_itlist,
+                                                                                                        NULL,
+                                                                                                        innerrel,
+                                                                                                        0);
+                       innerscan->indexqual = fix_join_expr(innerscan->indexqual,
+                                                                                                outer_itlist,
+                                                                                                NULL,
+                                                                                                innerrel,
+                                                                                                0);
 
                        /*
                         * We must fix the inner qpqual too, if it has join clauses (this
@@ -815,10 +743,11 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
                         * may get rechecked as qpquals).
                         */
                        if (NumRelids((Node *) inner_plan->qual) > 1)
-                               inner_plan->qual = join_references(inner_plan->qual,
-                                                                                                  outer_itlist,
-                                                                                                  NULL,
-                                                                                                  innerrel);
+                               inner_plan->qual = fix_join_expr(inner_plan->qual,
+                                                                                                outer_itlist,
+                                                                                                NULL,
+                                                                                                innerrel,
+                                                                                                0);
                }
        }
        else if (IsA(inner_plan, BitmapIndexScan))
@@ -835,14 +764,16 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
                        Index           innerrel = innerscan->scan.scanrelid;
 
                        /* only refs to outer vars get changed in the inner qual */
-                       innerscan->indexqualorig = join_references(indexqualorig,
-                                                                                                          outer_itlist,
-                                                                                                          NULL,
-                                                                                                          innerrel);
-                       innerscan->indexqual = join_references(innerscan->indexqual,
-                                                                                                  outer_itlist,
-                                                                                                  NULL,
-                                                                                                  innerrel);
+                       innerscan->indexqualorig = fix_join_expr(indexqualorig,
+                                                                                                        outer_itlist,
+                                                                                                        NULL,
+                                                                                                        innerrel,
+                                                                                                        0);
+                       innerscan->indexqual = fix_join_expr(innerscan->indexqual,
+                                                                                                outer_itlist,
+                                                                                                NULL,
+                                                                                                innerrel,
+                                                                                                0);
                        /* no need to fix inner qpqual */
                        Assert(inner_plan->qual == NIL);
                }
@@ -862,10 +793,11 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
                /* only refs to outer vars get changed in the inner qual */
                if (NumRelids((Node *) bitmapqualorig) > 1)
-                       innerscan->bitmapqualorig = join_references(bitmapqualorig,
-                                                                                                               outer_itlist,
-                                                                                                               NULL,
-                                                                                                               innerrel);
+                       innerscan->bitmapqualorig = fix_join_expr(bitmapqualorig,
+                                                                                                         outer_itlist,
+                                                                                                         NULL,
+                                                                                                         innerrel,
+                                                                                                         0);
 
                /*
                 * We must fix the inner qpqual too, if it has join clauses (this
@@ -873,14 +805,14 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
                 * get rechecked as qpquals).
                 */
                if (NumRelids((Node *) inner_plan->qual) > 1)
-                       inner_plan->qual = join_references(inner_plan->qual,
-                                                                                          outer_itlist,
-                                                                                          NULL,
-                                                                                          innerrel);
+                       inner_plan->qual = fix_join_expr(inner_plan->qual,
+                                                                                        outer_itlist,
+                                                                                        NULL,
+                                                                                        innerrel,
+                                                                                        0);
 
                /* Now recurse */
-               set_inner_join_references(inner_plan->lefttree,
-                                                                 outer_itlist);
+               set_inner_join_references(inner_plan->lefttree, outer_itlist);
        }
        else if (IsA(inner_plan, BitmapAnd))
        {
@@ -890,8 +822,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
                foreach(l, innerscan->bitmapplans)
                {
-                       set_inner_join_references((Plan *) lfirst(l),
-                                                                         outer_itlist);
+                       set_inner_join_references((Plan *) lfirst(l), outer_itlist);
                }
        }
        else if (IsA(inner_plan, BitmapOr))
@@ -902,10 +833,20 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
                foreach(l, innerscan->bitmapplans)
                {
-                       set_inner_join_references((Plan *) lfirst(l),
-                                                                         outer_itlist);
+                       set_inner_join_references((Plan *) lfirst(l), outer_itlist);
                }
        }
+       else if (IsA(inner_plan, TidScan))
+       {
+               TidScan    *innerscan = (TidScan *) inner_plan;
+               Index           innerrel = innerscan->scan.scanrelid;
+
+               innerscan->tidquals = fix_join_expr(innerscan->tidquals,
+                                                                                       outer_itlist,
+                                                                                       NULL,
+                                                                                       innerrel,
+                                                                                       0);
+       }
        else if (IsA(inner_plan, Append))
        {
                /*
@@ -917,8 +858,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
                foreach(l, appendplan->appendplans)
                {
-                       set_inner_join_references((Plan *) lfirst(l),
-                                                                         outer_itlist);
+                       set_inner_join_references((Plan *) lfirst(l), outer_itlist);
                }
        }
        else if (IsA(inner_plan, Result))
@@ -929,22 +869,13 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
                if (result->plan.lefttree)
                        set_inner_join_references(result->plan.lefttree, outer_itlist);
        }
-       else if (IsA(inner_plan, TidScan))
-       {
-               TidScan    *innerscan = (TidScan *) inner_plan;
-               Index           innerrel = innerscan->scan.scanrelid;
-
-               innerscan->tidquals = join_references(innerscan->tidquals,
-                                                                                         outer_itlist,
-                                                                                         NULL,
-                                                                                         innerrel);
-       }
 }
 
 /*
- * set_uppernode_references
+ * set_upper_references
  *       Update the targetlist and quals of an upper-level plan node
  *       to refer to the tuples returned by its lefttree subplan.
+ *       Also perform opcode lookup for these expressions.
  *
  * This is used for single-input plan types like Agg, Group, Result.
  *
@@ -958,7 +889,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
  * the expression.
  */
 static void
-set_uppernode_references(Plan *plan, Index subvarno)
+set_upper_references(Plan *plan, Index subvarno, int rtoffset)
 {
        Plan       *subplan = plan->lefttree;
        indexed_tlist *subplan_itlist;
@@ -976,9 +907,10 @@ set_uppernode_references(Plan *plan, Index subvarno)
                TargetEntry *tle = (TargetEntry *) lfirst(l);
                Node       *newexpr;
 
-               newexpr = replace_vars_with_subplan_refs((Node *) tle->expr,
-                                                                                                subplan_itlist,
-                                                                                                subvarno);
+               newexpr = fix_upper_expr((Node *) tle->expr,
+                                                                subplan_itlist,
+                                                                subvarno,
+                                                                rtoffset);
                tle = flatCopyTargetEntry(tle);
                tle->expr = (Expr *) newexpr;
                output_targetlist = lappend(output_targetlist, tle);
@@ -986,9 +918,10 @@ set_uppernode_references(Plan *plan, Index subvarno)
        plan->targetlist = output_targetlist;
 
        plan->qual = (List *)
-               replace_vars_with_subplan_refs((Node *) plan->qual,
-                                                                          subplan_itlist,
-                                                                          subvarno);
+               fix_upper_expr((Node *) plan->qual,
+                                          subplan_itlist,
+                                          subvarno,
+                                          rtoffset);
 
        pfree(subplan_itlist);
 }
@@ -1096,10 +1029,12 @@ build_tlist_index_other_vars(List *tlist, Index ignore_rel)
  *
  * 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).
+ * Also ensure that varnoold is incremented by rtoffset.
  * If no match, return NULL.
  */
 static Var *
-search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, Index newvarno)
+search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist,
+                                                        Index newvarno, int rtoffset)
 {
        Index           varno = var->varno;
        AttrNumber      varattno = var->varattno;
@@ -1117,6 +1052,8 @@ search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, Index newvarno)
 
                        newvar->varno = newvarno;
                        newvar->varattno = vinfo->resno;
+                       if (newvar->varnoold > 0)
+                               newvar->varnoold += rtoffset;
                        return newvar;
                }
                vinfo++;
@@ -1157,22 +1094,23 @@ search_indexed_tlist_for_non_var(Node *node,
 }
 
 /*
- * join_references
- *        Creates a new set of targetlist entries or join qual clauses by
+ * fix_join_expr
+ *        Create a new set of targetlist entries or join qual clauses by
  *        changing the varno/varattno values of variables in the clauses
  *        to reference target list values from the outer and inner join
- *        relation target lists.
+ *        relation target lists.  Also perform opcode lookup.
  *
  * This is used in two different scenarios: a normal join clause, where
  * all the Vars in the clause *must* be replaced by OUTER or INNER references;
  * and an indexscan being used on the inner side of a nestloop join.
  * In the latter case we want to replace the outer-relation Vars by OUTER
- * references, but not touch the Vars of the inner relation.  (We also
- * implement RETURNING clause fixup using this second scenario.)
+ * references, while Vars of the inner relation should be adjusted by rtoffset.
+ * (We also implement RETURNING clause fixup using this second scenario.)
  *
  * 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_itlist = NULL and acceptable_rel = the ID of the inner relation.
+ * pass inner_itlist = NULL and acceptable_rel = the (not-offseted-yet) ID
+ * of the inner relation.
  *
  * 'clauses' is the targetlist or list of join clauses
  * 'outer_itlist' is the indexed target list of the outer join relation
@@ -1180,27 +1118,29 @@ search_indexed_tlist_for_non_var(Node *node,
  *             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.
+ * 'rtoffset' is what to add to varno for Vars of acceptable_rel.
  *
  * Returns the new expression tree.  The original clause structure is
  * not modified.
  */
 static List *
-join_references(List *clauses,
-                               indexed_tlist *outer_itlist,
-                               indexed_tlist *inner_itlist,
-                               Index acceptable_rel)
+fix_join_expr(List *clauses,
+                         indexed_tlist *outer_itlist,
+                         indexed_tlist *inner_itlist,
+                         Index acceptable_rel,
+                         int rtoffset)
 {
-       join_references_context context;
+       fix_join_expr_context context;
 
        context.outer_itlist = outer_itlist;
        context.inner_itlist = inner_itlist;
        context.acceptable_rel = acceptable_rel;
-       return (List *) join_references_mutator((Node *) clauses, &context);
+       context.rtoffset = rtoffset;
+       return (List *) fix_join_expr_mutator((Node *) clauses, &context);
 }
 
 static Node *
-join_references_mutator(Node *node,
-                                               join_references_context *context)
+fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
 {
        Var                *newvar;
 
@@ -1213,21 +1153,28 @@ join_references_mutator(Node *node,
                /* First look for the var in the input tlists */
                newvar = search_indexed_tlist_for_var(var,
                                                                                          context->outer_itlist,
-                                                                                         OUTER);
+                                                                                         OUTER,
+                                                                                         context->rtoffset);
                if (newvar)
                        return (Node *) newvar;
                if (context->inner_itlist)
                {
                        newvar = search_indexed_tlist_for_var(var,
                                                                                                  context->inner_itlist,
-                                                                                                 INNER);
+                                                                                                 INNER,
+                                                                                                 context->rtoffset);
                        if (newvar)
                                return (Node *) newvar;
                }
 
-               /* Return the Var unmodified, if it's for acceptable_rel */
+               /* If it's for acceptable_rel, adjust and return it */
                if (var->varno == context->acceptable_rel)
-                       return (Node *) copyObject(var);
+               {
+                       var = (Var *) copyObject(var);
+                       var->varno += context->rtoffset;
+                       var->varnoold += context->rtoffset;
+                       return (Node *) var;
+               }
 
                /* No referent found for Var */
                elog(ERROR, "variable not found in subplan target lists");
@@ -1249,16 +1196,30 @@ join_references_mutator(Node *node,
                if (newvar)
                        return (Node *) newvar;
        }
+       /*
+        * Since we update opcode info in-place, this part could possibly
+        * scribble on the planner's input data structures, but it's OK.
+        */
+       if (IsA(node, OpExpr))
+               set_opfuncid((OpExpr *) node);
+       else if (IsA(node, DistinctExpr))
+               set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
+       else if (IsA(node, NullIfExpr))
+               set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
+       else if (IsA(node, ScalarArrayOpExpr))
+               set_sa_opfuncid((ScalarArrayOpExpr *) node);
        return expression_tree_mutator(node,
-                                                                  join_references_mutator,
+                                                                  fix_join_expr_mutator,
                                                                   (void *) context);
 }
 
 /*
- * replace_vars_with_subplan_refs
- *             This routine modifies an expression tree so that all Var nodes
- *             reference target nodes of a subplan.  It is used to fix up
- *             target and qual expressions of non-join upper-level plan nodes.
+ * fix_upper_expr
+ *             Modifies an expression tree so that all Var nodes reference outputs
+ *             of a subplan.  Also performs opcode lookup.
+ *
+ * This is used to fix up target and qual expressions of non-join upper-level
+ * plan nodes.
  *
  * An error is raised if no matching var can be found in the subplan tlist
  * --- so this routine should only be applied to nodes whose subplans'
@@ -1273,26 +1234,28 @@ join_references_mutator(Node *node,
  * '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
+ * 'rtoffset': how much to increment varnoold by
  *
  * The resulting tree is a copy of the original in which all Var nodes have
  * varno = subvarno, varattno = resno of corresponding subplan target.
  * The original tree is not modified.
  */
 static Node *
-replace_vars_with_subplan_refs(Node *node,
-                                                          indexed_tlist *subplan_itlist,
-                                                          Index subvarno)
+fix_upper_expr(Node *node,
+                          indexed_tlist *subplan_itlist,
+                          Index subvarno,
+                          int rtoffset)
 {
-       replace_vars_with_subplan_refs_context context;
+       fix_upper_expr_context context;
 
        context.subplan_itlist = subplan_itlist;
        context.subvarno = subvarno;
-       return replace_vars_with_subplan_refs_mutator(node, &context);
+       context.rtoffset = rtoffset;
+       return fix_upper_expr_mutator(node, &context);
 }
 
 static Node *
-replace_vars_with_subplan_refs_mutator(Node *node,
-                                                        replace_vars_with_subplan_refs_context *context)
+fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
 {
        Var                *newvar;
 
@@ -1304,7 +1267,8 @@ replace_vars_with_subplan_refs_mutator(Node *node,
 
                newvar = search_indexed_tlist_for_var(var,
                                                                                          context->subplan_itlist,
-                                                                                         context->subvarno);
+                                                                                         context->subvarno,
+                                                                                         context->rtoffset);
                if (!newvar)
                        elog(ERROR, "variable not found in subplan target list");
                return (Node *) newvar;
@@ -1318,8 +1282,20 @@ replace_vars_with_subplan_refs_mutator(Node *node,
                if (newvar)
                        return (Node *) newvar;
        }
+       /*
+        * Since we update opcode info in-place, this part could possibly
+        * scribble on the planner's input data structures, but it's OK.
+        */
+       if (IsA(node, OpExpr))
+               set_opfuncid((OpExpr *) node);
+       else if (IsA(node, DistinctExpr))
+               set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
+       else if (IsA(node, NullIfExpr))
+               set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
+       else if (IsA(node, ScalarArrayOpExpr))
+               set_sa_opfuncid((ScalarArrayOpExpr *) node);
        return expression_tree_mutator(node,
-                                                                  replace_vars_with_subplan_refs_mutator,
+                                                                  fix_upper_expr_mutator,
                                                                   (void *) context);
 }
 
@@ -1335,12 +1311,15 @@ replace_vars_with_subplan_refs_mutator(Node *node,
  * adjusted RETURNING list, result-table Vars will still have their
  * original varno, but Vars for other rels will have varno OUTER.
  *
- * We also must apply fix_expr_references to the list.
+ * We also must perform opcode lookup.
  *
  * 'rlist': the RETURNING targetlist to be fixed
  * 'topplan': the top Plan node for the query (not yet passed through
  *             set_plan_references)
- * 'resultRelation': RT index of the query's result relation
+ * 'resultRelation': RT index of the associated result relation
+ *
+ * Note: we assume that result relations will have rtoffset zero, that is,
+ * they are not coming from a subplan.
  */
 List *
 set_returning_clause_references(List *rlist,
@@ -1350,20 +1329,19 @@ set_returning_clause_references(List *rlist,
        indexed_tlist *itlist;
 
        /*
-        * We can perform the desired Var fixup by abusing the join_references
+        * We can perform the desired Var fixup by abusing the fix_join_expr
         * machinery that normally handles inner indexscan fixup.  We search the
         * top plan's targetlist for Vars of non-result relations, and use
-        * join_references to convert RETURNING Vars into references to those
+        * fix_join_expr to convert RETURNING Vars into references to those
         * tlist entries, while leaving result-rel Vars as-is.
         */
        itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
 
-       rlist = join_references(rlist,
-                                                       itlist,
-                                                       NULL,
-                                                       resultRelation);
-
-       fix_expr_references(topplan, (Node *) rlist);
+       rlist = fix_join_expr(rlist,
+                                                 itlist,
+                                                 NULL,
+                                                 resultRelation,
+                                                 0);
 
        pfree(itlist);
 
@@ -1399,10 +1377,10 @@ fix_opfuncids_walker(Node *node, void *context)
                set_opfuncid((OpExpr *) node);
        else if (IsA(node, DistinctExpr))
                set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
-       else if (IsA(node, ScalarArrayOpExpr))
-               set_sa_opfuncid((ScalarArrayOpExpr *) node);
        else if (IsA(node, NullIfExpr))
                set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
+       else if (IsA(node, ScalarArrayOpExpr))
+               set_sa_opfuncid((ScalarArrayOpExpr *) node);
        return expression_tree_walker(node, fix_opfuncids_walker, context);
 }
 
index b62aeb853d85e0e4e460c1e8cb696ff3afe6a1cc..d19e9d298c01cbd632811cdb6d6f08e4a7ada497 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.120 2007/02/19 07:03:30 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.121 2007/02/22 22:00:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,6 +46,7 @@ typedef struct process_sublinks_context
 
 typedef struct finalize_primnode_context
 {
+       PlannerInfo *root;
        Bitmapset  *paramids;           /* Set of PARAM_EXEC paramids found */
        Bitmapset  *outer_params;       /* Set of accessible outer paramids */
 } finalize_primnode_context;
@@ -57,12 +58,13 @@ static Node *convert_testexpr(PlannerInfo *root,
                                                          List **righthandIds);
 static Node *convert_testexpr_mutator(Node *node,
                                                 convert_testexpr_context *context);
-static bool subplan_is_hashable(SubLink *slink, SubPlan *node);
+static bool subplan_is_hashable(SubLink *slink, SubPlan *node, Plan *plan);
 static bool hash_ok_operator(OpExpr *expr);
 static Node *replace_correlation_vars_mutator(Node *node, PlannerInfo *root);
 static Node *process_sublinks_mutator(Node *node,
                                                                          process_sublinks_context *context);
-static Bitmapset *finalize_plan(Plan *plan, List *rtable,
+static Bitmapset *finalize_plan(PlannerInfo *root,
+                         Plan *plan,
                          Bitmapset *outer_params,
                          Bitmapset *valid_params);
 static bool finalize_primnode(Node *node, finalize_primnode_context *context);
@@ -203,6 +205,24 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod)
        return retval;
 }
 
+/*
+ * Get the datatype of the first column of the plan's output.
+ *
+ * This is a hack to support exprType(), which doesn't have any way to get
+ * at the plan associated with a SubPlan node.  We really only need the value
+ * for EXPR_SUBLINK and ARRAY_SUBLINK subplans, but for consistency we set
+ * it always.
+ */
+static Oid
+get_first_col_type(Plan *plan)
+{
+       TargetEntry *tent = (TargetEntry *) linitial(plan->targetlist);
+
+       Assert(IsA(tent, TargetEntry));
+       Assert(!tent->resjunk);
+       return exprType((Node *) tent->expr);
+}
+
 /*
  * Convert a SubLink (as created by the parser) into a SubPlan.
  *
@@ -219,10 +239,11 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod)
 static Node *
 make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
 {
-       SubPlan    *node = makeNode(SubPlan);
        Query      *subquery = (Query *) (slink->subselect);
        double          tuple_fraction;
+       SubPlan    *node;
        Plan       *plan;
+       PlannerInfo *subroot;
        Bitmapset  *tmpset;
        int                     paramid;
        Node       *result;
@@ -266,22 +287,19 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
        /*
         * Generate the plan for the subquery.
         */
-       node->plan = plan = subquery_planner(root->glob, subquery,
-                                                                                root->query_level + 1,
-                                                                                tuple_fraction,
-                                                                                NULL);
-
-       /* Assign quasi-unique ID to this SubPlan */
-       node->plan_id = root->glob->next_plan_id++;
-
-       node->rtable = subquery->rtable;
+       plan = subquery_planner(root->glob, subquery,
+                                                       root->query_level + 1,
+                                                       tuple_fraction,
+                                                       &subroot);
 
        /*
-        * Initialize other fields of the SubPlan node.
+        * Initialize the SubPlan node.  Note plan_id isn't set yet.
         */
+       node = makeNode(SubPlan);
        node->subLinkType = slink->subLinkType;
        node->testexpr = NULL;
        node->paramIds = NIL;
+       node->firstColType = get_first_col_type(plan);
        node->useHashTable = false;
        /* At top level of a qual, can treat UNKNOWN the same as FALSE */
        node->unknownEqFalse = isTopQual;
@@ -384,7 +402,7 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
                 * tuple.  But if it's an IN (= ANY) test, we might be able to use a
                 * hashtable to avoid comparing all the tuples.
                 */
-               if (subplan_is_hashable(slink, node))
+               if (subplan_is_hashable(slink, node, plan))
                        node->useHashTable = true;
 
                /*
@@ -411,7 +429,7 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
                                        break;
                        }
                        if (use_material)
-                               node->plan = plan = materialize_finished_plan(plan);
+                               plan = materialize_finished_plan(plan);
                }
 
                /*
@@ -435,6 +453,15 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
                result = (Node *) node;
        }
 
+       /*
+        * Add the subplan and its rtable to the global lists.
+        */
+       root->glob->subplans = lappend(root->glob->subplans,
+                                                                  plan);
+       root->glob->subrtables = lappend(root->glob->subrtables,
+                                                                        subroot->parse->rtable);
+       node->plan_id = list_length(root->glob->subplans);
+
        return result;
 }
 
@@ -539,7 +566,7 @@ convert_testexpr_mutator(Node *node,
  * on its plan and parParam fields, however.
  */
 static bool
-subplan_is_hashable(SubLink *slink, SubPlan *node)
+subplan_is_hashable(SubLink *slink, SubPlan *node, Plan *plan)
 {
        double          subquery_size;
        ListCell   *l;
@@ -574,8 +601,8 @@ subplan_is_hashable(SubLink *slink, SubPlan *node)
         * actually be stored as MinimalTuples; this provides some fudge factor
         * for hashtable overhead.)
         */
-       subquery_size = node->plan->plan_rows *
-               (MAXALIGN(node->plan->plan_width) + MAXALIGN(sizeof(HeapTupleHeaderData)));
+       subquery_size = plan->plan_rows *
+               (MAXALIGN(plan->plan_width) + MAXALIGN(sizeof(HeapTupleHeaderData)));
        if (subquery_size > work_mem * 1024L)
                return false;
 
@@ -964,7 +991,7 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
        /*
         * Now recurse through plan tree.
         */
-       (void) finalize_plan(plan, root->parse->rtable, outer_params, valid_params);
+       (void) finalize_plan(root, plan, outer_params, valid_params);
 
        bms_free(outer_params);
        bms_free(valid_params);
@@ -988,16 +1015,16 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
        initplan_cost = 0;
        foreach(l, plan->initPlan)
        {
-               SubPlan    *initplan = (SubPlan *) lfirst(l);
+               SubPlan    *initsubplan = (SubPlan *) lfirst(l);
+               Plan       *initplan = planner_subplan_get_plan(root, initsubplan);
                ListCell   *l2;
 
-               initExtParam = bms_add_members(initExtParam,
-                                                                          initplan->plan->extParam);
-               foreach(l2, initplan->setParam)
+               initExtParam = bms_add_members(initExtParam, initplan->extParam);
+               foreach(l2, initsubplan->setParam)
                {
                        initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
                }
-               initplan_cost += initplan->plan->total_cost;
+               initplan_cost += initplan->total_cost;
        }
        /* allParam must include all these params */
        plan->allParam = bms_add_members(plan->allParam, initExtParam);
@@ -1019,7 +1046,7 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
  * This is just an internal notational convenience.
  */
 static Bitmapset *
-finalize_plan(Plan *plan, List *rtable,
+finalize_plan(PlannerInfo *root, Plan *plan,
                          Bitmapset *outer_params, Bitmapset *valid_params)
 {
        finalize_primnode_context context;
@@ -1027,6 +1054,7 @@ finalize_plan(Plan *plan, List *rtable,
        if (plan == NULL)
                return NULL;
 
+       context.root = root;
        context.paramids = NULL;        /* initialize set to empty */
        context.outer_params = outer_params;
 
@@ -1110,8 +1138,8 @@ finalize_plan(Plan *plan, List *rtable,
                                {
                                        context.paramids =
                                                bms_add_members(context.paramids,
-                                                                               finalize_plan((Plan *) lfirst(l),
-                                                                                                         rtable,
+                                                                               finalize_plan(root,
+                                                                                                         (Plan *) lfirst(l),
                                                                                                          outer_params,
                                                                                                          valid_params));
                                }
@@ -1126,8 +1154,8 @@ finalize_plan(Plan *plan, List *rtable,
                                {
                                        context.paramids =
                                                bms_add_members(context.paramids,
-                                                                               finalize_plan((Plan *) lfirst(l),
-                                                                                                         rtable,
+                                                                               finalize_plan(root,
+                                                                                                         (Plan *) lfirst(l),
                                                                                                          outer_params,
                                                                                                          valid_params));
                                }
@@ -1142,8 +1170,8 @@ finalize_plan(Plan *plan, List *rtable,
                                {
                                        context.paramids =
                                                bms_add_members(context.paramids,
-                                                                               finalize_plan((Plan *) lfirst(l),
-                                                                                                         rtable,
+                                                                               finalize_plan(root,
+                                                                                                         (Plan *) lfirst(l),
                                                                                                          outer_params,
                                                                                                          valid_params));
                                }
@@ -1193,14 +1221,14 @@ finalize_plan(Plan *plan, List *rtable,
 
        /* Process left and right child plans, if any */
        context.paramids = bms_add_members(context.paramids,
-                                                                          finalize_plan(plan->lefttree,
-                                                                                                        rtable,
+                                                                          finalize_plan(root,
+                                                                                                        plan->lefttree,
                                                                                                         outer_params,
                                                                                                         valid_params));
 
        context.paramids = bms_add_members(context.paramids,
-                                                                          finalize_plan(plan->righttree,
-                                                                                                        rtable,
+                                                                          finalize_plan(root,
+                                                                                                        plan->righttree,
                                                                                                         outer_params,
                                                                                                         valid_params));
 
@@ -1252,10 +1280,11 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
        if (is_subplan(node))
        {
                SubPlan    *subplan = (SubPlan *) node;
+               Plan       *plan = planner_subplan_get_plan(context->root, subplan);
 
                /* Add outer-level params needed by the subplan to paramids */
                context->paramids = bms_join(context->paramids,
-                                                                        bms_intersect(subplan->plan->extParam,
+                                                                        bms_intersect(plan->extParam,
                                                                                                   context->outer_params));
                /* fall through to recurse into subplan args */
        }
@@ -1299,16 +1328,21 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
        root->query_level--;
        root->init_plans = saved_init_plans;
 
+       /*
+        * Add the subplan and its rtable to the global lists.
+        */
+       root->glob->subplans = lappend(root->glob->subplans,
+                                                                  plan);
+       root->glob->subrtables = lappend(root->glob->subrtables,
+                                                                        root->parse->rtable);
+
        /*
         * Create a SubPlan node and add it to the outer list of InitPlans.
         */
        node = makeNode(SubPlan);
        node->subLinkType = EXPR_SUBLINK;
-       node->plan = plan;
-       /* Assign quasi-unique ID to this SubPlan */
-       node->plan_id = root->glob->next_plan_id++;
-
-       node->rtable = root->parse->rtable;
+       node->firstColType = get_first_col_type(plan);
+       node->plan_id = list_length(root->glob->subplans);
 
        root->init_plans = lappend(root->init_plans, node);
 
index 2f06e1bf5322dfe3a03c14d310c9dbc03d964590..f09ddb1d23d1111205017deea44617f66fef7be0 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.138 2007/02/19 07:03:30 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.139 2007/02/22 22:00:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -169,6 +169,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
                RangeTblRef *rtr = (RangeTblRef *) setOp;
                RangeTblEntry *rte = rt_fetch(rtr->rtindex, root->parse->rtable);
                Query      *subquery = rte->subquery;
+               PlannerInfo *subroot;
                Plan       *subplan,
                                   *plan;
 
@@ -180,7 +181,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
                subplan = subquery_planner(root->glob, subquery,
                                                                   root->query_level + 1,
                                                                   tuple_fraction,
-                                                                  NULL);
+                                                                  &subroot);
 
                /*
                 * Add a SubqueryScan with the caller-requested targetlist
@@ -193,7 +194,8 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
                                                                                                   refnames_tlist),
                                                          NIL,
                                                          rtr->rtindex,
-                                                         subplan);
+                                                         subplan,
+                                                         subroot->parse->rtable);
 
                /*
                 * We don't bother to determine the subquery's output ordering since
@@ -223,7 +225,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
                 * output columns.
                 *
                 * XXX you don't really want to know about this: setrefs.c will apply
-                * replace_vars_with_subplan_refs() to the Result node's tlist. This
+                * fix_upper_expr() to the Result node's tlist. This
                 * would fail if the Vars generated by generate_setop_tlist() were not
                 * exactly equal() to the corresponding tlist entries of the subplan.
                 * However, since the subplan was generated by generate_union_plan()
@@ -235,7 +237,8 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
                        !tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
                {
                        plan = (Plan *)
-                               make_result(generate_setop_tlist(colTypes, flag,
+                               make_result(root,
+                                                       generate_setop_tlist(colTypes, flag,
                                                                                                 0,
                                                                                                 false,
                                                                                                 plan->targetlist,
@@ -1216,28 +1219,6 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
        Assert(!IsA(node, SubLink));
        Assert(!IsA(node, Query));
 
-       /*
-        * BUT: although we don't need to recurse into subplans, we do need to
-        * make sure that they are copied, not just referenced as
-        * expression_tree_mutator will do by default.  Otherwise we'll have the
-        * same subplan node referenced from each arm of the finished APPEND plan,
-        * which will cause trouble in the executor.  This is a kluge that should
-        * go away when we redesign querytrees.
-        */
-       if (is_subplan(node))
-       {
-               SubPlan    *subplan;
-
-               /* Copy the node and process subplan args */
-               node = expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
-                                                                          (void *) context);
-               /* Make sure we have separate copies of subplan and its rtable */
-               subplan = (SubPlan *) node;
-               subplan->plan = copyObject(subplan->plan);
-               subplan->rtable = copyObject(subplan->rtable);
-               return node;
-       }
-
        return expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
                                                                   (void *) context);
 }
index f90d55001979b65c15f8fdb222473cc349e83a1e..852b0f533e75d4251e128bb5aae0a3eb3e05b631 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.235 2007/02/19 07:03:30 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.236 2007/02/22 22:00:24 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -2989,7 +2989,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
                         */
                        if (contain_subplans(param))
                                goto fail;
-                       cost_qual_eval(&eval_cost, list_make1(param));
+                       cost_qual_eval(&eval_cost, list_make1(param), NULL);
                        if (eval_cost.startup + eval_cost.per_tuple >
                                10 * cpu_operator_cost)
                                goto fail;
index 8cc6c81746f3db605c323198a344483d1c2c2e69..6dfd2f61149e71c2ef87ec965b64a1b850e04aea 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.85 2007/01/20 20:45:40 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.86 2007/02/22 22:00:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -82,6 +82,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
        rel->pages = 0;
        rel->tuples = 0;
        rel->subplan = NULL;
+       rel->subrtable = NIL;
        rel->baserestrictinfo = NIL;
        rel->baserestrictcost.startup = 0;
        rel->baserestrictcost.per_tuple = 0;
@@ -333,6 +334,7 @@ build_join_rel(PlannerInfo *root,
        joinrel->pages = 0;
        joinrel->tuples = 0;
        joinrel->subplan = NULL;
+       joinrel->subrtable = NIL;
        joinrel->baserestrictinfo = NIL;
        joinrel->baserestrictcost.startup = 0;
        joinrel->baserestrictcost.per_tuple = 0;
index 8f34748f9987372ab03f8e52116d3bf428fc0592..5791215a95f29589e5ab9375498d0a6e3f182c61 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.211 2007/02/11 22:18:15 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.212 2007/02/22 22:00:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1769,12 +1769,7 @@ exprType(Node *expr)
                                        subplan->subLinkType == ARRAY_SUBLINK)
                                {
                                        /* get the type of the subselect's first target column */
-                                       TargetEntry *tent;
-
-                                       tent = (TargetEntry *) linitial(subplan->plan->targetlist);
-                                       Assert(IsA(tent, TargetEntry));
-                                       Assert(!tent->resjunk);
-                                       type = exprType((Node *) tent->expr);
+                                       type = subplan->firstColType;
                                        if (subplan->subLinkType == ARRAY_SUBLINK)
                                        {
                                                type = get_array_type(type);
@@ -1782,7 +1777,7 @@ exprType(Node *expr)
                                                        ereport(ERROR,
                                                                        (errcode(ERRCODE_UNDEFINED_OBJECT),
                                                                         errmsg("could not find array type for data type %s",
-                                                       format_type_be(exprType((Node *) tent->expr)))));
+                                                                                       format_type_be(subplan->firstColType))));
                                        }
                                }
                                else
index c6b8e8481c498d822de7700ca293713910021716..f25a8d8f70de62575cec804b5bedd90b5efdbb6b 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.226 2007/02/19 07:03:31 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.227 2007/02/22 22:00:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -4964,7 +4964,7 @@ genericcostestimate(PlannerInfo *root,
         * more expensive than it's worth, though, considering all the other
         * inaccuracies here ...
         */
-       cost_qual_eval(&index_qual_cost, indexQuals);
+       cost_qual_eval(&index_qual_cost, indexQuals, root);
        qual_op_cost = cpu_operator_cost * list_length(indexQuals);
        qual_arg_cost = index_qual_cost.startup +
                index_qual_cost.per_tuple - qual_op_cost;
index 38260b5ecd6c211dcd9b18ed590f688b0d04e1ee..7dfcabf5ac28227979700e7794a3baa71587a6bb 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.137 2007/02/20 17:32:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.138 2007/02/22 22:00:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -130,7 +130,6 @@ extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
                        ScanDirection direction, long count);
 extern void ExecutorEnd(QueryDesc *queryDesc);
 extern void ExecutorRewind(QueryDesc *queryDesc);
-extern void ExecCheckRTPerms(List *rangeTable);
 extern void ExecEndPlan(PlanState *planstate, EState *estate);
 extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
 extern void ExecConstraints(ResultRelInfo *resultRelInfo,
index b576f4610e3e75e7b7e84de5bb6b52b676db18ee..d0d47a8fd2b1ffce3a43753d14165fcff5d0002f 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.168 2007/02/20 17:32:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.169 2007/02/22 22:00:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -302,7 +302,7 @@ typedef struct EState
        ScanDirection es_direction; /* current scan direction */
        Snapshot        es_snapshot;    /* time qual to use */
        Snapshot        es_crosscheck_snapshot; /* crosscheck time qual for RI */
-       List       *es_range_table; /* List of RangeTableEntrys */
+       List       *es_range_table; /* List of RangeTblEntry */
 
        /* Info about target table for insert/update/delete queries: */
        ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
index 537981462b23e7b51585f63ab97e9116e8c37106..5a7445f69c0522db705059fdca13beade304492a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.91 2007/02/20 17:32:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.92 2007/02/22 22:00:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,6 +48,8 @@ typedef struct PlannedStmt
 
        IntoClause *into;                       /* target for SELECT INTO / CREATE TABLE AS */
 
+       List       *subplans;           /* Plan trees for SubPlan expressions */
+
        /*
         * If the query has a returningList then the planner will store a list of
         * processed targetlists (one per result relation) here.  We must have a
@@ -65,6 +67,10 @@ typedef struct PlannedStmt
        int                     nParamExec;             /* number of PARAM_EXEC Params used */
 } PlannedStmt;
 
+/* macro for fetching the Plan associated with a SubPlan node */
+#define exec_subplan_get_plan(plannedstmt, subplan) \
+       ((Plan *) list_nth((plannedstmt)->subplans, (subplan)->plan_id - 1))
+
 
 /* ----------------
  *             Plan node
@@ -313,12 +319,17 @@ typedef struct TidScan
  * the generic lefttree field as you might expect.     This is because we do
  * not want plan-tree-traversal routines to recurse into the subplan without
  * knowing that they are changing Query contexts.
+ *
+ * Note: subrtable is used just to carry the subquery rangetable from
+ * createplan.c to setrefs.c; it should always be NIL by the time the
+ * executor sees the plan.
  * ----------------
  */
 typedef struct SubqueryScan
 {
        Scan            scan;
        Plan       *subplan;
+       List       *subrtable;          /* temporary workspace for planner */
 } SubqueryScan;
 
 /* ----------------
index 185673f729a85f90750eff29f7e30ef2c720181b..7efb6ec77cfaa970fa1062b1d976d6ed97e85bac 100644 (file)
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.126 2007/02/20 17:32:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.127 2007/02/22 22:00:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -428,8 +428,10 @@ typedef struct SubLink
  * SubPlan - executable expression node for a subplan (sub-SELECT)
  *
  * The planner replaces SubLink nodes in expression trees with SubPlan
- * nodes after it has finished planning the subquery.  SubPlan contains
- * a sub-plantree and rtable instead of a sub-Query.
+ * nodes after it has finished planning the subquery.  SubPlan references
+ * a sub-plantree stored in the subplans list of the toplevel PlannedStmt.
+ * (We avoid a direct link to make it easier to copy expression trees
+ * without causing multiple processing of the subplan.)
  *
  * In an ordinary subplan, testexpr points to an executable expression
  * (OpExpr, an AND/OR tree of OpExprs, or RowCompareExpr) for the combining
@@ -463,12 +465,10 @@ typedef struct SubPlan
        /* The combining operators, transformed to an executable expression: */
        Node       *testexpr;           /* OpExpr or RowCompareExpr expression tree */
        List       *paramIds;           /* IDs of Params embedded in the above */
-       /* The subselect, transformed to a Plan: */
-       struct Plan *plan;                      /* subselect plan itself */
-       int                     plan_id;                /* kluge because we haven't equal-funcs for
-                                                                * plan nodes... we compare this instead of
-                                                                * subselect plan */
-       List       *rtable;                     /* range table for subselect */
+       /* Identification of the Plan tree to use: */
+       int                     plan_id;                /* Index (from 1) in PlannedStmt.subplans */
+       /* Extra data saved for the convenience of exprType(): */
+       Oid                     firstColType;   /* Type of first column of subplan result */
        /* Information about execution strategy: */
        bool            useHashTable;   /* TRUE to store subselect output in a hash
                                                                 * table (implies we are doing "IN") */
index fdb0cb0a5aeacfe10492011af4f97375c02b8eaf..76ad5abe1f5df70cf2c5f0e5e37fd7e6d4649b06 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/print.h,v 1.26 2007/01/05 22:19:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/print.h,v 1.27 2007/02/22 22:00:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,8 +31,5 @@ extern void print_expr(Node *expr, List *rtable);
 extern void print_pathkeys(List *pathkeys, List *rtable);
 extern void print_tl(List *tlist, List *rtable);
 extern void print_slot(TupleTableSlot *slot);
-extern void print_plan_recursive(Plan *p, Query *parsetree,
-                                        int indentLevel, char *label);
-extern void print_plan(Plan *p, Query *parsetree);
 
 #endif   /* PRINT_H */
index 59ec830f3ff6a23d1c065d7715a773d38bdb4037..19bcb51ea08c2bf8566f4033ca5a0a447ab52ff8 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.137 2007/02/20 17:32:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.138 2007/02/22 22:00:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -64,9 +64,17 @@ typedef struct PlannerGlobal
 
        List       *paramlist;          /* to keep track of cross-level Params */
 
-       int                     next_plan_id;   /* hack for distinguishing SubPlans */
+       List       *subplans;           /* Plans for SubPlan nodes */
+
+       List       *subrtables;         /* Rangetables for SubPlan nodes */
+
+       List       *finalrtable;        /* "flat" rangetable for executor */
 } PlannerGlobal;
 
+/* macro for fetching the Plan associated with a SubPlan node */
+#define planner_subplan_get_plan(root, subplan) \
+       ((Plan *) list_nth((root)->glob->subplans, (subplan)->plan_id - 1))
+
 
 /*----------
  * PlannerInfo
@@ -228,6 +236,7 @@ typedef struct PlannerInfo
  *             pages - number of disk pages in relation (zero if not a table)
  *             tuples - number of tuples in relation (not considering restrictions)
  *             subplan - plan for subquery (NULL if it's not a subquery)
+ *             subrtable - rangetable for subquery (NIL if it's not a subquery)
  *
  *             Note: for a subquery, tuples and subplan are not set immediately
  *             upon creation of the RelOptInfo object; they are filled in when
@@ -310,6 +319,7 @@ typedef struct RelOptInfo
        BlockNumber pages;
        double          tuples;
        struct Plan *subplan;           /* if subquery */
+       List       *subrtable;          /* if subquery */
 
        /* used by various scans and joins: */
        List       *baserestrictinfo;           /* RestrictInfo structures (if base
index fde65ed874a0d1cb6e4244d7478daac101d3e003..ef92d685eb4a433ef75bd77e5a7fbd9448bacef3 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.84 2007/01/22 01:35:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.85 2007/02/22 22:00:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,8 +88,8 @@ extern void cost_group(Path *path, PlannerInfo *root,
 extern void cost_nestloop(NestPath *path, PlannerInfo *root);
 extern void cost_mergejoin(MergePath *path, PlannerInfo *root);
 extern void cost_hashjoin(HashPath *path, PlannerInfo *root);
-extern void cost_qual_eval(QualCost *cost, List *quals);
-extern void cost_qual_eval_node(QualCost *cost, Node *qual);
+extern void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root);
+extern void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root);
 extern void set_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel);
 extern void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel,
                                                   RelOptInfo *outer_rel,
index 6bf34e162a7c479f45cf951ee15d27a77b92425d..b5ad4b3c3b503a5ae93db14f8a613477963e1505 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.99 2007/01/22 01:35:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.100 2007/02/22 22:00:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,7 +36,7 @@ extern Plan *optimize_minmax_aggregates(PlannerInfo *root, List *tlist,
  */
 extern Plan *create_plan(PlannerInfo *root, Path *best_path);
 extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual,
-                                 Index scanrelid, Plan *subplan);
+                                 Index scanrelid, Plan *subplan, List *subrtable);
 extern Append *make_append(List *appendplans, bool isTarget, List *tlist);
 extern Sort *make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree,
                                                List *pathkeys);
@@ -60,7 +60,8 @@ extern Limit *make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount,
                   int64 offset_est, int64 count_est);
 extern SetOp *make_setop(SetOpCmd cmd, Plan *lefttree,
                   List *distinctList, AttrNumber flagColIdx);
-extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
+extern Result *make_result(PlannerInfo *root, List *tlist,
+                                                  Node *resconstantqual, Plan *subplan);
 extern bool is_projection_capable_plan(Plan *plan);
 
 /*
@@ -91,7 +92,9 @@ extern RestrictInfo *build_implied_join_equality(Oid opno,
 /*
  * prototypes for plan/setrefs.c
  */
-extern Plan *set_plan_references(Plan *plan, List *rtable);
+extern Plan *set_plan_references(PlannerGlobal *glob,
+                                                                Plan *plan,
+                                                                List *rtable);
 extern List *set_returning_clause_references(List *rlist,
                                                                Plan *topplan,
                                                                Index resultRelation);