diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index b45850bd2b4e91ccf9c424b34a18f5c98ac19753..a390829bb8ef749dbb5882ce3b88ceb3d0fa202b 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.248 2005/05/06 17:24:53 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.249 2005/05/22 22:30:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -353,16 +353,10 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
 	AclId		userid;
 
 	/*
-	 * If it's a subquery, recursively examine its rangetable.
-	 */
-	if (rte->rtekind == RTE_SUBQUERY)
-	{
-		ExecCheckRTPerms(rte->subquery->rtable);
-		return;
-	}
-
-	/*
-	 * Otherwise, only plain-relation RTEs need to be checked here.
+	 * 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 checked by init_fcache when the function is
 	 * prepared for execution. Join and special RTEs need no checks.
 	 */
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index 1e80fa7be06a7603475baf76b908d61d3c43559a..843aa15101ccd268af738fa40bb43459d77cf6fd 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.35 2005/03/16 21:38:06 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.36 2005/05/22 22:30:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,7 +48,6 @@ TupleTableSlot *
 ExecScan(ScanState *node,
 		 ExecScanAccessMtd accessMtd)	/* function returning a tuple */
 {
-	EState	   *estate;
 	ExprContext *econtext;
 	List	   *qual;
 	ProjectionInfo *projInfo;
@@ -58,11 +57,16 @@ ExecScan(ScanState *node,
 	/*
 	 * Fetch data from node
 	 */
-	estate = node->ps.state;
-	econtext = node->ps.ps_ExprContext;
 	qual = node->ps.qual;
 	projInfo = node->ps.ps_ProjInfo;
 
+	/*
+	 * If we have neither a qual to check nor a projection to do,
+	 * just skip all the overhead and return the raw scan tuple.
+	 */
+	if (!qual && !projInfo)
+		return (*accessMtd) (node);
+
 	/*
 	 * Check to see if we're still projecting out tuples from a previous
 	 * scan tuple (because there is a function-returning-set in the
@@ -83,6 +87,7 @@ ExecScan(ScanState *node,
 	 * storage allocated in the previous tuple cycle.  Note this can't
 	 * happen until we're done projecting out tuples from a scan tuple.
 	 */
+	econtext = node->ps.ps_ExprContext;
 	ResetExprContext(econtext);
 
 	/*
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 0f77741a82501d743ccdce60b2583a5980f6b176..b88eec46a40699b61648b300c7d3a64eab7a7312 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeAppend.c,v 1.63 2005/04/24 11:46:20 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeAppend.c,v 1.64 2005/05/22 22:30:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -251,67 +251,52 @@ ExecCountSlotsAppend(Append *node)
 /* ----------------------------------------------------------------
  *	   ExecAppend
  *
- *		Handles the iteration over the multiple scans.
+ *		Handles iteration over multiple subplans.
  * ----------------------------------------------------------------
  */
 TupleTableSlot *
 ExecAppend(AppendState *node)
 {
-	EState	   *estate;
-	int			whichplan;
-	PlanState  *subnode;
-	TupleTableSlot *result;
-	TupleTableSlot *result_slot;
-	ScanDirection direction;
-
-	/*
-	 * get information from the node
-	 */
-	estate = node->ps.state;
-	direction = estate->es_direction;
-	whichplan = node->as_whichplan;
-	result_slot = node->ps.ps_ResultTupleSlot;
-
-	/*
-	 * figure out which subplan we are currently processing
-	 */
-	subnode = node->appendplans[whichplan];
-
-	/*
-	 * get a tuple from the subplan
-	 */
-	result = ExecProcNode(subnode);
-
-	if (!TupIsNull(result))
+	for (;;)
 	{
+		PlanState  *subnode;
+		TupleTableSlot *result;
+
 		/*
-		 * if the subplan gave us something then return it as-is.  We do
-		 * NOT make use of the result slot that was set up in ExecInitAppend,
-		 * first because there's no reason to and second because it may have
-		 * the wrong tuple descriptor in inherited-UPDATE cases.
+		 * figure out which subplan we are currently processing
 		 */
-		return result;
-	}
-	else
-	{
+		subnode = node->appendplans[node->as_whichplan];
+
 		/*
-		 * .. go on to the "next" subplan in the appropriate direction and
-		 * try processing again (recursively)
+		 * get a tuple from the subplan
 		 */
-		if (ScanDirectionIsForward(direction))
-			node->as_whichplan++;
-		else
-			node->as_whichplan--;
+		result = ExecProcNode(subnode);
+
+		if (!TupIsNull(result))
+		{
+			/*
+			 * If the subplan gave us something then return it as-is.
+			 * We do NOT make use of the result slot that was set up in
+			 * ExecInitAppend, first because there's no reason to and
+			 * second because it may have the wrong tuple descriptor in
+			 * inherited-UPDATE cases.
+			 */
+			return result;
+		}
 
 		/*
-		 * return something from next node or an empty slot if all of our
-		 * subplans have been exhausted.  The empty slot is the one set up
+		 * Go on to the "next" subplan in the appropriate direction.
+		 * If no more subplans, return the empty slot set up for us
 		 * by ExecInitAppend.
 		 */
-		if (exec_append_initialize_next(node))
-			return ExecAppend(node);
+		if (ScanDirectionIsForward(node->ps.state->es_direction))
+			node->as_whichplan++;
 		else
-			return ExecClearTuple(result_slot);
+			node->as_whichplan--;
+		if (!exec_append_initialize_next(node))
+			return ExecClearTuple(node->ps.ps_ResultTupleSlot);
+
+		/* Else loop back and try to get a tuple from the new subplan */
 	}
 }
 
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index f8f13f1c786f63f4cf6e889cf3935343f9c33152..5cd6de45fda7705f3fffeb863ca75f67eb6e4f4c 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.33 2005/04/14 22:09:40 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.34 2005/05/22 22:30:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -219,8 +219,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate)
 	BlessTupleDesc(tupdesc);
 
 	scanstate->tupdesc = tupdesc;
-	ExecSetSlotDescriptor(scanstate->ss.ss_ScanTupleSlot,
-						  tupdesc, false);
+	ExecAssignScanType(&scanstate->ss, tupdesc, false);
 
 	/*
 	 * Other node-specific setup
@@ -235,7 +234,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate)
 	 * Initialize result tuple type and projection info.
 	 */
 	ExecAssignResultTypeFromTL(&scanstate->ss.ps);
-	ExecAssignProjectionInfo(&scanstate->ss.ps);
+	ExecAssignScanProjectionInfo(&scanstate->ss);
 
 	return scanstate;
 }
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index 9bc5a6294d0e6a52b50120bdd09d5435b10e1ef9..90e59f90f4d4f1f3a645c65973c7423edf5d613d 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.25 2004/12/31 21:59:45 pgsql Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.26 2005/05/22 22:30:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -78,6 +78,10 @@ SubqueryNext(SubqueryScanState *node)
 
 	MemoryContextSwitchTo(oldcontext);
 
