From 2d8d66628a8ac49deba8483608135b3c358ae729 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 14 Dec 2002 00:17:59 +0000
Subject: [PATCH] Clean up plantree representation of SubPlan-s --- SubLink
 does not appear in the planned representation of a subplan at all any more,
 only SubPlan. This means subselect.c doesn't scribble on its input anymore,
 which seems like a good thing; and there are no longer three different
 possible interpretations of a SubLink.  Simplify node naming and improve
 comments in primnodes.h.  No change to stored rules, though.

---
 src/backend/commands/explain.c         |  10 +-
 src/backend/executor/execAmi.c         |   6 +-
 src/backend/executor/execProcnode.c    |  16 +-
 src/backend/executor/execQual.c        |  45 ++---
 src/backend/executor/nodeSubplan.c     |  47 +++--
 src/backend/nodes/copyfuncs.c          |  19 ++-
 src/backend/nodes/equalfuncs.c         |  13 +-
 src/backend/nodes/outfuncs.c           |  15 +-
 src/backend/nodes/readfuncs.c          |   4 +-
 src/backend/optimizer/path/costsize.c  |  12 +-
 src/backend/optimizer/plan/planner.c   |   6 +-
 src/backend/optimizer/plan/setrefs.c   |  12 +-
 src/backend/optimizer/plan/subselect.c | 227 +++++++++++++------------
 src/backend/optimizer/prep/prepunion.c |   6 +-
 src/backend/optimizer/util/clauses.c   | 121 ++++++-------
 src/backend/optimizer/util/var.c       |  14 +-
 src/backend/utils/adt/ruleutils.c      |   4 +-
 src/include/executor/executor.h        |   5 +-
 src/include/executor/nodeSubplan.h     |  12 +-
 src/include/nodes/execnodes.h          |  17 +-
 src/include/nodes/nodes.h              |   6 +-
 src/include/nodes/params.h             |   6 +-
 src/include/nodes/primnodes.h          |  88 +++++-----
 src/include/optimizer/clauses.h        |   4 +-
 24 files changed, 357 insertions(+), 358 deletions(-)

diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 1f9e7543d6f..05815a2201b 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.97 2002/12/13 19:45:49 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.98 2002/12/14 00:17:50 tgl Exp $
  *
  */
 