+	/*
+	 * We just overwrite our ScanTupleSlot with the subplan's result slot,
+	 * rather than expending the cycles for ExecCopySlot().
+	 */
 	node->ss.ss_ScanTupleSlot = slot;
 
 	return slot;
@@ -144,12 +148,13 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
 		ExecInitExpr((Expr *) node->scan.plan.qual,
 					 (PlanState *) subquerystate);
 
-#define SUBQUERYSCAN_NSLOTS 1
+#define SUBQUERYSCAN_NSLOTS 2
 
 	/*
 	 * tuple table initialization
 	 */
 	ExecInitResultTupleSlot(estate, &subquerystate->ss.ps);
+	ExecInitScanTupleSlot(estate, &subquerystate->ss);
 
 	/*
 	 * initialize subquery
@@ -159,6 +164,11 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
 	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, however.  XXX if
@@ -187,14 +197,20 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
 
 	MemoryContextSwitchTo(oldcontext);
 
-	subquerystate->ss.ss_ScanTupleSlot = NULL;
 	subquerystate->ss.ps.ps_TupFromTlist = false;
 
+	/*
+	 * Initialize scan tuple type (needed by ExecAssignScanProjectionInfo)
+	 */
+	ExecAssignScanType(&subquerystate->ss,
+					   ExecGetResultType(subquerystate->subplan),
+					   false);
+
 	/*
 	 * Initialize result tuple type and projection info.
 	 */
 	ExecAssignResultTypeFromTL(&subquerystate->ss.ps);
-	ExecAssignProjectionInfo(&subquerystate->ss.ps);
+	ExecAssignScanProjectionInfo(&subquerystate->ss);
 
 	return subquerystate;
 }
@@ -230,6 +246,7 @@ ExecEndSubqueryScan(SubqueryScanState *node)
 	 * clean out the upper tuple table
 	 */
 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+	node->ss.ss_ScanTupleSlot = NULL;		/* not ours to clear */
 
 	/*
 	 * close down subquery
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index e042468c6654199d1318ecc1ed828746f9726c9d..930355b5204d5d37a59e766f268a8e57a15c16e3 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.188 2005/04/25 04:27:12 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.189 2005/05/22 22:30:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -308,10 +308,11 @@ use_physical_tlist(RelOptInfo *rel)
 	int			i;
 
 	/*
-	 * Currently, can't do this for subquery or function scans.  (This is
-	 * mainly because we don't have an equivalent of build_physical_tlist
-	 * for them; worth adding?)
+	 * OK for subquery scans, but not function scans.  (This is mainly
+	 * because build_physical_tlist doesn't support them; worth adding?)
 	 */
+	if (rel->rtekind == RTE_SUBQUERY)
+		return true;
 	if (rel->rtekind != RTE_RELATION)
 		return false;
 
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 2e83a7417df466ed6da67458475ed4b4791ef835..c14983baa0f052436391f35305763d1d534a4e43 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.185 2005/04/28 21:47:13 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.186 2005/05/22 22:30:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -144,12 +144,12 @@ planner(Query *parse, bool isCursor, int cursorOptions,
 			result_plan = materialize_finished_plan(result_plan);
 	}
 
+	/* final cleanup of the plan */
+	result_plan = set_plan_references(result_plan, parse->rtable);
+
 	/* executor wants to know total number of Params used overall */
 	result_plan->nParamExec = list_length(PlannerParamList);
 
-	/* final cleanup of the plan */
-	set_plan_references(result_plan, parse->rtable);
-
 	/* restore state for outer planner, if any */
 	PlannerQueryLevel = save_PlannerQueryLevel;
 	PlannerParamList = save_PlannerParamList;
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 0dc0f1393c8503a59e34d65455a71dee8e542bfd..c3eb36bcfc4815d0d12b12c9dd5040bc10fd4630 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.109 2005/04/25 01:30:13 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.110 2005/05/22 22:30:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -41,6 +41,11 @@ typedef struct
 	bool		tlist_has_non_vars;
 } replace_vars_with_subplan_refs_context;
 
+static Plan *set_subqueryscan_references(SubqueryScan *plan, List *rtable);
+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, List *rtable);
@@ -76,23 +81,42 @@ static void set_sa_opfuncid(ScalarArrayOpExpr *opexpr);
 
 /*
  * set_plan_references
- *	  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).
  *
- *	  set_plan_references recursively traverses the whole plan tree.
+ * 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).
  *
- * Returns nothing of interest, but modifies internal fields of nodes.
+ * 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
+ * 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.
+ *
+ * set_plan_references recursively traverses the whole plan tree.
+ *
+ * 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.)
  */