@@ -589,8 +589,8 @@ explain_outNode(StringInfo str,
 		appendStringInfo(str, "  InitPlan\n");
 		foreach(lst, planstate->initPlan)
 		{
-			SubPlanExprState *sps = (SubPlanExprState *) lfirst(lst);
-			SubPlanExpr *sp = (SubPlanExpr *) sps->xprstate.expr;
+			SubPlanState *sps = (SubPlanState *) lfirst(lst);
+			SubPlan *sp = (SubPlan *) sps->xprstate.expr;
 
 			es->rtable = sp->rtable;
 			for (i = 0; i < indent; i++)
@@ -687,8 +687,8 @@ explain_outNode(StringInfo str,
 		appendStringInfo(str, "  SubPlan\n");
 		foreach(lst, planstate->subPlan)
 		{
-			SubPlanExprState *sps = (SubPlanExprState *) lfirst(lst);
-			SubPlanExpr *sp = (SubPlanExpr *) sps->xprstate.expr;
+			SubPlanState *sps = (SubPlanState *) lfirst(lst);
+			SubPlan *sp = (SubPlan *) sps->xprstate.expr;
 
 			es->rtable = sp->rtable;
 			for (i = 0; i < indent; i++)
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index fa95ad6d992..c55e5ecd149 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.67 2002/12/13 19:45:52 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.68 2002/12/14 00:17:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,7 +61,7 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
 
 		foreach(lst, node->initPlan)
 		{
-			SubPlanExprState  *sstate = (SubPlanExprState *) lfirst(lst);
+			SubPlanState  *sstate = (SubPlanState *) lfirst(lst);
 			PlanState  *splan = sstate->planstate;
 
 			if (splan->plan->extParam != NIL)	/* don't care about child
@@ -72,7 +72,7 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
 		}
 		foreach(lst, node->subPlan)
 		{
-			SubPlanExprState  *sstate = (SubPlanExprState *) lfirst(lst);
+			SubPlanState  *sstate = (SubPlanState *) lfirst(lst);
 			PlanState  *splan = sstate->planstate;
 
 			if (splan->plan->extParam != NIL)
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 59c798b267a..dc5a3085ead 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.33 2002/12/13 19:45:52 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.34 2002/12/14 00:17:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -228,10 +228,10 @@ ExecInitNode(Plan *node, EState *estate)
 	subps = NIL;
 	foreach(subp, node->initPlan)
 	{
-		SubPlanExpr *subplan = (SubPlanExpr *) lfirst(subp);
-		SubPlanExprState *sstate;
+		SubPlan	   *subplan = (SubPlan *) lfirst(subp);
+		SubPlanState *sstate;
 
-		Assert(IsA(subplan, SubPlanExpr));
+		Assert(IsA(subplan, SubPlan));
 		sstate = ExecInitExprInitPlan(subplan, result);
 		ExecInitSubPlan(sstate, estate);
 		subps = lappend(subps, sstate);
@@ -247,9 +247,9 @@ ExecInitNode(Plan *node, EState *estate)
 	subps = NIL;
 	foreach(subp, result->subPlan)
 	{
-		SubPlanExprState *sstate = (SubPlanExprState *) lfirst(subp);
+		SubPlanState *sstate = (SubPlanState *) lfirst(subp);
 
-		Assert(IsA(sstate, SubPlanExprState));
+		Assert(IsA(sstate, SubPlanState));
 		ExecInitSubPlan(sstate, estate);
 		subps = lappend(subps, sstate);
 	}
@@ -500,9 +500,9 @@ ExecEndNode(PlanState *node)
 
 	/* Clean up initPlans and subPlans */
 	foreach(subp, node->initPlan)
-		ExecEndSubPlan((SubPlanExprState *) lfirst(subp));
+		ExecEndSubPlan((SubPlanState *) lfirst(subp));
 	foreach(subp, node->subPlan)
-		ExecEndSubPlan((SubPlanExprState *) lfirst(subp));
+		ExecEndSubPlan((SubPlanState *) lfirst(subp));
 
 	if (node->chgParam != NIL)
 	{
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index b529d045c4d..a3f79c3ac80 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.119 2002/12/13 19:45:52 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.120 2002/12/14 00:17:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1794,8 +1794,8 @@ ExecEvalExpr(ExprState *expression,
 				}
 				break;
 			}
-		case T_SubPlanExpr:
-			retDatum = ExecSubPlan((SubPlanExprState *) expression,
+		case T_SubPlan:
+			retDatum = ExecSubPlan((SubPlanState *) expression,
 								   econtext,
 								   isNull);
 			break;
@@ -1883,7 +1883,7 @@ ExecEvalExprSwitchContext(ExprState *expression,
  * executions of the expression are needed.  Typically the context will be
  * the same as the per-query context of the associated ExprContext.
  *
- * Any Aggref and SubplanExpr nodes found in the tree are added to the lists
+ * Any Aggref and SubPlan nodes found in the tree are added to the lists
  * of such nodes held by the parent PlanState.  Otherwise, we do very little
  * initialization here other than building the state-node tree.  Any nontrivial
  * work associated with initializing runtime info for a node should happen
@@ -2003,31 +2003,26 @@ ExecInitExpr(Expr *node, PlanState *parent)
 				state = (ExprState *) bstate;
 			}
 			break;
-		case T_SubPlanExpr:
+		case T_SubPlan:
 			{
 				/* Keep this in sync with ExecInitExprInitPlan, below */
-				SubPlanExpr *subplanexpr = (SubPlanExpr *) node;
-				SubLink *sublink = subplanexpr->sublink;
-				SubPlanExprState *sstate = makeNode(SubPlanExprState);
+				SubPlan *subplan = (SubPlan *) node;
+				SubPlanState *sstate = makeNode(SubPlanState);
 
-				Assert(IsA(sublink, SubLink));
 				if (!parent)
-					elog(ERROR, "ExecInitExpr: SubPlanExpr not expected here");
+					elog(ERROR, "ExecInitExpr: SubPlan not expected here");
 
 				/*
-				 * Here we just add the SubPlanExprState nodes to
+				 * Here we just add the SubPlanState nodes to
 				 * parent->subPlan.  The subplans will be initialized later.
 				 */
 				parent->subPlan = lcons(sstate, parent->subPlan);
 				sstate->planstate = NULL;
 
-				sstate->args = (List *)
-					ExecInitExpr((Expr *) subplanexpr->args, parent);
-
-				if (sublink->lefthand)
-					elog(ERROR, "ExecInitExpr: sublink has not been transformed");
 				sstate->oper = (List *)
-					ExecInitExpr((Expr *) sublink->oper, parent);
+					ExecInitExpr((Expr *) subplan->oper, parent);
+				sstate->args = (List *)
+					ExecInitExpr((Expr *) subplan->args, parent);
 
 				state = (ExprState *) sstate;
 			}
@@ -2145,26 +2140,20 @@ ExecInitExpr(Expr *node, PlanState *parent)
  * subplan expr, except we do NOT want to add the node to the parent's
  * subplan list.
  */
-SubPlanExprState *
-ExecInitExprInitPlan(SubPlanExpr *node, PlanState *parent)
+SubPlanState *
+ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
 {
-	SubLink *sublink = node->sublink;
-	SubPlanExprState *sstate = makeNode(SubPlanExprState);
+	SubPlanState *sstate = makeNode(SubPlanState);
 
-	Assert(IsA(sublink, SubLink));
 	if (!parent)
-		elog(ERROR, "ExecInitExpr: SubPlanExpr not expected here");
+		elog(ERROR, "ExecInitExpr: SubPlan not expected here");
 
 	/* The subplan's state will be initialized later */
 	sstate->planstate = NULL;
 
+	sstate->oper = (List *) ExecInitExpr((Expr *) node->oper, parent);
 	sstate->args = (List *) ExecInitExpr((Expr *) node->args, parent);
 
-	if (sublink->lefthand)
-		elog(ERROR, "ExecInitExpr: sublink has not been transformed");
-
-	sstate->oper = (List *) ExecInitExpr((Expr *) sublink->oper, parent);
-
 	sstate->xprstate.expr = (Expr *) node;
 
 	return sstate;
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 69fcc58e079..3a2ca974aee 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.37 2002/12/13 19:45:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.38 2002/12/14 00:17:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,15 +30,14 @@
  * ----------------------------------------------------------------
  */
 Datum
-ExecSubPlan(SubPlanExprState *node,
+ExecSubPlan(SubPlanState *node,
 			ExprContext *econtext,
 			bool *isNull)
 {
+	SubPlan	   *subplan = (SubPlan *) node->xprstate.expr;
 	PlanState  *planstate = node->planstate;
-	SubPlanExpr *subplan = (SubPlanExpr *) node->xprstate.expr;
-	SubLink    *sublink = subplan->sublink;
-	SubLinkType subLinkType = sublink->subLinkType;
-	bool		useor = sublink->useor;
+	SubLinkType subLinkType = subplan->subLinkType;
+	bool		useor = subplan->useor;
 	MemoryContext oldcontext;
 	TupleTableSlot *slot;
 	Datum		result;
@@ -292,56 +291,56 @@ ExecSubPlan(SubPlanExprState *node,
  * ----------------------------------------------------------------
  */
 void
-ExecInitSubPlan(SubPlanExprState *sstate, EState *estate)
+ExecInitSubPlan(SubPlanState *node, EState *estate)
 {
-	SubPlanExpr *expr = (SubPlanExpr *) sstate->xprstate.expr;
+	SubPlan	   *subplan = (SubPlan *) node->xprstate.expr;
 	EState	   *sp_estate;
 
 	/*
 	 * Do access checking on the rangetable entries in the subquery.
 	 * Here, we assume the subquery is a SELECT.
 	 */
-	ExecCheckRTPerms(expr->rtable, CMD_SELECT);
+	ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
 
 	/*
 	 * initialize state
 	 */
-	sstate->needShutdown = false;
-	sstate->curTuple = NULL;
+	node->needShutdown = false;
+	node->curTuple = NULL;
 
 	/*
 	 * create an EState for the subplan
 	 */
 	sp_estate = CreateExecutorState();
 
-	sp_estate->es_range_table = expr->rtable;
+	sp_estate->es_range_table = subplan->rtable;
 	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(expr->plan) + 10);
+		ExecCreateTupleTable(ExecCountSlotsNode(subplan->plan) + 10);
 	sp_estate->es_snapshot = estate->es_snapshot;
 	sp_estate->es_instrument = estate->es_instrument;
 
 	/*
 	 * Start up the subplan
 	 */
-	sstate->planstate = ExecInitNode(expr->plan, sp_estate);
+	node->planstate = ExecInitNode(subplan->plan, sp_estate);
 
-	sstate->needShutdown = true;	/* now we need to shutdown the subplan */
+	node->needShutdown = true;	/* now we need to shutdown the subplan */
 
 	/*
 	 * If this plan is un-correlated or undirect correlated one and want
 	 * to set params for parent plan then prepare parameters.
 	 */
-	if (expr->setParam != NIL)
+	if (subplan->setParam != NIL)
 	{
 		List	   *lst;
 
-		foreach(lst, expr->setParam)
+		foreach(lst, subplan->setParam)
 		{
 			ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
 
-			prm->execPlan = sstate;
+			prm->execPlan = node;
 		}
 
 		/*
@@ -366,11 +365,11 @@ ExecInitSubPlan(SubPlanExprState *sstate, EState *estate)
  * ----------------------------------------------------------------
  */
 void
-ExecSetParamPlan(SubPlanExprState *node, ExprContext *econtext)
+ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 {
+	SubPlan	   *subplan = (SubPlan *) node->xprstate.expr;
 	PlanState  *planstate = node->planstate;
-	SubPlanExpr *subplan = (SubPlanExpr *) node->xprstate.expr;
-	SubLinkType	subLinkType = subplan->sublink->subLinkType;
+	SubLinkType	subLinkType = subplan->subLinkType;
 	MemoryContext oldcontext;
 	TupleTableSlot *slot;
 	List	   *lst;
@@ -473,7 +472,7 @@ ExecSetParamPlan(SubPlanExprState *node, ExprContext *econtext)
  * ----------------------------------------------------------------
  */
 void
-ExecEndSubPlan(SubPlanExprState *node)
+ExecEndSubPlan(SubPlanState *node)
 {
 	if (node->needShutdown)
 	{
@@ -488,10 +487,10 @@ ExecEndSubPlan(SubPlanExprState *node)
 }
 
 void
-ExecReScanSetParamPlan(SubPlanExprState *node, PlanState *parent)
+ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
 {
 	PlanState  *planstate = node->planstate;
-	SubPlanExpr *subplan = (SubPlanExpr *) node->xprstate.expr;
+	SubPlan	   *subplan = (SubPlan *) node->xprstate.expr;
 	EState	   *estate = parent->state;
 	List	   *lst;
 
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index d84e6061246..c3abcfc9e80 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.232 2002/12/13 19:45:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.233 2002/12/14 00:17:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -818,21 +818,22 @@ _copySubLink(SubLink *from)
 }
 
 /*
- * _copySubPlanExpr
+ * _copySubPlan
  */
-static SubPlanExpr *
-_copySubPlanExpr(SubPlanExpr *from)
+static SubPlan *
+_copySubPlan(SubPlan *from)
 {
-	SubPlanExpr    *newnode = makeNode(SubPlanExpr);
+	SubPlan    *newnode = makeNode(SubPlan);
 
-	COPY_SCALAR_FIELD(typeOid);
+	COPY_SCALAR_FIELD(subLinkType);
+	COPY_SCALAR_FIELD(useor);
+	COPY_NODE_FIELD(oper);
 	COPY_NODE_FIELD(plan);
 	COPY_SCALAR_FIELD(plan_id);
 	COPY_NODE_FIELD(rtable);
 	COPY_INTLIST_FIELD(setParam);
 	COPY_INTLIST_FIELD(parParam);
 	COPY_NODE_FIELD(args);
-	COPY_NODE_FIELD(sublink);
 
 	return newnode;
 }
@@ -2431,8 +2432,8 @@ copyObject(void *from)
 		case T_SubLink:
 			retval = _copySubLink(from);
 			break;
-		case T_SubPlanExpr:
-			retval = _copySubPlanExpr(from);
+		case T_SubPlan:
+			retval = _copySubPlan(from);
 			break;
 		case T_FieldSelect:
 			retval = _copyFieldSelect(from);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3fc924024e2..5fc333df3de 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.176 2002/12/12 20:35:12 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.177 2002/12/14 00:17:51 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -296,16 +296,17 @@ _equalSubLink(SubLink *a, SubLink *b)
 }
 
 static bool
-_equalSubPlanExpr(SubPlanExpr *a, SubPlanExpr *b)
+_equalSubPlan(SubPlan *a, SubPlan *b)
 {
-	COMPARE_SCALAR_FIELD(typeOid);
+	COMPARE_SCALAR_FIELD(subLinkType);
+	COMPARE_SCALAR_FIELD(useor);
+	COMPARE_NODE_FIELD(oper);
 	/* should compare plans, but have to settle for comparing plan IDs */
 	COMPARE_SCALAR_FIELD(plan_id);
 	COMPARE_NODE_FIELD(rtable);
 	COMPARE_INTLIST_FIELD(setParam);
 	COMPARE_INTLIST_FIELD(parParam);
 	COMPARE_NODE_FIELD(args);
-	COMPARE_NODE_FIELD(sublink);
 
 	return true;
 }
@@ -1561,8 +1562,8 @@ equal(void *a, void *b)
 		case T_SubLink:
 			retval = _equalSubLink(a, b);
 			break;
-		case T_SubPlanExpr:
-			retval = _equalSubPlanExpr(a, b);
+		case T_SubPlan:
+			retval = _equalSubPlan(a, b);
 			break;
 		case T_FieldSelect:
 			retval = _equalFieldSelect(a, b);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index a688b471e79..97fc9462a27 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.189 2002/12/13 19:45:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.190 2002/12/14 00:17:52 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -665,18 +665,19 @@ _outSubLink(StringInfo str, SubLink *node)
 }
 
 static void
-_outSubPlanExpr(StringInfo str, SubPlanExpr *node)
+_outSubPlan(StringInfo str, SubPlan *node)
 {
-	WRITE_NODE_TYPE("SUBPLANEXPR");
+	WRITE_NODE_TYPE("SUBPLAN");
 
-	WRITE_OID_FIELD(typeOid);
+	WRITE_ENUM_FIELD(subLinkType, SubLinkType);
+	WRITE_BOOL_FIELD(useor);
+	WRITE_NODE_FIELD(oper);
 	WRITE_NODE_FIELD(plan);
 	WRITE_INT_FIELD(plan_id);
 	WRITE_NODE_FIELD(rtable);
 	WRITE_INTLIST_FIELD(setParam);
 	WRITE_INTLIST_FIELD(parParam);
 	WRITE_NODE_FIELD(args);
-	WRITE_NODE_FIELD(sublink);
 }
 
 static void
@@ -1498,8 +1499,8 @@ _outNode(StringInfo str, void *obj)
 			case T_SubLink:
 				_outSubLink(str, obj);
 				break;
-			case T_SubPlanExpr:
-				_outSubPlanExpr(str, obj);
+			case T_SubPlan:
+				_outSubPlan(str, obj);
 				break;
 			case T_FieldSelect:
 				_outFieldSelect(str, obj);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 54e3916ebf6..9ecd40f2e1d 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.143 2002/12/13 19:45:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.144 2002/12/14 00:17:54 tgl Exp $
  *
  * NOTES
  *	  Path and Plan nodes do not have any readfuncs support, because we
@@ -540,7 +540,7 @@ _readSubLink(void)
 }
 
 /*
- * _readSubPlanExpr is not needed since it doesn't appear in stored rules.
+ * _readSubPlan is not needed since it doesn't appear in stored rules.
  */
 
 /*
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 114e8798856..5feaed49158 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -42,7 +42,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.95 2002/12/13 17:29:25 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.96 2002/12/14 00:17:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1234,7 +1234,7 @@ cost_qual_eval_walker(Node *node, Cost *total)
 		IsA(node, OpExpr) ||
 		IsA(node, DistinctExpr))
 		*total += cpu_operator_cost;
-	else if (IsA(node, SubPlanExpr))
+	else if (IsA(node, SubPlan))
 	{
 		/*
 		 * A subplan node in an expression indicates that the
@@ -1246,18 +1246,18 @@ cost_qual_eval_walker(Node *node, Cost *total)
 		 * NOTE: this logic should agree with the estimates used by
 		 * make_subplan() in plan/subselect.c.
 		 */
-		SubPlanExpr *subplan = (SubPlanExpr *) node;
+		SubPlan	   *subplan = (SubPlan *) node;
 		Plan	   *plan = subplan->plan;
 		Cost		subcost;
 
-		if (subplan->sublink->subLinkType == EXISTS_SUBLINK)
+		if (subplan->subLinkType == EXISTS_SUBLINK)
 		{
 			/* we only need to fetch 1 tuple */
 			subcost = plan->startup_cost +
 				(plan->total_cost - plan->startup_cost) / plan->plan_rows;
 		}
-		else if (subplan->sublink->subLinkType == ALL_SUBLINK ||
-				 subplan->sublink->subLinkType == ANY_SUBLINK)
+		else if (subplan->subLinkType == ALL_SUBLINK ||
+				 subplan->subLinkType == ANY_SUBLINK)
 		{
 			/* assume we need 50% of the tuples */
 			subcost = plan->startup_cost +
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index b3d7b5303c4..b7c0c2ad4b5 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.134 2002/12/12 15:49:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.135 2002/12/14 00:17:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -91,7 +91,7 @@ planner(Query *parse)
 	 * purpose is communication across multiple sub-Queries.
 	 *
 	 * Note we do NOT save and restore PlannerPlanId: it exists to assign
-	 * unique IDs to SubPlanExpr nodes, and we want those IDs to be unique for
+	 * unique IDs to SubPlan nodes, and we want those IDs to be unique for
 	 * the life of a backend.  Also, PlannerInitPlan is saved/restored in
 	 * subquery_planner, not here.
 	 */
@@ -278,7 +278,7 @@ subquery_planner(Query *parse, double tuple_fraction)
 		/* Must add the initPlans' extParams to the topmost node's, too */
 		foreach(lst, plan->initPlan)
 		{
-			SubPlanExpr *subplan = (SubPlanExpr *) lfirst(lst);
+			SubPlan	   *subplan = (SubPlan *) lfirst(lst);
 
 			plan->extParam = set_unioni(plan->extParam,
 										subplan->plan->extParam);
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 0d66c97964c..5081f9c3401 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.85 2002/12/12 15:49:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.86 2002/12/14 00:17:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -219,7 +219,7 @@ set_plan_references(Plan *plan, List *rtable)
 	 * 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 SubPlanExpr
+	 * 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);
@@ -227,9 +227,9 @@ set_plan_references(Plan *plan, List *rtable)
 
 	foreach(pl, plan->initPlan)
 	{
-		SubPlanExpr *sp = (SubPlanExpr *) lfirst(pl);
+		SubPlan *sp = (SubPlan *) lfirst(pl);
 
-		Assert(IsA(sp, SubPlanExpr));
+		Assert(IsA(sp, SubPlan));
 		set_plan_references(sp->plan, sp->rtable);
 	}
 }
@@ -259,9 +259,9 @@ fix_expr_references_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, SubPlanExpr))
+	else if (IsA(node, SubPlan))
 	{
-		SubPlanExpr *sp = (SubPlanExpr *) node;
+		SubPlan *sp = (SubPlan *) node;
 
 		set_plan_references(sp->plan, sp->rtable);
 	}
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index fe17b8ebb01..840ba975a34 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.60 2002/12/12 15:49:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.61 2002/12/14 00:17:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,8 +53,17 @@ int			PlannerPlanId = 0;	/* to assign unique ID to subquery plans */
  */
 
 
-static void convert_sublink_opers(SubLink *slink, List *targetlist,
-								  List **setParams);
+typedef struct finalize_primnode_results
+{
+	List	   *paramids;		/* List of PARAM_EXEC paramids found */
+} finalize_primnode_results;
+
+
+static List *convert_sublink_opers(List *operlist, List *lefthand,
+								   List *targetlist, List **setParams);
+static Node *replace_correlation_vars_mutator(Node *node, void *context);
+static Node *process_sublinks_mutator(Node *node, void *context);
+static bool finalize_primnode(Node *node, finalize_primnode_results *results);
 
 
 /*
@@ -144,29 +153,27 @@ generate_new_param(Oid paramtype, int32 paramtypmod)
 }
 
 /*
- * Convert a bare SubLink (as created by the parser) into a SubPlanExpr.
+ * Convert a bare SubLink (as created by the parser) into a SubPlan.
+ *
+ * We are given the raw SubLink and the already-processed lefthand argument
+ * list (use this instead of the SubLink's own field).
+ *
+ * The result is whatever we need to substitute in place of the SubLink
+ * node in the executable expression.  This will be either the SubPlan
+ * node (if we have to do the subplan as a subplan), or a Param node
+ * representing the result of an InitPlan, or possibly an AND or OR tree
+ * containing InitPlan Param nodes.
  */
 static Node *
-make_subplan(SubLink *slink)
+make_subplan(SubLink *slink, List *lefthand)
 {
-	SubPlanExpr *node = makeNode(SubPlanExpr);
+	SubPlan	   *node = makeNode(SubPlan);
 	Query	   *subquery = (Query *) (slink->subselect);
-	Oid			result_type = exprType((Node *) slink);
 	double		tuple_fraction;
 	Plan	   *plan;
 	List	   *lst;
 	Node	   *result;
 
-	/*
-	 * Check to see if this node was already processed; if so we have
-	 * trouble.  We check to see if the linked-to Query appears to have
-	 * been planned already, too.
-	 */
-	if (subquery == NULL)
-		elog(ERROR, "make_subplan: invalid expression structure (SubLink already processed?)");
-	if (subquery->base_rel_list != NIL)
-		elog(ERROR, "make_subplan: invalid expression structure (subquery already processed?)");
-
 	/*
 	 * Copy the source Query node.	This is a quick and dirty kluge to
 	 * resolve the fact that the parser can generate trees with multiple
@@ -210,14 +217,19 @@ make_subplan(SubLink *slink)
 	node->plan = plan = subquery_planner(subquery, tuple_fraction);
 
 	node->plan_id = PlannerPlanId++;	/* Assign unique ID to this
-										 * SubPlanExpr */
+										 * SubPlan */
 
 	node->rtable = subquery->rtable;
-	node->sublink = slink;
-
-	node->typeOid = result_type;
 
-	slink->subselect = NULL;	/* cool ?! see error check above! */
+	/*
+	 * Fill in other fields of the SubPlan node.
+	 */
+	node->subLinkType = slink->subLinkType;
+	node->useor = slink->useor;
+	node->oper = NIL;
+	node->setParam = NIL;
+	node->parParam = NIL;
+	node->args = NIL;
 
 	/*
 	 * Make parParam list of params that current query level will pass to
@@ -262,17 +274,23 @@ make_subplan(SubLink *slink)
 	}
 	else if (node->parParam == NIL && slink->subLinkType == MULTIEXPR_SUBLINK)
 	{
-		convert_sublink_opers(slink, plan->targetlist, &node->setParam);
+		List   *oper;
+
+		/* Convert the oper list, but don't put it into the SubPlan node */
+		oper = convert_sublink_opers(slink->oper,
+									 lefthand,
+									 plan->targetlist,
+									 &node->setParam);
 		PlannerInitPlan = lappend(PlannerInitPlan, node);
-		if (length(slink->oper) > 1)
-			result = (Node *) ((slink->useor) ? make_orclause(slink->oper) :
-							   make_andclause(slink->oper));
+		if (length(oper) > 1)
+			result = (Node *) (node->useor ? make_orclause(oper) :
+							   make_andclause(oper));
 		else
-			result = (Node *) lfirst(slink->oper);
+			result = (Node *) lfirst(oper);
 	}
 	else
 	{
-		List	   *args = NIL;
+		List	   *args;
 
 		/*
 		 * We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types
@@ -347,12 +365,16 @@ make_subplan(SubLink *slink)
 			}
 		}
 
-		/* Fix the SubLink's oper list */
-		convert_sublink_opers(slink, plan->targetlist, NULL);
+		/* Convert the SubLink's oper list into executable form */
+		node->oper = convert_sublink_opers(slink->oper,
+										   lefthand,
+										   plan->targetlist,
+										   NULL);
 
 		/*
 		 * Make node->args from parParam.
 		 */
+		args = NIL;
 		foreach(lst, node->parParam)
 		{
 			Var		   *var = nth(lfirsti(lst), PlannerParamVar);
@@ -379,27 +401,26 @@ make_subplan(SubLink *slink)
  * convert_sublink_opers: convert a SubLink's oper list from the
  * parser/rewriter format into the executor's format.
  *
- * The oper list is initially just a list of OpExpr nodes.  We replace it
- * with a list of actually executable expressions, in which the specified
- * operators are applied to corresponding elements of the lefthand list
- * and Params representing the results of the subplan.  lefthand is then
- * set to NIL.
+ * The oper list is initially a list of OpExpr nodes with NIL args.  We
+ * convert it to a list of actually executable expressions, in which the
+ * specified operators are applied to corresponding elements of the
+ * lefthand list and Params representing the results of the subplan.
  *
  * If setParams is not NULL, the paramids of the Params created are added
  * to the *setParams list.
  */
-static void
-convert_sublink_opers(SubLink *slink, List *targetlist,
-					  List **setParams)
+static List *
+convert_sublink_opers(List *operlist, List *lefthand,
+					  List *targetlist, List **setParams)
 {
 	List	   *newoper = NIL;
-	List	   *leftlist = slink->lefthand;
+	List	   *leftlist = lefthand;
 	List	   *lst;
 
-	foreach(lst, slink->oper)
+	foreach(lst, operlist)
 	{
 		OpExpr	   *oper = (OpExpr *) lfirst(lst);
-		Node	   *lefthand = lfirst(leftlist);
+		Node	   *leftop = lfirst(leftlist);
 		TargetEntry *te = lfirst(targetlist);
 		Param	   *prm;
 		Operator	tup;
@@ -430,7 +451,7 @@ convert_sublink_opers(SubLink *slink, List *targetlist,
 		 * Note: we use make_operand in case runtime type conversion
 		 * function calls must be inserted for this operator!
 		 */
-		left = make_operand(lefthand, exprType(lefthand), opform->oprleft);
+		left = make_operand(leftop, exprType(leftop), opform->oprleft);
 		right = make_operand((Node *) prm, prm->paramtype, opform->oprright);
 		newoper = lappend(newoper,
 						  make_opclause(oper->opno,
@@ -445,65 +466,12 @@ convert_sublink_opers(SubLink *slink, List *targetlist,
 		targetlist = lnext(targetlist);
 	}
 
-	slink->oper = newoper;
-	slink->lefthand = NIL;
-}
-
-/*
- * finalize_primnode: build lists of params appearing
- * in the given expression tree.  NOTE: items are added to list passed in,
- * so caller must initialize list to NIL before first call!
- */
-
-typedef struct finalize_primnode_results
-{
-	List	   *paramids;		/* List of PARAM_EXEC paramids found */
-} finalize_primnode_results;
-
-static bool
-finalize_primnode(Node *node, finalize_primnode_results *results)
-{
-	if (node == NULL)
-		return false;
-	if (IsA(node, Param))
-	{
-		if (((Param *) node)->paramkind == PARAM_EXEC)
-		{
-			int			paramid = (int) ((Param *) node)->paramid;
-
-			if (!intMember(paramid, results->paramids))
-				results->paramids = lconsi(paramid, results->paramids);
-		}
-		return false;			/* no more to do here */
-	}
-	if (is_subplan(node))
-	{
-		SubPlanExpr *subplan = (SubPlanExpr *) node;
-		List	   *lst;
-
-		/* Check extParam list for params to add to paramids */
-		foreach(lst, subplan->plan->extParam)
-		{
-			int			paramid = lfirsti(lst);
-			Var		   *var = nth(paramid, PlannerParamVar);
-
-			/* note varlevelsup is absolute level number */
-			if (var->varlevelsup < PlannerQueryLevel &&
-				!intMember(paramid, results->paramids))
-				results->paramids = lconsi(paramid, results->paramids);
-		}
-		/* fall through to recurse into subplan args */
-	}
-	return expression_tree_walker(node, finalize_primnode,
-								  (void *) results);
+	return newoper;
 }
 
 /*
  * Replace correlation vars (uplevel vars) with Params.
  */
-
-static Node *replace_correlation_vars_mutator(Node *node, void *context);
-
 Node *
 SS_replace_correlation_vars(Node *expr)
 {
@@ -529,9 +497,6 @@ replace_correlation_vars_mutator(Node *node, void *context)
 /*
  * Expand SubLinks to SubPlans in the given expression.
  */
-
-static Node *process_sublinks_mutator(Node *node, void *context);
-
 Node *
 SS_process_sublinks(Node *expr)
 {
@@ -547,20 +512,21 @@ process_sublinks_mutator(Node *node, void *context)
 	if (IsA(node, SubLink))
 	{
 		SubLink    *sublink = (SubLink *) node;
+		List	   *lefthand;
 
 		/*
-		 * First, scan the lefthand-side expressions, if any. This is a
-		 * tad klugy since we modify the input SubLink node, but that
-		 * should be OK (make_subplan does it too!)
+		 * First, recursively process the lefthand-side expressions, if any.
 		 */
-		sublink->lefthand = (List *)
+		lefthand = (List *)
 			process_sublinks_mutator((Node *) sublink->lefthand, context);
-		/* Now build the SubPlanExpr node and make the expr to return */
-		return make_subplan(sublink);
+		/*
+		 * Now build the SubPlan node and make the expr to return.
+		 */
+		return make_subplan(sublink, lefthand);
 	}
 
 	/*
-	 * Note that we will never see a SubPlanExpr expression in the input
+	 * Note that we will never see a SubPlan expression in the input
 	 * (since this is the very routine that creates 'em to begin with). So
 	 * the code in expression_tree_mutator() that might do inappropriate
 	 * things with SubPlans or SubLinks will not be exercised.
@@ -572,6 +538,12 @@ process_sublinks_mutator(Node *node, void *context)
 								   context);
 }
 
+/*
+ * SS_finalize_plan - do final sublink processing for a completed Plan.
+ *
+ * This recursively computes and sets the extParam and locParam lists
+ * for every Plan node in the given tree.
+ */
 List *
 SS_finalize_plan(Plan *plan, List *rtable)
 {
@@ -721,3 +693,46 @@ SS_finalize_plan(Plan *plan, List *rtable)
 
 	return results.paramids;
 }
+
+/*
+ * finalize_primnode: build lists of params appearing
+ * in the given expression tree.  NOTE: items are added to list passed in,
+ * so caller must initialize list to NIL before first call!
+ */
+static bool
+finalize_primnode(Node *node, finalize_primnode_results *results)
+{
+	if (node == NULL)
+		return false;
+	if (IsA(node, Param))
+	{
+		if (((Param *) node)->paramkind == PARAM_EXEC)
+		{
+			int			paramid = (int) ((Param *) node)->paramid;
+
+			if (!intMember(paramid, results->paramids))
+				results->paramids = lconsi(paramid, results->paramids);
+		}
+		return false;			/* no more to do here */
+	}
+	if (is_subplan(node))
+	{
+		SubPlan	   *subplan = (SubPlan *) node;
+		List	   *lst;
+
+		/* Check extParam list for params to add to paramids */
+		foreach(lst, subplan->plan->extParam)
+		{
+			int			paramid = lfirsti(lst);
+			Var		   *var = nth(paramid, PlannerParamVar);
+
+			/* note varlevelsup is absolute level number */
+			if (var->varlevelsup < PlannerQueryLevel &&
+				!intMember(paramid, results->paramids))
+				results->paramids = lconsi(paramid, results->paramids);
+		}
+		/* fall through to recurse into subplan args */
+	}
+	return expression_tree_walker(node, finalize_primnode,
+								  (void *) results);
+}
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index a55af2e2d06..5e44a64c012 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.82 2002/12/12 15:49:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.83 2002/12/14 00:17:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -872,13 +872,13 @@ adjust_inherited_attrs_mutator(Node *node,
 	 */
 	if (is_subplan(node))
 	{
-		SubPlanExpr *subplan;
+		SubPlan *subplan;
 
 		/* Copy the node and process subplan args */
 		node = expression_tree_mutator(node, adjust_inherited_attrs_mutator,
 									   (void *) context);
 		/* Make sure we have separate copies of subplan and its rtable */
-		subplan = (SubPlanExpr *) node;
+		subplan = (SubPlan *) node;
 		subplan->plan = copyObject(subplan->plan);
 		subplan->rtable = copyObject(subplan->rtable);
 		return node;
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index af96615c7fc..1d87afdc42f 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.118 2002/12/13 19:45:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.119 2002/12/14 00:17:59 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -486,7 +486,7 @@ expression_returns_set_walker(Node *node, void *context)
 		return false;
 	if (IsA(node, SubLink))
 		return false;
-	if (IsA(node, SubPlanExpr))
+	if (IsA(node, SubPlan))
 		return false;
 
 	return expression_tree_walker(node, expression_returns_set_walker,
@@ -519,7 +519,7 @@ contain_subplans_walker(Node *node, void *context)
 {
 	if (node == NULL)
 		return false;
-	if (IsA(node, SubPlanExpr) ||
+	if (IsA(node, SubPlan) ||
 		IsA(node, SubLink))
 		return true;			/* abort the tree traversal and return
 								 * true */
@@ -530,7 +530,7 @@ contain_subplans_walker(Node *node, void *context)
  * pull_subplans
  *	  Recursively pulls all subplans from an expression tree.
  *
- *	  Returns list of SubPlanExpr nodes found.  Note the nodes themselves
+ *	  Returns list of SubPlan nodes found.  Note the nodes themselves
  *	  are not copied, only referenced.
  */
 List *
@@ -656,7 +656,7 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
 		 */
 		List	   *t;
 
-		foreach(t, ((SubPlanExpr *) node)->args)
+		foreach(t, ((SubPlan *) node)->args)
 		{
 			Node	   *thisarg = lfirst(t);
 			Var		   *var;
@@ -1483,14 +1483,14 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
 				break;
 		}
 	}
-	if (IsA(node, SubPlanExpr))
+	if (IsA(node, SubPlan))
 	{
 		/*
-		 * Return a SubPlanExpr unchanged --- too late to do anything
+		 * Return a SubPlan unchanged --- too late to do anything
 		 * with it.
 		 *
 		 * XXX should we elog() here instead?  Probably this routine
-		 * should never be invoked after SubPlanExpr creation.
+		 * should never be invoked after SubPlan creation.
 		 */
 		return node;
 	}
@@ -2089,17 +2089,17 @@ substitute_actual_parameters_mutator(Node *node,
  * FromExpr, JoinExpr, and SetOperationStmt nodes are handled, so that query
  * jointrees and setOperation trees can be processed without additional code.
  *
- * expression_tree_walker will handle SubLink and SubPlanExpr nodes by
- * recursing normally into the "lefthand" arguments (which are expressions
- * belonging to the outer plan).  It will also call the walker on the
- * sub-Query node; however, when expression_tree_walker itself is called on a
- * Query node, it does nothing and returns "false".  The net effect is that
- * unless the walker does something special at a Query node, sub-selects will
- * not be visited during an expression tree walk. This is exactly the behavior
- * wanted in many cases --- and for those walkers that do want to recurse into
- * sub-selects, special behavior is typically needed anyway at the entry to a
- * sub-select (such as incrementing a depth counter). A walker that wants to
- * examine sub-selects should include code along the lines of:
+ * expression_tree_walker will handle SubLink nodes by recursing normally into
+ * the "lefthand" arguments (which are expressions belonging to the outer
+ * plan).  It will also call the walker on the sub-Query node; however, when
+ * expression_tree_walker itself is called on a Query node, it does nothing
+ * and returns "false".  The net effect is that unless the walker does
+ * something special at a Query node, sub-selects will not be visited during
+ * an expression tree walk. This is exactly the behavior wanted in many cases
+ * --- and for those walkers that do want to recurse into sub-selects, special
+ * behavior is typically needed anyway at the entry to a sub-select (such as
+ * incrementing a depth counter). A walker that wants to examine sub-selects
+ * should include code along the lines of:
  *
  *		if (IsA(node, Query))
  *		{
@@ -2113,10 +2113,12 @@ substitute_actual_parameters_mutator(Node *node,
  * query_tree_walker is a convenience routine (see below) that calls the
  * walker on all the expression subtrees of the given Query node.
  *
- * NOTE: currently, because make_subplan() clears the subselect link in
- * a SubLink node, it is not actually possible to recurse into subselects
- * of an already-planned expression tree.  This is OK for current uses,
- * but ought to be cleaned up when we redesign querytree processing.
+ * expression_tree_walker will handle SubPlan nodes by recursing normally
+ * into the "oper" and "args" lists (which are expressions belonging to the
+ * outer plan).  It will not touch the completed subplan, however.  Since
+ * there is no link to the original Query, it is not possible to recurse into
+ * subselects of an already-planned expression tree.  This is OK for current
+ * uses, but may need to be revisited in future.
  *--------------------
  */
 
@@ -2207,24 +2209,13 @@ expression_tree_walker(Node *node,
 				SubLink    *sublink = (SubLink *) node;
 
 				/*
-				 * If the SubLink has already been processed by
-				 * subselect.c, it will have lefthand=NIL, and we need to
-				 * scan the oper list.	Otherwise we only need to look at
-				 * the lefthand list (the incomplete OpExpr nodes in the
-				 * oper list are deemed uninteresting, perhaps even
-				 * confusing).
+				 * We only recurse into the lefthand list (the incomplete
+				 * OpExpr nodes in the oper list are deemed uninteresting,
+				 * perhaps even confusing).
 				 */
-				if (sublink->lefthand)
-				{
-					if (walker((Node *) sublink->lefthand, context))
-						return true;
-				}
-				else
-				{
-					if (walker((Node *) sublink->oper, context))
-						return true;
-				}
-
+				if (expression_tree_walker((Node *) sublink->lefthand,
+										   walker, context))
+					return true;
 				/*
 				 * Also invoke the walker on the sublink's Query node, so
 				 * it can recurse into the sub-query if it wants to.
@@ -2232,15 +2223,16 @@ expression_tree_walker(Node *node,
 				return walker(sublink->subselect, context);
 			}
 			break;
-		case T_SubPlanExpr:
+		case T_SubPlan:
 			{
-				SubPlanExpr *expr = (SubPlanExpr *) node;
+				SubPlan *subplan = (SubPlan *) node;
 
-				/* recurse to the SubLink node, but not into the Plan */
-				if (walker((Node *) expr->sublink, context))
+				/* recurse into the oper list, but not into the Plan */
+				if (expression_tree_walker((Node *) subplan->oper,
+										   walker, context))
 					return true;
 				/* also examine args list */
-				if (expression_tree_walker((Node *) expr->args,
+				if (expression_tree_walker((Node *) subplan->args,
 										   walker, context))
 					return true;
 			}
@@ -2442,18 +2434,17 @@ query_tree_walker(Query *query,
  * expression_tree_mutator include all those normally found in target lists
  * and qualifier clauses during the planning stage.
  *
- * expression_tree_mutator will handle a SubPlanExpr node by recursing into
- * the args and sublink->oper lists (which belong to the outer plan), but it
+ * expression_tree_mutator will handle a SubPlan node by recursing into
+ * the "oper" and "args" lists (which belong to the outer plan), but it
  * will simply copy the link to the inner plan, since that's typically what
  * expression tree mutators want.  A mutator that wants to modify the subplan
- * can force appropriate behavior by recognizing subplan expression nodes
+ * can force appropriate behavior by recognizing SubPlan expression nodes
  * and doing the right thing.
  *
- * Bare SubLink nodes (without a SubPlanExpr) are handled by recursing into
- * the "lefthand" argument list only.  (A bare SubLink should be seen only if
- * the tree has not yet been processed by subselect.c.)  Again, this can be
- * overridden by the mutator, but it seems to be the most useful default
- * behavior.
+ * SubLink nodes are handled by recursing into the "lefthand" argument list
+ * only.  (A SubLink will be seen only if the tree has not yet been
+ * processed by subselect.c.)  Again, this can be overridden by the mutator,
+ * but it seems to be the most useful default behavior.
  *--------------------
  */
 
@@ -2560,9 +2551,8 @@ expression_tree_mutator(Node *node,
 		case T_SubLink:
 			{
 				/*
-				 * A "bare" SubLink (note we will not come here if we
-				 * found a SubPlanExpr node above it).  Transform the
-				 * lefthand side, but not the oper list nor the subquery.
+				 * We transform the lefthand side, but not the oper list nor
+				 * the subquery.
 				 */
 				SubLink    *sublink = (SubLink *) node;
 				SubLink    *newnode;
@@ -2572,20 +2562,17 @@ expression_tree_mutator(Node *node,
 				return (Node *) newnode;
 			}
 			break;
-		case T_SubPlanExpr:
+		case T_SubPlan:
 			{
-				SubPlanExpr   *expr = (SubPlanExpr *) node;
-				SubLink		  *oldsublink = expr->sublink;
-				SubPlanExpr   *newnode;
+				SubPlan	   *subplan = (SubPlan *) node;
+				SubPlan	   *newnode;
 
-				FLATCOPY(newnode, expr, SubPlanExpr);
-				/* flat-copy the SubLink node */
-				CHECKFLATCOPY(newnode->sublink, oldsublink, SubLink);
+				FLATCOPY(newnode, subplan, SubPlan);
 				/* transform args list (params to be passed to subplan) */
-				MUTATE(newnode->args, expr->args, List *);
-				/* transform sublink's oper list as well */
-				MUTATE(newnode->sublink->oper, oldsublink->oper, List *);
-				/* but not the subplan itself, which is referenced as-is */
+				MUTATE(newnode->args, subplan->args, List *);
+				/* transform oper list as well */
+				MUTATE(newnode->oper, subplan->oper, List *);
+				/* but not the sub-Plan itself, which is referenced as-is */
 				return (Node *) newnode;
 			}
 			break;
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index 8d22aa26b91..e4868af11cd 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.41 2002/12/12 15:49:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.42 2002/12/14 00:17:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,7 +65,7 @@ static Node *flatten_join_alias_vars_mutator(Node *node,
  * NOTE: this is used on not-yet-planned expressions.  It may therefore find
  * bare SubLinks, and if so it needs to recurse into them to look for uplevel
  * references to the desired rtable level!	But when we find a completed
- * SubPlanExpr, we only need to look at the parameters passed to the subplan.
+ * SubPlan, we only need to look at the parameters passed to the subplan.
  */
 List *
 pull_varnos(Node *node)
@@ -111,9 +111,9 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
 		 * executed by the outer query.  But short-circuit recursion into
 		 * the subquery itself, which would be a waste of effort.
 		 */
-		SubPlanExpr *subplan = (SubPlanExpr *) node;
+		SubPlan *subplan = (SubPlan *) node;
 
-		if (pull_varnos_walker((Node *) subplan->sublink->oper,
+		if (pull_varnos_walker((Node *) subplan->oper,
 							   context))
 			return true;
 		if (pull_varnos_walker((Node *) subplan->args,
@@ -146,7 +146,7 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
  * NOTE: this is used on not-yet-planned expressions.  It may therefore find
  * bare SubLinks, and if so it needs to recurse into them to look for uplevel
  * references to the desired rtable entry!	But when we find a completed
- * SubPlanExpr, we only need to look at the parameters passed to the subplan.
+ * SubPlan, we only need to look at the parameters passed to the subplan.
  */
 bool
 contain_var_reference(Node *node, int varno, int varattno, int levelsup)
@@ -194,9 +194,9 @@ contain_var_reference_walker(Node *node,
 		 * executed by the outer query.  But short-circuit recursion into
 		 * the subquery itself, which would be a waste of effort.
 		 */
-		SubPlanExpr *subplan = (SubPlanExpr *) node;
+		SubPlan *subplan = (SubPlan *) node;
 
-		if (contain_var_reference_walker((Node *) subplan->sublink->oper,
+		if (contain_var_reference_walker((Node *) subplan->oper,
 										 context))
 			return true;
 		if (contain_var_reference_walker((Node *) subplan->args,
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 92f69a32a82..2fecab9655c 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
  *				back to source text
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.128 2002/12/12 15:49:40 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.129 2002/12/14 00:17:59 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -2099,7 +2099,7 @@ get_rule_expr(Node *node, deparse_context *context,
 			get_sublink_expr((SubLink *) node, context);
 			break;
 
-		case T_SubPlanExpr:
+		case T_SubPlan:
 			{
 				/*
 				 * We cannot see an already-planned subplan in
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index bdcb3a6afa5..9b7af6d36fb 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: executor.h,v 1.82 2002/12/13 19:45:56 tgl Exp $
+ * $Id: executor.h,v 1.83 2002/12/14 00:17:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -92,8 +92,7 @@ extern Datum ExecEvalExpr(ExprState *expression, ExprContext *econtext,
 extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext,
 						  bool *isNull, ExprDoneCond *isDone);
 extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
-extern SubPlanExprState *ExecInitExprInitPlan(SubPlanExpr *node,
-											  PlanState *parent);
+extern SubPlanState *ExecInitExprInitPlan(SubPlan *node, PlanState *parent);
 extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
 extern int	ExecTargetListLength(List *targetlist);
 extern int	ExecCleanTargetListLength(List *targetlist);
diff --git a/src/include/executor/nodeSubplan.h b/src/include/executor/nodeSubplan.h
index 97f4b66bcd6..8a3e74ebd1c 100644
--- a/src/include/executor/nodeSubplan.h
+++ b/src/include/executor/nodeSubplan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodeSubplan.h,v 1.14 2002/12/13 19:45:56 tgl Exp $
+ * $Id: nodeSubplan.h,v 1.15 2002/12/14 00:17:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,13 +16,13 @@
 
 #include "nodes/execnodes.h"
 
-extern void ExecInitSubPlan(SubPlanExprState *sstate, EState *estate);
-extern Datum ExecSubPlan(SubPlanExprState *node,
+extern void ExecInitSubPlan(SubPlanState *node, EState *estate);
+extern Datum ExecSubPlan(SubPlanState *node,
 						 ExprContext *econtext,
 						 bool *isNull);
-extern void ExecEndSubPlan(SubPlanExprState *node);
-extern void ExecReScanSetParamPlan(SubPlanExprState *node, PlanState *parent);
+extern void ExecEndSubPlan(SubPlanState *node);
+extern void ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent);
 
-extern void ExecSetParamPlan(SubPlanExprState *node, ExprContext *econtext);
+extern void ExecSetParamPlan(SubPlanState *node, ExprContext *econtext);
 
 #endif   /* NODESUBPLAN_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 905bfae6d87..f8e1f7cc4c9 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.84 2002/12/13 19:45:57 tgl Exp $
+ * $Id: execnodes.h,v 1.85 2002/12/14 00:17:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -451,21 +451,18 @@ typedef struct BoolExprState
 } BoolExprState;
 
 /* ----------------
- *		SubPlanExprState node
- *
- * Note: there is no separate ExprState node for the SubLink.  All it would
- * need is the oper field, which we can just as easily put here.
+ *		SubPlanState node
  * ----------------
  */
-typedef struct SubPlanExprState
+typedef struct SubPlanState
 {
 	ExprState	xprstate;
 	struct PlanState *planstate; /* subselect plan's state tree */
 	bool		needShutdown;	/* TRUE = need to shutdown subplan */
 	HeapTuple	curTuple;		/* copy of most recent tuple from subplan */
-	List	   *args;			/* states of argument expression(s) */
 	List	   *oper;			/* states for executable combining exprs */
-} SubPlanExprState;
+	List	   *args;			/* states of argument expression(s) */
+} SubPlanState;
 
 /* ----------------
  *		CaseExprState node
@@ -538,9 +535,9 @@ typedef struct PlanState
 	List	   *qual;			/* implicitly-ANDed qual conditions */
 	struct PlanState *lefttree;	/* input plan tree(s) */
 	struct PlanState *righttree;
-	List	   *initPlan;		/* Init SubPlanExprState nodes (un-correlated
+	List	   *initPlan;		/* Init SubPlanState nodes (un-correlated
 								 * expr subselects) */
-	List	   *subPlan;		/* SubPlanExprState nodes in my expressions */
+	List	   *subPlan;		/* SubPlanState nodes in my expressions */
 
 	/*
 	 * State for management of parameter-change-driven rescanning
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index cc550131852..5f628168738 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.132 2002/12/13 19:46:00 tgl Exp $
+ * $Id: nodes.h,v 1.133 2002/12/14 00:17:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -107,7 +107,7 @@ typedef enum NodeTag
 	T_DistinctExpr,
 	T_BoolExpr,
 	T_SubLink,
-	T_SubPlanExpr,
+	T_SubPlan,
 	T_FieldSelect,
 	T_RelabelType,
 	T_CaseExpr,
@@ -133,7 +133,7 @@ typedef enum NodeTag
 	T_ArrayRefExprState,
 	T_FuncExprState,
 	T_BoolExprState,
-	T_SubPlanExprState,
+	T_SubPlanState,
 	T_CaseExprState,
 	T_CaseWhenState,
 	T_ConstraintTestState,
diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h
index c8bc2857ed8..8d7aa3ab32b 100644
--- a/src/include/nodes/params.h
+++ b/src/include/nodes/params.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: params.h,v 1.20 2002/12/13 19:46:00 tgl Exp $
+ * $Id: params.h,v 1.21 2002/12/14 00:17:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,7 +88,7 @@ typedef ParamListInfoData *ParamListInfo;
  *	  array of ParamExecData records, which is referenced through
  *	  es_param_exec_vals or ecxt_param_exec_vals.
  *
- *	  If execPlan is not NULL, it points to a SubPlanExprState node that needs
+ *	  If execPlan is not NULL, it points to a SubPlanState node that needs
  *	  to be executed to produce the value.  (This is done so that we can have
  *	  lazy evaluation of InitPlans: they aren't executed until/unless a
  *	  result value is needed.)  Otherwise the value is assumed to be valid
@@ -98,7 +98,7 @@ typedef ParamListInfoData *ParamListInfo;
 
 typedef struct ParamExecData
 {
-	void	   *execPlan;		/* should be "SubPlanExprState *" */
+	void	   *execPlan;		/* should be "SubPlanState *" */
 	Datum		value;
 	bool		isnull;
 } ParamExecData;
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 01a6dbf8d64..285a0008fdc 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: primnodes.h,v 1.74 2002/12/13 19:46:00 tgl Exp $
+ * $Id: primnodes.h,v 1.75 2002/12/14 00:17:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -378,32 +378,21 @@ typedef struct BoolExpr
  * using AND and OR semantics respectively.
  *
  * SubLink is classed as an Expr node, but it is not actually executable;
- * it must be replaced in the expression tree by a SubPlanExpr node during
+ * it must be replaced in the expression tree by a SubPlan node during
  * planning.
  *
- * NOTE: lefthand and oper have varying meanings depending on where you look
- * in the parse/plan pipeline:
- * 1. gram.y delivers a list of the (untransformed) lefthand expressions in
- *	  lefthand, and sets oper to a single A_Expr (not a list!) containing
- *	  the string name of the operator, but no arguments.
- * 2. The parser's expression transformation transforms lefthand normally,
- *	  and replaces oper with a list of OpExpr nodes, one per lefthand
- *	  expression.  These nodes represent the parser's resolution of exactly
- *	  which operator to apply to each pair of lefthand and targetlist
- *	  expressions.	However, we have not constructed complete Expr trees for
- *	  these operations yet: the args fields of the OpExpr nodes are NIL.
- *	  This is the representation seen in saved rules and in the rewriter.
- * 3. Finally, the planner converts the oper list to a list of normal OpExpr
- *	  nodes representing the application of the operator(s) to the lefthand
- *	  expressions and values from the inner targetlist.  The inner
- *	  targetlist items are represented by placeholder Param nodes.
- *	  The lefthand field is set to NIL, since its expressions are now in
- *	  the Expr list.  This representation is passed to the executor.
- *
- * Planner routines that might see either representation 2 or 3 can tell
- * the difference by checking whether lefthand is NIL or not.  Also,
- * representation 2 appears in a "bare" SubLink, while representation 3 is
- * found in SubLinks that are children of SubPlanExpr nodes.
+ * NOTE: in the raw output of gram.y, lefthand contains a list of (raw)
+ * expressions, and oper contains a single A_Expr (not a list!) containing
+ * the string name of the operator, but no arguments.  Also, subselect is
+ * a raw parsetree.  During parse analysis, the parser transforms the
+ * lefthand expression list using normal expression transformation rules.
+ * It replaces oper with a list of OpExpr nodes, one per lefthand expression.
+ * These nodes represent the parser's resolution of exactly which operator
+ * to apply to each pair of lefthand and targetlist expressions.  However,
+ * we have not constructed complete Expr trees for these operations yet:
+ * the args fields of the OpExpr nodes are NIL.  And subselect is transformed
+ * to a Query.  This is the representation seen in saved rules and in the
+ * rewriter.
  *
  * In EXISTS and EXPR SubLinks, both lefthand and oper are unused and are
  * always NIL.	useor is not significant either for these sublink types.
@@ -423,37 +412,58 @@ typedef struct SubLink
 								 * "OR" not "AND" */
 	List	   *lefthand;		/* list of outer-query expressions on the
 								 * left */
-	List	   *oper;			/* list of OpExpr nodes for combining
-								 * operators, or final list of executable
-								 * expressions */
+	List	   *oper;			/* list of arg-less OpExpr nodes for
+								 * combining operators */
 	Node	   *subselect;		/* subselect as Query* or parsetree */
 } SubLink;
 
 /*
- * SubPlanExpr - executable expression node for a subplan (sub-SELECT)
- *
- * The planner replaces SubLink nodes in expression trees with SubPlanExpr
- * nodes after it has finished planning the subquery.  See notes above.
- */
-typedef struct SubPlanExpr
+ * 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.  Its "oper" field
+ * corresponds to the original SubLink's oper list, but has been expanded
+ * into valid executable expressions representing the application of the
+ * combining operator(s) to the lefthand expressions and values from the
+ * inner targetlist.  The original lefthand expressions now appear as
+ * left-hand arguments of the OpExpr nodes, while the inner targetlist items
+ * are represented by PARAM_EXEC Param nodes.  (Note: if the sub-select
+ * becomes an InitPlan rather than a SubPlan, the rebuilt oper list is
+ * part of the outer plan tree and so is not stored in the oper field.)
+ *
+ * The planner also derives lists of the values that need to be passed into
+ * and out of the subplan.  Input values are represented as a list "args" of
+ * expressions to be evaluated in the outer-query context (currently these
+ * args are always just Vars, but in principle they could be any expression).
+ * The values are assigned to the global PARAM_EXEC params indexed by parParam
+ * (the parParam and args lists must have the same length).  setParam is a
+ * list of the PARAM_EXEC params that are computed by the sub-select, if it
+ * is an initPlan.
+ */
+typedef struct SubPlan
 {
 	Expr		xpr;
-	Oid			typeOid;		/* PG_TYPE OID of the expression result */
+	/* Fields copied from original SubLink: */
+	SubLinkType subLinkType;	/* EXISTS, ALL, ANY, MULTIEXPR, EXPR */
+	bool		useor;			/* TRUE to combine column results with
+								 * "OR" not "AND" */
+	List	   *oper;			/* list of executable expressions for
+								 * combining operators (with arguments) */
+	/* The subselect, transformed to a Plan: */
 	struct Plan *plan;			/* subselect plan itself */
 	int			plan_id;		/* dummy thing because of we haven't equal
 								 * funcs for plan nodes... actually, we
 								 * could put *plan itself somewhere else
 								 * (TopPlan node ?)... */
 	List	   *rtable;			/* range table for subselect */
+	/* Information for passing params into and out of the subselect: */
 	/* setParam and parParam are lists of integers (param IDs) */
 	List	   *setParam;		/* non-correlated EXPR & EXISTS subqueries
 								 * have to set some Params for paren Plan */
 	List	   *parParam;		/* indices of input Params from parent plan */
 	List	   *args;			/* exprs to pass as parParam values */
-	SubLink    *sublink;		/* SubLink node from parser; holds info
-								 * about what to do with subselect's
-								 * results */
-} SubPlanExpr;
+} SubPlan;
 
 /* ----------------
  * FieldSelect
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 8da7a8688ef..f280e420d9b 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: clauses.h,v 1.57 2002/12/12 15:49:41 tgl Exp $
+ * $Id: clauses.h,v 1.58 2002/12/14 00:17:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,7 +20,7 @@
 
 #define is_opclause(clause)		((clause) != NULL && IsA(clause, OpExpr))
 #define is_funcclause(clause)	((clause) != NULL && IsA(clause, FuncExpr))
-#define is_subplan(clause)		((clause) != NULL && IsA(clause, SubPlanExpr))
+#define is_subplan(clause)		((clause) != NULL && IsA(clause, SubPlan))
 
 
 extern Expr *make_opclause(Oid opno, Oid opresulttype, bool opretset,
-- 
GitLab