-void
+Plan *
 set_plan_references(Plan *plan, List *rtable)
 {
 	ListCell   *l;
 
 	if (plan == NULL)
-		return;
+		return NULL;
 
 	/*
 	 * Plan-type-specific fixes
@@ -133,25 +157,8 @@ set_plan_references(Plan *plan, List *rtable)
 								(Node *) ((TidScan *) plan)->tideval);
 			break;
 		case T_SubqueryScan:
-			{
-				RangeTblEntry *rte;
-
-				/*
-				 * We do not do set_uppernode_references() here, because a
-				 * SubqueryScan will always have been created with correct
-				 * references to its subplan's outputs to begin with.
-				 */
-				fix_expr_references(plan, (Node *) plan->targetlist);
-				fix_expr_references(plan, (Node *) plan->qual);
-
-				/* Recurse into subplan too */
-				rte = rt_fetch(((SubqueryScan *) plan)->scan.scanrelid,
-							   rtable);
-				Assert(rte->rtekind == RTE_SUBQUERY);
-				set_plan_references(((SubqueryScan *) plan)->subplan,
-									rte->subquery->rtable);
-			}
-			break;
+			/* Needs special treatment, see comments below */
+			return set_subqueryscan_references((SubqueryScan *) plan, rtable);
 		case T_FunctionScan:
 			{
 				RangeTblEntry *rte;
@@ -194,14 +201,18 @@ set_plan_references(Plan *plan, List *rtable)
 
 			/*
 			 * These plan types don't actually bother to evaluate their
-			 * targetlists or quals (because they just return their
-			 * unmodified input tuples).  The optimizer is lazy about
-			 * creating really valid targetlists for them.	Best to just
-			 * leave the targetlist alone.	In particular, we do not want
-			 * to process subplans for them, since we will likely end up
-			 * reprocessing subplans that also appear in lower levels of
-			 * the plan tree!
+			 * 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!
+			 *
+			 * 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:
 
@@ -210,6 +221,7 @@ set_plan_references(Plan *plan, List *rtable)
 			 * 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);
 			break;
@@ -237,22 +249,27 @@ set_plan_references(Plan *plan, List *rtable)
 
 			/*
 			 * Append, like Sort et al, doesn't actually evaluate its
-			 * targetlist or quals, and we haven't bothered to give it its
-			 * own tlist copy. So, don't fix targetlist/qual. But do
+			 * 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)
-				set_plan_references((Plan *) lfirst(l), rtable);
+				lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);
 			break;
 		case T_BitmapAnd:
-			/* BitmapAnd works like Append */
+			/* BitmapAnd works like Append, but has no tlist */
+			Assert(plan->targetlist == NIL);
+			Assert(plan->qual == NIL);
 			foreach(l, ((BitmapAnd *) plan)->bitmapplans)
-				set_plan_references((Plan *) lfirst(l), rtable);
+				lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);
 			break;
 		case T_BitmapOr:
-			/* BitmapOr works like Append */
+			/* BitmapOr works like Append, but has no tlist */
+			Assert(plan->targetlist == NIL);
+			Assert(plan->qual == NIL);
 			foreach(l, ((BitmapOr *) plan)->bitmapplans)
-				set_plan_references((Plan *) lfirst(l), rtable);
+				lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);
 			break;
 		default:
 			elog(ERROR, "unrecognized node type: %d",
@@ -270,16 +287,349 @@ set_plan_references(Plan *plan, List *rtable)
 	 * children.  Fortunately, that consideration doesn't apply to SubPlan
 	 * nodes; else we'd need two passes over the expression trees.
 	 */
-	set_plan_references(plan->lefttree, rtable);
-	set_plan_references(plan->righttree, rtable);
+	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));
-		set_plan_references(sp->plan, sp->rtable);
+		sp->plan = set_plan_references(sp->plan, sp->rtable);
+	}
+
+	return plan;
+}
+
+/*
+ * set_subqueryscan_references
+ *		Do set_plan_references processing on a SubqueryScan
+ *
+ * We try to strip out the SubqueryScan entirely; if we can't, we have
+ * to do the normal processing on it.
+ */
+static Plan *
+set_subqueryscan_references(SubqueryScan *plan, List *rtable)
+{
+	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);
+
+		Assert(IsA(sp, SubPlan));
+		sp->plan = set_plan_references(sp->plan, sp->rtable);
+	}
+
+	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.
+		 */
+		int		rtoffset = list_length(rtable);
+		List   *sub_rtable;
+
+		sub_rtable = copyObject(rte->subquery->rtable);
+		range_table_walker(sub_rtable,
+						   adjust_expr_varnos_walker,
+						   (void *) &rtoffset,
+						   QTW_IGNORE_RT_SUBQUERIES);
+		rtable = list_concat(rtable, sub_rtable);
+
+		result = plan->subplan;
+
+		adjust_plan_varnos(result, rtoffset);
+
+		result->initPlan = list_concat(plan->scan.plan.initPlan,
+									   result->initPlan);
+	}
+	else
+	{
+		/*
+		 * 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 always have been created with correct
+		 * references to its subplan's outputs to begin with.
+		 */
+		result = (Plan *) plan;
+
+		fix_expr_references(result, (Node *) result->targetlist);
+		fix_expr_references(result, (Node *) result->qual);
+	}
+
+	return result;
+}
+
+/*
+ * trivial_subqueryscan
+ *		Detect whether a SubqueryScan can be deleted from the plan tree.
+ *
+ * We can delete it if it has no qual to check and the targetlist just
+ * regurgitates the output of the child plan.
+ */
+static bool
+trivial_subqueryscan(SubqueryScan *plan)
+{
+	int			attrno;
+	ListCell   *lp,
+			   *lc;
+
+	if (plan->scan.plan.qual != NIL)
+		return false;
+
+	attrno = 1;
+	forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)
+	{
+		TargetEntry *ptle = (TargetEntry *) lfirst(lp);
+		TargetEntry *ctle = (TargetEntry *) lfirst(lc);
+		Var		   *var = (Var *) ptle->expr;
+
+		if (ptle->resjunk != ctle->resjunk)
+			return false;		/* tlist doesn't match junk status */
+		if (!var || !IsA(var, Var))
+			return false;		/* tlist item not a Var */
+		Assert(var->varno == plan->scan.scanrelid);
+		Assert(var->varlevelsup == 0);
+		if (var->varattno != attrno)
+			return false;		/* out of order */
+		attrno++;
+	}
+
+	if (lp)
+		return false;			/* parent tlist longer than child */
+
+	/* extra child items are OK only if all are resjunk */
+	for_each_cell(lc, lc)
+	{
+		TargetEntry *ctle = (TargetEntry *) lfirst(lc);
+
+		if (!ctle->resjunk)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * 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)->tideval,
+							   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);
+			/* rte was already fixed by set_subqueryscan_references */
+			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).
+			 * We have to make a copy because the tlist is very likely
+			 * shared with lower plan levels.
+			 */
+			plan->targetlist = copyObject(plan->targetlist);
+			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.
+			 */
+			plan->targetlist = copyObject(plan->targetlist);
+			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:
+
+			/*
+			 * 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, copy tlist before fixing.  Then
+			 * recurse into child plans.
+			 */
+			plan->targetlist = copyObject(plan->targetlist);
+			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.
+ *
+ * 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.
+ */
+static void
+adjust_expr_varnos(Node *node, int rtoffset)
+{
+	/* This tree walk requires no special setup, so away we go... */
+	adjust_expr_varnos_walker(node, &rtoffset);
+}
+
+static bool
+adjust_expr_varnos_walker(Node *node, int *context)
+{
+	if (node == NULL)
+		return false;
+	if (IsA(node, Var))
+	{
+		Var		   *var = (Var *) node;
+
+		Assert(var->varlevelsup == 0);
+		if (var->varno > 0 && var->varno != INNER && var->varno != OUTER)
+			var->varno += *context;
+		if (var->varnoold > 0)
+			var->varnoold += *context;
+		return false;
 	}
+	return expression_tree_walker(node, adjust_expr_varnos_walker,
+								  (void *) context);
 }
 
 /*
@@ -315,7 +665,7 @@ fix_expr_references_walker(Node *node, void *context)
 	{
 		SubPlan    *sp = (SubPlan *) node;
 
-		set_plan_references(sp->plan, sp->rtable);
+		sp->plan = set_plan_references(sp->plan, sp->rtable);
 	}
 	return expression_tree_walker(node, fix_expr_references_walker, context);
 }
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index ae3c3a8c18219d39a0671f6b6409fa3b4fa5e09e..0f532a99453f1047f5fd4d1965d249154a6603df 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.120 2005/04/06 16:34:06 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.121 2005/05/22 22:30:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,6 +61,7 @@ static List *recurse_union_children(Node *setOp, Query *parse,
 					   SetOperationStmt *top_union,
 					   List *refnames_tlist);
 static List *generate_setop_tlist(List *colTypes, int flag,
+					 Index varno,
 					 bool hack_constants,
 					 List *input_tlist,
 					 List *refnames_tlist);
@@ -119,8 +120,8 @@ plan_set_operations(Query *parse, List **sortClauses)
 	/*
 	 * Recurse on setOperations tree to generate plans for set ops. The
 	 * final output plan should have just the column types shown as the
-	 * output from the top-level node, plus possibly a resjunk working
-	 * column (we can rely on upper-level nodes to deal with that).
+	 * output from the top-level node, plus possibly resjunk working
+	 * columns (we can rely on upper-level nodes to deal with that).
 	 */
 	return recurse_set_operations((Node *) topop, parse,
 								  topop->colTypes, true, -1,
@@ -163,7 +164,9 @@ recurse_set_operations(Node *setOp, Query *parse,
 		 * Add a SubqueryScan with the caller-requested targetlist
 		 */
 		plan = (Plan *)
-			make_subqueryscan(generate_setop_tlist(colTypes, flag, true,
+			make_subqueryscan(generate_setop_tlist(colTypes, flag,
+												   rtr->rtindex,
+												   true,
 												   subplan->targetlist,
 												   refnames_tlist),
 							  NIL,
@@ -202,13 +205,15 @@ recurse_set_operations(Node *setOp, Query *parse,
 		 * the subplan.  However, since the subplan was generated by
 		 * generate_union_plan() or generate_nonunion_plan(), and hence
 		 * its tlist was generated by generate_append_tlist(), this will
-		 * work.
+		 * work.  We just tell generate_setop_tlist() to use varno 0.
 		 */
 		if (flag >= 0 ||
 			!tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
 		{
 			plan = (Plan *)
-				make_result(generate_setop_tlist(colTypes, flag, false,
+				make_result(generate_setop_tlist(colTypes, flag,
+												 0,
+												 false,
 												 plan->targetlist,
 												 refnames_tlist),
 							NULL,
@@ -415,12 +420,14 @@ recurse_union_children(Node *setOp, Query *parse,
  *
  * colTypes: column datatypes for non-junk columns
  * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
+ * varno: varno to use in generated Vars
  * hack_constants: true to copy up constants (see comments in code)
  * input_tlist: targetlist of this node's input node
  * refnames_tlist: targetlist to take column names from
  */
 static List *
 generate_setop_tlist(List *colTypes, int flag,
+					 Index varno,
 					 bool hack_constants,
 					 List *input_tlist,
 					 List *refnames_tlist)
@@ -462,7 +469,7 @@ generate_setop_tlist(List *colTypes, int flag,
 		if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
 			expr = (Node *) inputtle->expr;
 		else
-			expr = (Node *) makeVar(0,
+			expr = (Node *) makeVar(varno,
 									inputtle->resno,
 									exprType((Node *) inputtle->expr),
 									exprTypmod((Node *) inputtle->expr),
@@ -513,6 +520,7 @@ generate_setop_tlist(List *colTypes, int flag,
  *
  * The entries in the Append's targetlist should always be simple Vars;
  * we just have to make sure they have the right datatypes and typmods.
+ * The Vars are always generated with varno 0.
  */
 static List *
 generate_append_tlist(List *colTypes, bool flag,
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8ddb4df45a31a77fe8d3693d9fed261304832202..429e5d2495cda6c3c06fd75ab6903c677f0b9e08 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.196 2005/04/23 04:42:53 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.197 2005/05/22 22:30:20 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -3026,8 +3026,6 @@ query_tree_walker(Query *query,
 				  void *context,
 				  int flags)
 {
-	ListCell   *rt;
-
 	Assert(query != NULL && IsA(query, Query));
 
 	if (walker((Node *) query->targetList, context))
@@ -3044,7 +3042,25 @@ query_tree_walker(Query *query,
 		return true;
 	if (walker(query->in_info_list, context))
 		return true;
-	foreach(rt, query->rtable)
+	if (range_table_walker(query->rtable, walker, context, flags))
+		return true;
+	return false;
+}
+
+/*
+ * range_table_walker is just the part of query_tree_walker that scans
+ * a query's rangetable.  This is split out since it can be useful on
+ * its own.
+ */
+bool
+range_table_walker(List *rtable,
+				   bool (*walker) (),
+				   void *context,
+				   int flags)
+{
+	ListCell   *rt;
+
+	foreach(rt, rtable)
 	{
 		RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
 
@@ -3532,9 +3548,6 @@ query_tree_mutator(Query *query,
 				   void *context,
 				   int flags)
 {
-	List	   *newrt;
-	ListCell   *rt;
-
 	Assert(query != NULL && IsA(query, Query));
 
 	if (!(flags & QTW_DONT_COPY_QUERY))
@@ -3552,8 +3565,26 @@ query_tree_mutator(Query *query,
 	MUTATE(query->limitOffset, query->limitOffset, Node *);
 	MUTATE(query->limitCount, query->limitCount, Node *);
 	MUTATE(query->in_info_list, query->in_info_list, List *);
-	newrt = NIL;
-	foreach(rt, query->rtable)
+	query->rtable = range_table_mutator(query->rtable,
+										mutator, context, flags);
+	return query;
+}
+
+/*
+ * range_table_mutator is just the part of query_tree_mutator that processes
+ * a query's rangetable.  This is split out since it can be useful on
+ * its own.
+ */
+List *
+range_table_mutator(List *rtable,
+					Node *(*mutator) (),
+					void *context,
+					int flags)
+{
+	List	   *newrt = NIL;
+	ListCell   *rt;
+
+	foreach(rt, rtable)
 	{
 		RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
 		RangeTblEntry *newrte;
@@ -3592,8 +3623,7 @@ query_tree_mutator(Query *query,
 		}
 		newrt = lappend(newrt, newrte);
 	}
-	query->rtable = newrt;
-	return query;
+	return newrt;
 }
 
 /*
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 8c9b34f0fe7a70052ac047aa96123facce58d08b..ad4e3cd34724f0eb64542c0e1fc2361e6078ad79 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.106 2005/04/22 21:58:31 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.107 2005/05/22 22:30:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,7 @@
 #include "optimizer/plancat.h"
 #include "optimizer/tlist.h"
 #include "parser/parsetree.h"
+#include "parser/parse_expr.h"
 #include "rewrite/rewriteManip.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
@@ -353,49 +354,82 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
  * relation, but that data is not readily available to ExecTypeFromTL.
  * For now, we don't apply the physical-tlist optimization when there are
  * dropped cols.
+ *
+ * We also support building a "physical" tlist for subqueries, since the
+ * same optimization can occur in SubqueryScan nodes.
  */
 List *
 build_physical_tlist(Query *root, RelOptInfo *rel)
 {
+	List	   *tlist = NIL;
 	Index		varno = rel->relid;
 	RangeTblEntry *rte = rt_fetch(varno, root->rtable);
 	Relation	relation;
-	List	   *tlist = NIL;
+	Query	   *subquery;
+	Var		   *var;
+	ListCell   *l;
 	int			attrno,
 				numattrs;
 
-	Assert(rte->rtekind == RTE_RELATION);
+	switch (rte->rtekind)
+	{
+		case RTE_RELATION:
+			relation = heap_open(rte->relid, AccessShareLock);
 
-	relation = heap_open(rte->relid, AccessShareLock);
+			numattrs = RelationGetNumberOfAttributes(relation);
+			for (attrno = 1; attrno <= numattrs; attrno++)
+			{
+				Form_pg_attribute att_tup = relation->rd_att->attrs[attrno - 1];
 
-	numattrs = RelationGetNumberOfAttributes(relation);
+				if (att_tup->attisdropped)
+				{
+					/* found a dropped col, so punt */
+					tlist = NIL;
+					break;
+				}
 
-	for (attrno = 1; attrno <= numattrs; attrno++)
-	{
-		Form_pg_attribute att_tup = relation->rd_att->attrs[attrno - 1];
-		Var	   *var;
+				var = makeVar(varno,
+							  attrno,
+							  att_tup->atttypid,
+							  att_tup->atttypmod,
+							  0);
+
+				tlist = lappend(tlist,
+								makeTargetEntry((Expr *) var,
+												attrno,
+												NULL,
+												false));
+			}
 
-		if (att_tup->attisdropped)
-		{
-			/* found a dropped col, so punt */
-			tlist = NIL;
+			heap_close(relation, AccessShareLock);
 			break;
-		}
 
-		var = makeVar(varno,
-					  attrno,
-					  att_tup->atttypid,
-					  att_tup->atttypmod,
-					  0);
-
-		tlist = lappend(tlist,
-						makeTargetEntry((Expr *) var,
-										attrno,
-										NULL,
-										false));
-	}
+		case RTE_SUBQUERY:
+			subquery = rte->subquery;
+			foreach(l, subquery->targetList)
+			{
+				TargetEntry *tle = (TargetEntry *) lfirst(l);
+
+				var = makeVar(varno,
+							  tle->resno,
+							  exprType((Node *) tle->expr),
+							  exprTypmod((Node *) tle->expr),
+							  0);
+
+				tlist = lappend(tlist,
+								makeTargetEntry((Expr *) var,
+												tle->resno,
+												NULL,
+												tle->resjunk));
+			}
+			break;
 
-	heap_close(relation, AccessShareLock);
+		default:
+			/* caller error */
+			elog(ERROR, "unsupported RTE kind %d in build_physical_tlist",
+				 (int) rte->rtekind);
+			break;
+	}
 
 	return tlist;
 }
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index b2ec17ef40574e5610d4ab6aa20b1fd1d7cb5623..ae5ab79f987dd244567d0c30e843a1f0060aa845 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.78 2005/01/28 19:34:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.79 2005/05/22 22:30:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -87,9 +87,14 @@ extern Node *expression_tree_mutator(Node *node, Node *(*mutator) (),
 #define QTW_DONT_COPY_QUERY			0x04		/* do not copy top Query */
 
 extern bool query_tree_walker(Query *query, bool (*walker) (),
-										  void *context, int flags);
+							  void *context, int flags);
 extern Query *query_tree_mutator(Query *query, Node *(*mutator) (),
-											 void *context, int flags);
+								 void *context, int flags);
+
+extern bool range_table_walker(List *rtable, bool (*walker) (),
+							   void *context, int flags);
+extern List *range_table_mutator(List *rtable, Node *(*mutator) (),
+								 void *context, int flags);
 
 extern bool query_or_expression_tree_walker(Node *node, bool (*walker) (),
 											   void *context, int flags);
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 129439ddec895f086d3841cca6590f16e1630e43..bb27bf01d57ca3a0d4f786e424170a6c185c53ad 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.84 2005/04/25 02:14:48 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.85 2005/05/22 22:30:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -74,7 +74,7 @@ extern void process_implied_equality(Query *root,
 /*
  * prototypes for plan/setrefs.c
  */
-extern void set_plan_references(Plan *plan, List *rtable);
+extern Plan *set_plan_references(Plan *plan, List *rtable);
 extern void fix_opfuncids(Node *node);
 extern void set_opfuncid(OpExpr *opexpr);