diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index bd837da31ac278e36e7dcdd54a41da70ebcad0db..bcc92bfab0f779fd5fdf835f2e3445841a3a3c87 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.17 2002/12/06 05:00:10 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.18 2002/12/12 15:49:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -806,25 +806,28 @@ find_expr_references_walker(Node *node,
 		}
 		return false;
 	}
-	if (IsA(node, Expr))
+	if (IsA(node, FuncExpr))
 	{
-		Expr	   *expr = (Expr *) node;
+		FuncExpr   *funcexpr = (FuncExpr *) node;
 
-		if (expr->opType == OP_EXPR ||
-			expr->opType == DISTINCT_EXPR)
-		{
-			Oper	   *oper = (Oper *) expr->oper;
+		add_object_address(OCLASS_PROC, funcexpr->funcid, 0,
+						   &context->addrs);
+		/* fall through to examine arguments */
+	}
+	if (IsA(node, OpExpr))
+	{
+		OpExpr   *opexpr = (OpExpr *) node;
 
-			add_object_address(OCLASS_OPERATOR, oper->opno, 0,
-							   &context->addrs);
-		}
-		else if (expr->opType == FUNC_EXPR)
-		{
-			Func	   *func = (Func *) expr->oper;
+		add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
+						   &context->addrs);
+		/* fall through to examine arguments */
+	}
+	if (IsA(node, DistinctExpr))
+	{
+		DistinctExpr   *distinctexpr = (DistinctExpr *) node;
 
-			add_object_address(OCLASS_PROC, func->funcid, 0,
-							   &context->addrs);
-		}
+		add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
+						   &context->addrs);
 		/* fall through to examine arguments */
 	}
 	if (IsA(node, Aggref))
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index f8f667e24a9d8f01f4c89b27ca86b66aba61cb09..bd068271acdcc7d9cafa06e97f9d764bda523d68 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.235 2002/11/15 02:50:05 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.236 2002/12/12 15:49:23 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1602,11 +1602,6 @@ AddRelationRawConstraints(Relation rel,
 		 */
 		expr = (Node *) make_ands_implicit((Expr *) expr);
 
-		/*
-		 * Must fix opids in operator clauses.
-		 */
-		fix_opids(expr);
-
 		/*
 		 * OK, store it.
 		 */
@@ -1750,11 +1745,6 @@ cookDefault(ParseState *pstate,
 	 */
 	expr = eval_const_expressions(expr);
 
-	/*
-	 * Must fix opids, in case any operators remain...
-	 */
-	fix_opids(expr);
-
 	return (expr);
 }
 
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index cdac597ae5fde2866d4782741f9821630f86b2fa..c11bd5b172bb82da21c31510ab205973f7b6a454 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.205 2002/11/13 00:39:46 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.206 2002/12/12 15:49:24 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -41,6 +41,7 @@
 #include "executor/executor.h"
 #include "miscadmin.h"
 #include "optimizer/clauses.h"
+#include "optimizer/planmain.h"
 #include "optimizer/prep.h"
 #include "parser/parse_func.h"
 #include "storage/sinval.h"
@@ -919,6 +920,7 @@ BuildIndexInfo(Form_pg_index indexStruct)
 		predString = DatumGetCString(DirectFunctionCall1(textout,
 								PointerGetDatum(&indexStruct->indpred)));
 		ii->ii_Predicate = stringToNode(predString);
+		fix_opfuncids((Node *) ii->ii_Predicate);
 		pfree(predString);
 	}
 	else
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index b915a02c310ac4b619fccce47ce87e98b97037d5..14f37344b4d65e7e787e418163c8431c47340edc 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.94 2002/09/18 21:35:20 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.95 2002/12/12 15:49:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -424,7 +424,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
 			} while (attr->attisdropped);
 			rellogcols++;
 
-			tletype = exprType(tle->expr);
+			tletype = exprType((Node *) tle->expr);
 			atttype = attr->atttypid;
 			if (!IsBinaryCoercible(tletype, atttype))
 				elog(ERROR, "function declared to return %s returns %s instead of %s at column %d",
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 45749ab673ab65f6ba789eb4fc73609e3c795a11..41586331af07faebea0517dc3d9109c8aef475a9 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.184 2002/12/01 18:14:22 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.185 2002/12/12 15:49:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,6 +35,7 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/planmain.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_relation.h"
 #include "rewrite/rewriteHandler.h"
@@ -839,6 +840,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 			defexprs[num_defaults] = build_column_default(rel, i + 1);
 			if (defexprs[num_defaults] != NULL)
 			{
+				fix_opfuncids(defexprs[num_defaults]);
 				defmap[num_defaults] = i;
 				num_defaults++;
 			}
@@ -869,6 +871,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 			/* check whether any constraints actually found */
 			if (node != (Node *) prm)
 			{
+				fix_opfuncids(node);
 				constraintexprs[i] = node;
 				hasConstraints = true;
 			}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 0b5efaa319e732c3501e981b8fd4faffa3445e96..c587765bd5af0d236bf8a65d0c30dce854016009 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.95 2002/12/06 19:28:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.96 2002/12/12 15:49:24 tgl Exp $
  *
  */
 
@@ -417,20 +417,27 @@ explain_outNode(StringInfo str,
 			{
 				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
 											  es->rtable);
-				Expr	   *expr;
-				Func	   *funcnode;
-				Oid			funcid;
 				char	   *proname;
 
 				/* Assert it's on a RangeFunction */
 				Assert(rte->rtekind == RTE_FUNCTION);
 
-				expr = (Expr *) rte->funcexpr;
-				funcnode = (Func *) expr->oper;
-				funcid = funcnode->funcid;
-
-				/* We only show the func name, not schema name */
-				proname = get_func_name(funcid);
+				/*
+				 * If the expression is still a function call, we can get
+				 * the real name of the function.  Otherwise, punt (this
+				 * can happen if the optimizer simplified away the function
+				 * call, for example).
+				 */
+				if (rte->funcexpr && IsA(rte->funcexpr, FuncExpr))
+				{
+					FuncExpr   *funcexpr = (FuncExpr *) rte->funcexpr;
+					Oid			funcid = funcexpr->funcid;
+
+					/* We only show the func name, not schema name */
+					proname = get_func_name(funcid);
+				}
+				else
+					proname = rte->eref->aliasname;
 
 				appendStringInfo(str, " on %s",
 								 quote_identifier(proname));
@@ -583,7 +590,7 @@ explain_outNode(StringInfo str,
 		appendStringInfo(str, "  InitPlan\n");
 		foreach(lst, plan->initPlan)
 		{
-			SubPlan	   *subplan = (SubPlan *) lfirst(lst);
+			SubPlanExpr  *subplan = (SubPlanExpr *) lfirst(lst);
 			SubPlanState *subplanstate = (SubPlanState *) lfirst(pslist);
 
 			es->rtable = subplan->rtable;
@@ -683,7 +690,7 @@ explain_outNode(StringInfo str,
 		foreach(lst, planstate->subPlan)
 		{
 			SubPlanState *sps = (SubPlanState *) lfirst(lst);
-			SubPlan *sp = (SubPlan *) sps->ps.plan;
+			SubPlanExpr *sp = (SubPlanExpr *) sps->ps.plan;
 
 			es->rtable = sp->rtable;
 			for (i = 0; i < indent; i++)
@@ -870,7 +877,7 @@ show_sort_keys(List *tlist, int nkeys, const char *qlabel,
 			if (target->resdom->reskey == keyno)
 			{
 				/* Deparse the expression, showing any top-level cast */
-				exprstr = deparse_expression(target->expr, context,
+				exprstr = deparse_expression((Node *) target->expr, context,
 											 useprefix, true);
 				/* And add to str */
 				if (keyno > 1)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 5447780b69e2f8e0f8b56b5ed78cff4b1394019e..d6ccdb926131daaf468fafd4c9ede6a67891aee1 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.92 2002/10/21 22:06:19 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.93 2002/12/12 15:49:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -159,10 +159,10 @@ DefineIndex(RangeVar *heapRelation,
 	 * While we are at it, we reduce it to a canonical (CNF or DNF) form
 	 * to simplify the task of proving implications.
 	 */
-	if (predicate != NULL && rangetable != NIL)
+	if (predicate)
 	{
 		cnfPred = canonicalize_qual((Expr *) copyObject(predicate), true);
-		fix_opids((Node *) cnfPred);
+		fix_opfuncids((Node *) cnfPred);
 		CheckPredicate(cnfPred, rangetable, relationId);
 	}
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 8da1de580fb8516320a9f8b4fa6b3aedc4536d90..19687737337c897dc539b28345c60f61ed0b89f0 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.57 2002/11/23 18:26:45 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.58 2002/12/12 15:49:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2723,7 +2723,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
 	/*
 	 * We need to make a parse state and range
 	 * table to allow us to transformExpr and
-	 * fix_opids to get a version of the
+	 * fix_opfuncids to get a version of the
 	 * expression we can pass to ExecQual
 	 */
 	pstate = make_parsestate(NULL);
@@ -2764,8 +2764,8 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
 	 */
 	expr = eval_const_expressions(expr);
 
-	/* And fix the opids */
-	fix_opids(expr);
+	/* And fix the opfuncids */
+	fix_opfuncids(expr);
 
 	qual = makeList1(expr);
 
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d5260ad119074c89ef20ad6309652041499065fd..e16942acd72d43b9df817b128dbae4d46b677b55 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.21 2002/12/09 20:31:05 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.22 2002/12/12 15:49:24 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -1341,7 +1341,9 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
 	 * the constraint is being added to.
 	 */
 	expr = stringToNode(ccbin);
+	fix_opfuncids(expr);
 	rels = get_rels_with_domain(domainoid);
+
 	foreach (rt, rels)
 	{
 		Relation	typrel;
@@ -1522,7 +1524,7 @@ domainPermissionCheck(HeapTuple tup, TypeName *typename)
 
 
 /*
- *
+ * domainAddConstraint
  */
 char *
 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
@@ -1601,21 +1603,20 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
 	expr = eval_const_expressions(expr);
 
 	/*
-	 * Must fix opids in operator clauses.
+	 * Convert to string form for storage.
 	 */
-	fix_opids(expr);
-
 	ccbin = nodeToString(expr);
 
 	/*
-	 * Deparse it.  Since VARNOs aren't allowed in domain
-	 * constraints, relation context isn't required as anything
-	 * other than a shell.
+	 * Deparse it to produce text for consrc.
+	 *
+	 * Since VARNOs aren't allowed in domain constraints, relation context
+	 * isn't required as anything other than a shell.
 	 */
 	ccsrc = deparse_expression(expr,
-				deparse_context_for(domainName,
-									InvalidOid),
-								   false, false);
+							   deparse_context_for(domainName,
+												   InvalidOid),
+							   false, false);
 
 	/* Write the constraint */
 	CreateConstraintEntry(constr->name,		/* Constraint Name */
diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c
index 761ff403dd81dee564ea741c7202aa6e746fd32a..edaf7aa40cd511c0ae12586b124559742533a249 100644
--- a/src/backend/executor/execJunk.c
+++ b/src/backend/executor/execJunk.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.32 2002/09/04 20:31:17 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.33 2002/12/12 15:49:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -77,7 +77,7 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType,
 	bool		resjunk;
 	AttrNumber	cleanResno;
 	AttrNumber *cleanMap;
-	Node	   *expr;
+	Expr	   *expr;
 
 	/*
 	 * Make a memory context that will hold the JunkFilter as well as all
@@ -104,65 +104,23 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType,
 	{
 		TargetEntry *rtarget = lfirst(t);
 
-		if (rtarget->resdom != NULL)
-		{
-			resdom = rtarget->resdom;
-			expr = rtarget->expr;
-			resjunk = resdom->resjunk;
-			if (!resjunk)
-			{
-				/*
-				 * make a copy of the resdom node, changing its resno.
-				 */
-				cleanResdom = (Resdom *) copyObject(resdom);
-				cleanResdom->resno = cleanResno;
-				cleanResno++;
-
-				/*
-				 * create a new target list entry
-				 */
-				tle = makeTargetEntry(cleanResdom, expr);
-				cleanTargetList = lappend(cleanTargetList, tle);
-			}
-		}
-		else
+		resdom = rtarget->resdom;
+		expr = rtarget->expr;
+		resjunk = resdom->resjunk;
+		if (!resjunk)
 		{
-#ifdef SETS_FIXED
-			List	   *fjListP;
-			Fjoin	   *cleanFjoin;
-			List	   *cleanFjList;
-			List	   *fjList = lfirst(t);
-			Fjoin	   *fjNode = (Fjoin *) tl_node(fjList);
-
-			cleanFjoin = (Fjoin) copyObject((Node) fjNode);
-			cleanFjList = makeList1(cleanFjoin);
-
-			resdom = (Resdom) lfirst(get_fj_innerNode(fjNode));
-			expr = lsecond(get_fj_innerNode(fjNode));
-			cleanResdom = (Resdom) copyObject((Node) resdom);
-			set_resno(cleanResdom, cleanResno);
+			/*
+			 * make a copy of the resdom node, changing its resno.
+			 */
+			cleanResdom = (Resdom *) copyObject(resdom);
+			cleanResdom->resno = cleanResno;
 			cleanResno++;
-			tle = (List) makeTargetEntry(cleanResdom, (Node *) expr);
-			set_fj_innerNode(cleanFjoin, tle);
-
-			foreach(fjListP, lnext(fjList))
-			{
-				TargetEntry *tle = lfirst(fjListP);
 
-				resdom = tle->resdom;
-				expr = tle->expr;
-				cleanResdom = (Resdom *) copyObject((Node) resdom);
-				cleanResno++;
-				cleanResdom->Resno = cleanResno;
-
-				/*
-				 * create a new target list entry
-				 */
-				tle = (List) makeTargetEntry(cleanResdom, (Node *) expr);
-				cleanFjList = lappend(cleanFjList, tle);
-			}
-			lappend(cleanTargetList, cleanFjList);
-#endif
+			/*
+			 * create a new target list entry
+			 */
+			tle = makeTargetEntry(cleanResdom, expr);
+			cleanTargetList = lappend(cleanTargetList, tle);
 		}
 	}
 
@@ -192,41 +150,12 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType,
 		{
 			TargetEntry *tle = lfirst(t);
 
-			if (tle->resdom != NULL)
-			{
-				resdom = tle->resdom;
-				expr = tle->expr;
-				resjunk = resdom->resjunk;
-				if (!resjunk)
-				{
-					cleanMap[cleanResno - 1] = resdom->resno;
-					cleanResno++;
-				}
-			}
-			else
+			resdom = tle->resdom;
+			resjunk = resdom->resjunk;
+			if (!resjunk)
 			{
-#ifdef SETS_FIXED
-				List		fjListP;
-				List		fjList = lfirst(t);
-				Fjoin		fjNode = (Fjoin) lfirst(fjList);
-
-				/* what the hell is this????? */
-				resdom = (Resdom) lfirst(get_fj_innerNode(fjNode));
-#endif
-
-				cleanMap[cleanResno - 1] = tle->resdom->resno;
+				cleanMap[cleanResno - 1] = resdom->resno;
 				cleanResno++;
-
-#ifdef SETS_FIXED
-				foreach(fjListP, lnext(fjList))
-				{
-					TargetEntry *tle = lfirst(fjListP);
-
-					resdom = tle->resdom;
-					cleanMap[cleanResno - 1] = resdom->resno;
-					cleanResno++;
-				}
-#endif
 			}
 		}
 	}
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 15d47df669f38c7096fa8cc3ee15603f21555fb3..abd099c08c08a4ce966446ae039d87d938184df9 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.190 2002/12/05 15:50:30 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.191 2002/12/12 15:49:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,6 +40,7 @@
 #include "executor/execdebug.h"
 #include "executor/execdefs.h"
 #include "miscadmin.h"
+#include "optimizer/planmain.h"
 #include "optimizer/var.h"
 #include "parser/parsetree.h"
 #include "utils/acl.h"
@@ -1541,6 +1542,7 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
 		for (i = 0; i < ncheck; i++)
 		{
 			qual = (List *) stringToNode(check[i].ccbin);
+			fix_opfuncids((Node *) qual);
 			resultRelInfo->ri_ConstraintExprs[i] = qual;
 		}
 		MemoryContextSwitchTo(oldContext);
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 2db4a146bc16cefb8ff3e58eba817b2bc9c0a60b..680a6da609baff0c63fe127deb841356e5aedf11 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.31 2002/12/05 15:50:31 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.32 2002/12/12 15:49:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -228,9 +228,9 @@ ExecInitNode(Plan *node, EState *estate)
 	subps = NIL;
 	foreach(subp, node->initPlan)
 	{
-		SubPlan	   *subplan = (SubPlan *) lfirst(subp);
+		SubPlanExpr *subplan = (SubPlanExpr *) lfirst(subp);
 
-		Assert(IsA(subplan, SubPlan));
+		Assert(IsA(subplan, SubPlanExpr));
 		subps = lappend(subps, ExecInitSubPlan(subplan, estate));
 	}
 	result->initPlan = subps;
@@ -242,9 +242,9 @@ ExecInitNode(Plan *node, EState *estate)
 	subps = NIL;
 	foreach(subp, result->subPlan)
 	{
-		SubPlan	   *subplan = (SubPlan *) lfirst(subp);
+		SubPlanExpr *subplan = (SubPlanExpr *) lfirst(subp);
 
-		Assert(IsA(subplan, SubPlan));
+		Assert(IsA(subplan, SubPlanExpr));
 		subps = lappend(subps, ExecInitSubPlan(subplan, estate));
 	}
 	result->subPlan = subps;
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 2392981a5ec3746ef2901a949f8d58e9e5f12607..d96e983fa30ab6eae2a7aec79d126f17b0b285e5 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.116 2002/12/06 05:00:16 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.117 2002/12/12 15:49:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,17 +53,20 @@ static Datum ExecEvalAggref(Aggref *aggref, ExprContext *econtext,
 static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext,
 				 bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);
-static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext,
+static Datum ExecEvalOper(OpExpr *op, ExprContext *econtext,
 			 bool *isNull, ExprDoneCond *isDone);
-static Datum ExecEvalDistinct(Expr *opClause, ExprContext *econtext,
+static Datum ExecEvalDistinct(DistinctExpr *op, ExprContext *econtext,
 				 bool *isNull, ExprDoneCond *isDone);
-static Datum ExecEvalFunc(Expr *funcClause, ExprContext *econtext,
+static Datum ExecEvalFunc(FuncExpr *func, ExprContext *econtext,
 			 bool *isNull, ExprDoneCond *isDone);
 static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo,
 				 List *argList, ExprContext *econtext);
-static Datum ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull);
-static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);
-static Datum ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull);
+static Datum ExecEvalNot(BoolExpr *notclause, ExprContext *econtext,
+						 bool *isNull);
+static Datum ExecEvalOr(BoolExpr *orExpr, ExprContext *econtext,
+						bool *isNull);
+static Datum ExecEvalAnd(BoolExpr *andExpr, ExprContext *econtext,
+						 bool *isNull);
 static Datum ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext,
 			 bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalNullTest(NullTest *ntest, ExprContext *econtext,
@@ -122,7 +125,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
 	if (arrayRef->refexpr != NULL)
 	{
 		array_source = (ArrayType *)
-			DatumGetPointer(ExecEvalExpr(arrayRef->refexpr,
+			DatumGetPointer(ExecEvalExpr((Node *) arrayRef->refexpr,
 										 econtext,
 										 isNull,
 										 isDone));
@@ -203,7 +206,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
 
 	if (isAssignment)
 	{
-		Datum		sourceData = ExecEvalExpr(arrayRef->refassgnexpr,
+		Datum		sourceData = ExecEvalExpr((Node *) arrayRef->refassgnexpr,
 											  econtext,
 											  isNull,
 											  NULL);
@@ -839,7 +842,7 @@ ExecMakeTableFunctionResult(Node *funcexpr,
 	bool		returnsTuple = false;
 
 	/*
-	 * Normally the passed expression tree will be a FUNC_EXPR, since the
+	 * Normally the passed expression tree will be a FuncExpr, since the
 	 * grammar only allows a function call at the top level of a table
 	 * function reference.  However, if the function doesn't return set then
 	 * the planner might have replaced the function call via constant-folding
@@ -848,11 +851,9 @@ ExecMakeTableFunctionResult(Node *funcexpr,
 	 * we don't get a chance to pass a special ReturnSetInfo to any functions
 	 * buried in the expression.
 	 */
-	if (funcexpr &&
-		IsA(funcexpr, Expr) &&
-		((Expr *) funcexpr)->opType == FUNC_EXPR)
+	if (funcexpr && IsA(funcexpr, FuncExpr))
 	{
-		Func	   *func;
+		FuncExpr   *func = (FuncExpr *) funcexpr;
 		List	   *argList;
 		FunctionCachePtr fcache;
 		ExprDoneCond argDone;
@@ -862,13 +863,12 @@ ExecMakeTableFunctionResult(Node *funcexpr,
 		 */
 		direct_function_call = true;
 
-		funcrettype = ((Expr *) funcexpr)->typeOid;
-		func = (Func *) ((Expr *) funcexpr)->oper;
-		argList = ((Expr *) funcexpr)->args;
+		funcrettype = func->funcresulttype;
+		argList = func->args;
 
 		/*
-		 * get the fcache from the Func node. If it is NULL, then initialize
-		 * it
+		 * get the fcache from the FuncExpr node. If it is NULL, then
+		 * initialize it
 		 */
 		fcache = func->func_fcache;
 		if (fcache == NULL)
@@ -1102,12 +1102,11 @@ ExecMakeTableFunctionResult(Node *funcexpr,
  * ----------------------------------------------------------------
  */
 static Datum
-ExecEvalOper(Expr *opClause,
+ExecEvalOper(OpExpr *op,
 			 ExprContext *econtext,
 			 bool *isNull,
 			 ExprDoneCond *isDone)
 {
-	Oper	   *op;
 	List	   *argList;
 	FunctionCachePtr fcache;
 
@@ -1117,17 +1116,16 @@ ExecEvalOper(Expr *opClause,
 	 * arguments and returns the result of calling the function on the
 	 * evaluated arguments.
 	 */
-	op = (Oper *) opClause->oper;
-	argList = opClause->args;
+	argList = op->args;
 
 	/*
-	 * get the fcache from the Oper node. If it is NULL, then initialize
+	 * get the fcache from the OpExpr node. If it is NULL, then initialize
 	 * it
 	 */
 	fcache = op->op_fcache;
 	if (fcache == NULL)
 	{
-		fcache = init_fcache(op->opid, length(argList),
+		fcache = init_fcache(op->opfuncid, length(argList),
 							 econtext->ecxt_per_query_memory);
 		op->op_fcache = fcache;
 	}
@@ -1142,12 +1140,11 @@ ExecEvalOper(Expr *opClause,
  */
 
 static Datum
-ExecEvalFunc(Expr *funcClause,
+ExecEvalFunc(FuncExpr *func,
 			 ExprContext *econtext,
 			 bool *isNull,
 			 ExprDoneCond *isDone)
 {
-	Func	   *func;
 	List	   *argList;
 	FunctionCachePtr fcache;
 
@@ -1159,11 +1156,10 @@ ExecEvalFunc(Expr *funcClause,
 	 *
 	 * this is nearly identical to the ExecEvalOper code.
 	 */
-	func = (Func *) funcClause->oper;
-	argList = funcClause->args;
+	argList = func->args;
 
 	/*
-	 * get the fcache from the Func node. If it is NULL, then initialize
+	 * get the fcache from the FuncExpr node. If it is NULL, then initialize
 	 * it
 	 */
 	fcache = func->func_fcache;
@@ -1190,7 +1186,7 @@ ExecEvalFunc(Expr *funcClause,
  * ----------------------------------------------------------------
  */
 static Datum
-ExecEvalDistinct(Expr *opClause,
+ExecEvalDistinct(DistinctExpr *op,
 				 ExprContext *econtext,
 				 bool *isNull,
 				 ExprDoneCond *isDone)
@@ -1199,23 +1195,21 @@ ExecEvalDistinct(Expr *opClause,
 	FunctionCachePtr fcache;
 	FunctionCallInfoData fcinfo;
 	ExprDoneCond argDone;
-	Oper	   *op;
 	List	   *argList;
 
 	/*
-	 * extract info from opClause
+	 * extract info from op
 	 */
-	op = (Oper *) opClause->oper;
-	argList = opClause->args;
+	argList = op->args;
 
 	/*
-	 * get the fcache from the Oper node. If it is NULL, then initialize
-	 * it
+	 * get the fcache from the DistinctExpr node. If it is NULL, then
+	 * initialize it
 	 */
 	fcache = op->op_fcache;
 	if (fcache == NULL)
 	{
-		fcache = init_fcache(op->opid, length(argList),
+		fcache = init_fcache(op->opfuncid, length(argList),
 							 econtext->ecxt_per_query_memory);
 		op->op_fcache = fcache;
 	}
@@ -1256,8 +1250,7 @@ ExecEvalDistinct(Expr *opClause,
  *		ExecEvalOr
  *		ExecEvalAnd
  *
- *		Evaluate boolean expressions.  Evaluation of 'or' is
- *		short-circuited when the first true (or null) value is found.
+ *		Evaluate boolean expressions, with appropriate short-circuiting.
  *
  *		The query planner reformulates clause expressions in the
  *		qualification to conjunctive normal form.  If we ever get
@@ -1268,7 +1261,7 @@ ExecEvalDistinct(Expr *opClause,
  * ----------------------------------------------------------------
  */
 static Datum
-ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull)
+ExecEvalNot(BoolExpr *notclause, ExprContext *econtext, bool *isNull)
 {
 	Node	   *clause;
 	Datum		expr_value;
@@ -1296,7 +1289,7 @@ ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull)
  * ----------------------------------------------------------------
  */
 static Datum
-ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull)
+ExecEvalOr(BoolExpr *orExpr, ExprContext *econtext, bool *isNull)
 {
 	List	   *clauses;
 	List	   *clause;
@@ -1344,7 +1337,7 @@ ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull)
  * ----------------------------------------------------------------
  */
 static Datum
-ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
+ExecEvalAnd(BoolExpr *andExpr, ExprContext *econtext, bool *isNull)
 {
 	List	   *clauses;
 	List	   *clause;
@@ -1409,7 +1402,7 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext,
 	{
 		CaseWhen   *wclause = lfirst(clause);
 
-		clause_value = ExecEvalExpr(wclause->expr,
+		clause_value = ExecEvalExpr((Node *) wclause->expr,
 									econtext,
 									isNull,
 									NULL);
@@ -1421,7 +1414,7 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext,
 		 */
 		if (DatumGetBool(clause_value) && !*isNull)
 		{
-			return ExecEvalExpr(wclause->result,
+			return ExecEvalExpr((Node *) wclause->result,
 								econtext,
 								isNull,
 								isDone);
@@ -1430,7 +1423,7 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext,
 
 	if (caseExpr->defresult)
 	{
-		return ExecEvalExpr(caseExpr->defresult,
+		return ExecEvalExpr((Node *) caseExpr->defresult,
 							econtext,
 							isNull,
 							isDone);
@@ -1454,7 +1447,7 @@ ExecEvalNullTest(NullTest *ntest,
 {
 	Datum		result;
 
-	result = ExecEvalExpr(ntest->arg, econtext, isNull, isDone);
+	result = ExecEvalExpr((Node *) ntest->arg, econtext, isNull, isDone);
 	switch (ntest->nulltesttype)
 	{
 		case IS_NULL:
@@ -1494,7 +1487,7 @@ ExecEvalBooleanTest(BooleanTest *btest,
 {
 	Datum		result;
 
-	result = ExecEvalExpr(btest->arg, econtext, isNull, isDone);
+	result = ExecEvalExpr((Node *) btest->arg, econtext, isNull, isDone);
 	switch (btest->booltesttype)
 	{
 		case IS_TRUE:
@@ -1590,7 +1583,7 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
 {
 	Datum		result;
 
-	result = ExecEvalExpr(constraint->arg, econtext, isNull, isDone);
+	result = ExecEvalExpr((Node *) constraint->arg, econtext, isNull, isDone);
 
 	switch (constraint->testtype)
 	{
@@ -1607,7 +1600,7 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
 				econtext->domainValue_datum = result;
 				econtext->domainValue_isNull = *isNull;
 
-				conResult = ExecEvalExpr(constraint->check_expr, econtext, isNull, isDone);
+				conResult = ExecEvalExpr((Node *) constraint->check_expr, econtext, isNull, isDone);
 
 				if (!DatumGetBool(conResult))
 					elog(ERROR, "ExecEvalConstraintTest: Domain %s constraint %s failed",
@@ -1638,7 +1631,7 @@ ExecEvalFieldSelect(FieldSelect *fselect,
 	Datum		result;
 	TupleTableSlot *resSlot;
 
-	result = ExecEvalExpr(fselect->arg, econtext, isNull, isDone);
+	result = ExecEvalExpr((Node *) fselect->arg, econtext, isNull, isDone);
 	if (*isNull)
 		return result;
 	resSlot = (TupleTableSlot *) DatumGetPointer(result);
@@ -1738,47 +1731,48 @@ ExecEvalExpr(Node *expression,
 										isNull,
 										isDone);
 			break;
-		case T_Expr:
+		case T_FuncExpr:
+			retDatum = ExecEvalFunc((FuncExpr *) expression, econtext,
+									isNull, isDone);
+			break;
+		case T_OpExpr:
+			retDatum = ExecEvalOper((OpExpr *) expression, econtext,
+									isNull, isDone);
+			break;
+		case T_DistinctExpr:
+			retDatum = ExecEvalDistinct((DistinctExpr *) expression, econtext,
+										isNull, isDone);
+			break;
+		case T_BoolExpr:
 			{
-				Expr	   *expr = (Expr *) expression;
+				BoolExpr   *expr = (BoolExpr *) expression;
 
-				switch (expr->opType)
+				switch (expr->boolop)
 				{
-					case OP_EXPR:
-						retDatum = ExecEvalOper(expr, econtext,
-												isNull, isDone);
-						break;
-					case FUNC_EXPR:
-						retDatum = ExecEvalFunc(expr, econtext,
-												isNull, isDone);
+					case AND_EXPR:
+						retDatum = ExecEvalAnd(expr, econtext, isNull);
 						break;
 					case OR_EXPR:
 						retDatum = ExecEvalOr(expr, econtext, isNull);
 						break;
-					case AND_EXPR:
-						retDatum = ExecEvalAnd(expr, econtext, isNull);
-						break;
 					case NOT_EXPR:
 						retDatum = ExecEvalNot(expr, econtext, isNull);
 						break;
-					case DISTINCT_EXPR:
-						retDatum = ExecEvalDistinct(expr, econtext,
-													isNull, isDone);
-						break;
-					case SUBPLAN_EXPR:
-						/* XXX temporary hack to find exec state node */
-						retDatum = ExecSubPlan(((SubPlan *) expr->oper)->pstate,
-											   expr->args, econtext,
-											   isNull);
-						break;
 					default:
-						elog(ERROR, "ExecEvalExpr: unknown expression type %d",
-							 expr->opType);
+						elog(ERROR, "ExecEvalExpr: unknown boolop %d",
+							 expr->boolop);
 						retDatum = 0;	/* keep compiler quiet */
 						break;
 				}
 				break;
 			}
+		case T_SubPlanExpr:
+			/* XXX temporary hack to find exec state node */
+			retDatum = ExecSubPlan(((SubPlanExpr *) expression)->pstate,
+								   ((SubPlanExpr *) expression)->args,
+								   econtext,
+								   isNull);
+			break;
 		case T_FieldSelect:
 			retDatum = ExecEvalFieldSelect((FieldSelect *) expression,
 										   econtext,
@@ -1786,7 +1780,7 @@ ExecEvalExpr(Node *expression,
 										   isDone);
 			break;
 		case T_RelabelType:
-			retDatum = ExecEvalExpr(((RelabelType *) expression)->arg,
+			retDatum = ExecEvalExpr((Node *) ((RelabelType *) expression)->arg,
 									econtext,
 									isNull,
 									isDone);
@@ -1861,7 +1855,7 @@ ExecEvalExprSwitchContext(Node *expression,
  *
  * Soon this will generate an expression state tree paralleling the given
  * expression tree.  Right now, it just searches the expression tree for
- * Aggref and SubPlan nodes.
+ * Aggref and SubPlanExpr nodes.
  */
 Node *
 ExecInitExpr(Node *node, PlanState *parent)
@@ -1887,7 +1881,7 @@ ExecInitExpr(Node *node, PlanState *parent)
 				aggstate->aggs = lcons(node, aggstate->aggs);
 				naggs = ++aggstate->numaggs;
 
-				ExecInitExpr(((Aggref *) node)->target, parent);
+				ExecInitExpr((Node *) ((Aggref *) node)->target, parent);
 
 				/*
 				 * Complain if the aggregate's argument contains any
@@ -1907,64 +1901,67 @@ ExecInitExpr(Node *node, PlanState *parent)
 
 				ExecInitExpr((Node *) aref->refupperindexpr, parent);
 				ExecInitExpr((Node *) aref->reflowerindexpr, parent);
-				ExecInitExpr(aref->refexpr, parent);
-				ExecInitExpr(aref->refassgnexpr, parent);
+				ExecInitExpr((Node *) aref->refexpr, parent);
+				ExecInitExpr((Node *) aref->refassgnexpr, parent);
 			}
 			break;
-		case T_Expr:
+		case T_FuncExpr:
 			{
-				Expr	   *expr = (Expr *) node;
+				FuncExpr   *funcexpr = (FuncExpr *) node;
 
-				switch (expr->opType)
-				{
-					case OP_EXPR:
-						break;
-					case FUNC_EXPR:
-						break;
-					case OR_EXPR:
-						break;
-					case AND_EXPR:
-						break;
-					case NOT_EXPR:
-						break;
-					case DISTINCT_EXPR:
-						break;
-					case SUBPLAN_EXPR:
-						if (parent)
-						{
-							SubLink *sublink = ((SubPlan *) expr->oper)->sublink;
+				ExecInitExpr((Node *) funcexpr->args, parent);
+			}
+			break;
+		case T_OpExpr:
+			{
+				OpExpr   *opexpr = (OpExpr *) node;
 
-							/*
-							 * Here we just add the SubPlan nodes to
-							 * parent->subPlan.  Later they will be expanded
-							 * to SubPlanState nodes.
-							 */
-							parent->subPlan = lcons(expr->oper,
-													parent->subPlan);
-
-							/* Must recurse into oper list too */
-							Assert(IsA(sublink, SubLink));
-							if (sublink->lefthand)
-								elog(ERROR, "ExecInitExpr: sublink has not been transformed");
-							ExecInitExpr((Node *) sublink->oper, parent);
-						}
-						else
-							elog(ERROR, "ExecInitExpr: SubPlan not expected here");
-						break;
-					default:
-						elog(ERROR, "ExecInitExpr: unknown expression type %d",
-							 expr->opType);
-						break;
-				}
-				/* for all Expr node types, examine args list */
-				ExecInitExpr((Node *) expr->args, parent);
+				ExecInitExpr((Node *) opexpr->args, parent);
+			}
+			break;
+		case T_DistinctExpr:
+			{
+				DistinctExpr   *distinctexpr = (DistinctExpr *) node;
+
+				ExecInitExpr((Node *) distinctexpr->args, parent);
+			}
+			break;
+		case T_BoolExpr:
+			{
+				BoolExpr   *boolexpr = (BoolExpr *) node;
+
+				ExecInitExpr((Node *) boolexpr->args, parent);
+			}
+			break;
+		case T_SubPlanExpr:
+			{
+				SubPlanExpr *subplanexpr = (SubPlanExpr *) node;
+				SubLink *sublink = subplanexpr->sublink;
+
+				Assert(IsA(sublink, SubLink));
+				if (!parent)
+					elog(ERROR, "ExecInitExpr: SubPlanExpr not expected here");
+
+				/*
+				 * Here we just add the SubPlanExpr nodes to
+				 * parent->subPlan.  Later they will be expanded
+				 * to SubPlanState nodes.
+				 */
+				parent->subPlan = lcons(subplanexpr, parent->subPlan);
+
+				/* Must recurse into oper list too */
+				if (sublink->lefthand)
+					elog(ERROR, "ExecInitExpr: sublink has not been transformed");
+				ExecInitExpr((Node *) sublink->oper, parent);
+
+				ExecInitExpr((Node *) subplanexpr->args, parent);
 			}
 			break;
 		case T_FieldSelect:
-			ExecInitExpr(((FieldSelect *) node)->arg, parent);
+			ExecInitExpr((Node *) ((FieldSelect *) node)->arg, parent);
 			break;
 		case T_RelabelType:
-			ExecInitExpr(((RelabelType *) node)->arg, parent);
+			ExecInitExpr((Node *) ((RelabelType *) node)->arg, parent);
 			break;
 		case T_CaseExpr:
 			{
@@ -1975,35 +1972,35 @@ ExecInitExpr(Node *node, PlanState *parent)
 					CaseWhen   *when = (CaseWhen *) lfirst(temp);
 
 					Assert(IsA(when, CaseWhen));
-					ExecInitExpr(when->expr, parent);
-					ExecInitExpr(when->result, parent);
+					ExecInitExpr((Node *) when->expr, parent);
+					ExecInitExpr((Node *) when->result, parent);
 				}
 				/* caseexpr->arg should be null, but we'll check it anyway */
-				ExecInitExpr(caseexpr->arg, parent);
-				ExecInitExpr(caseexpr->defresult, parent);
+				ExecInitExpr((Node *) caseexpr->arg, parent);
+				ExecInitExpr((Node *) caseexpr->defresult, parent);
 			}
 			break;
 		case T_NullTest:
-			ExecInitExpr(((NullTest *) node)->arg, parent);
+			ExecInitExpr((Node *) ((NullTest *) node)->arg, parent);
 			break;
 		case T_BooleanTest:
-			ExecInitExpr(((BooleanTest *) node)->arg, parent);
+			ExecInitExpr((Node *) ((BooleanTest *) node)->arg, parent);
 			break;
 		case T_ConstraintTest:
-			ExecInitExpr(((ConstraintTest *) node)->arg, parent);
-			ExecInitExpr(((ConstraintTest *) node)->check_expr, parent);
+			ExecInitExpr((Node *) ((ConstraintTest *) node)->arg, parent);
+			ExecInitExpr((Node *) ((ConstraintTest *) node)->check_expr, parent);
 			break;
 		case T_ConstraintTestValue:
 			break;
+		case T_TargetEntry:
+			ExecInitExpr((Node *) ((TargetEntry *) node)->expr, parent);
+			break;
 		case T_List:
 			foreach(temp, (List *) node)
 			{
 				ExecInitExpr((Node *) lfirst(temp), parent);
 			}
 			break;
-		case T_TargetEntry:
-			ExecInitExpr(((TargetEntry *) node)->expr, parent);
-			break;
 		default:
 			elog(ERROR, "ExecInitExpr: unknown expression type %d",
 				 nodeTag(node));
@@ -2119,19 +2116,8 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
 int
 ExecTargetListLength(List *targetlist)
 {
-	int			len = 0;
-	List	   *tl;
-
-	foreach(tl, targetlist)
-	{
-		TargetEntry *curTle = (TargetEntry *) lfirst(tl);
-
-		if (curTle->resdom != NULL)
-			len++;
-		else
-			len += curTle->fjoin->fj_nNodes;
-	}
-	return len;
+	/* This used to be more complex, but fjoins are dead */
+	return length(targetlist);
 }
 
 /*
@@ -2147,13 +2133,8 @@ ExecCleanTargetListLength(List *targetlist)
 	{
 		TargetEntry *curTle = (TargetEntry *) lfirst(tl);
 
-		if (curTle->resdom != NULL)
-		{
-			if (!curTle->resdom->resjunk)
-				len++;
-		}
-		else
-			len += curTle->fjoin->fj_nNodes;
+		if (!curTle->resdom->resjunk)
+			len++;
 	}
 	return len;
 }
@@ -2182,10 +2163,8 @@ ExecTargetList(List *targetlist,
 
 #define NPREALLOCDOMAINS 64
 	char		nullsArray[NPREALLOCDOMAINS];
-	bool		fjIsNullArray[NPREALLOCDOMAINS];
 	ExprDoneCond itemIsDoneArray[NPREALLOCDOMAINS];
 	char	   *nulls;
-	bool	   *fjIsNull;
 	ExprDoneCond *itemIsDone;
 	List	   *tl;
 	TargetEntry *tle;
@@ -2223,24 +2202,20 @@ ExecTargetList(List *targetlist,
 	 * allocate an array of char's to hold the "null" information only if
 	 * we have a really large targetlist.  otherwise we use the stack.
 	 *
-	 * We also allocate a bool array that is used to hold fjoin result state,
-	 * and another array that holds the isDone status for each targetlist
-	 * item. The isDone status is needed so that we can iterate,
+	 * We also allocate another array that holds the isDone status for each
+	 * targetlist item. The isDone status is needed so that we can iterate,
 	 * generating multiple tuples, when one or more tlist items return
-	 * sets.  (We expect the caller to call us again if we return:
-	 *
+	 * sets.  (We expect the caller to call us again if we return
 	 * isDone = ExprMultipleResult.)
 	 */
 	if (nodomains > NPREALLOCDOMAINS)
 	{
 		nulls = (char *) palloc(nodomains * sizeof(char));
-		fjIsNull = (bool *) palloc(nodomains * sizeof(bool));
 		itemIsDone = (ExprDoneCond *) palloc(nodomains * sizeof(ExprDoneCond));
 	}
 	else
 	{
 		nulls = nullsArray;
-		fjIsNull = fjIsNullArray;
 		itemIsDone = itemIsDoneArray;
 	}
 
@@ -2257,82 +2232,29 @@ ExecTargetList(List *targetlist,
 	{
 		tle = lfirst(tl);
 
-		if (tle->resdom != NULL)
-		{
-			resind = tle->resdom->resno - 1;
+		resind = tle->resdom->resno - 1;
 
-			values[resind] = ExecEvalExpr(tle->expr,
-										  econtext,
-										  &isNull,
-										  &itemIsDone[resind]);
-			nulls[resind] = isNull ? 'n' : ' ';
+		values[resind] = ExecEvalExpr((Node *) tle->expr,
+									  econtext,
+									  &isNull,
+									  &itemIsDone[resind]);
+		nulls[resind] = isNull ? 'n' : ' ';
 
-			if (itemIsDone[resind] != ExprSingleResult)
-			{
-				/* We have a set-valued expression in the tlist */
-				if (isDone == NULL)
-					elog(ERROR, "Set-valued function called in context that cannot accept a set");
-				if (itemIsDone[resind] == ExprMultipleResult)
-				{
-					/* we have undone sets in the tlist, set flag */
-					*isDone = ExprMultipleResult;
-				}
-				else
-				{
-					/* we have done sets in the tlist, set flag for that */
-					haveDoneSets = true;
-				}
-			}
-		}
-		else
+		if (itemIsDone[resind] != ExprSingleResult)
 		{
-#ifdef SETS_FIXED
-			int			curNode;
-			Resdom	   *fjRes;
-			List	   *fjTlist = (List *) tle->expr;
-			Fjoin	   *fjNode = tle->fjoin;
-			int			nNodes = fjNode->fj_nNodes;
-			DatumPtr	results = fjNode->fj_results;
-
-			ExecEvalFjoin(tle, econtext, fjIsNull, isDone);
-
-			/*
-			 * XXX this is wrong, but since fjoin code is completely
-			 * broken anyway, I'm not going to worry about it now --- tgl
-			 * 8/23/00
-			 */
-			if (isDone && *isDone == ExprEndResult)
+			/* We have a set-valued expression in the tlist */
+			if (isDone == NULL)
+				elog(ERROR, "Set-valued function called in context that cannot accept a set");
+			if (itemIsDone[resind] == ExprMultipleResult)
 			{
-				MemoryContextSwitchTo(oldContext);
-				newTuple = NULL;
-				goto exit;
+				/* we have undone sets in the tlist, set flag */
+				*isDone = ExprMultipleResult;
 			}
-
-			/*
-			 * get the result from the inner node
-			 */
-			fjRes = (Resdom *) fjNode->fj_innerNode;
-			resind = fjRes->resno - 1;
-			values[resind] = results[0];
-			nulls[resind] = fjIsNull[0] ? 'n' : ' ';
-
-			/*
-			 * Get results from all of the outer nodes
-			 */
-			for (curNode = 1;
-				 curNode < nNodes;
-				 curNode++, fjTlist = lnext(fjTlist))
+			else
 			{
-				Node	   *outernode = lfirst(fjTlist);
-
-				fjRes = (Resdom *) outernode->iterexpr;
-				resind = fjRes->resno - 1;
-				values[resind] = results[curNode];
-				nulls[resind] = fjIsNull[curNode] ? 'n' : ' ';
+				/* we have done sets in the tlist, set flag for that */
+				haveDoneSets = true;
 			}
-#else
-			elog(ERROR, "ExecTargetList: fjoin nodes not currently supported");
-#endif
 		}
 	}
 
@@ -2368,7 +2290,7 @@ ExecTargetList(List *targetlist,
 
 					if (itemIsDone[resind] == ExprEndResult)
 					{
-						values[resind] = ExecEvalExpr(tle->expr,
+						values[resind] = ExecEvalExpr((Node *) tle->expr,
 													  econtext,
 													  &isNull,
 													&itemIsDone[resind]);
@@ -2404,7 +2326,7 @@ ExecTargetList(List *targetlist,
 
 						while (itemIsDone[resind] == ExprMultipleResult)
 						{
-							(void) ExecEvalExpr(tle->expr,
+							(void) ExecEvalExpr((Node *) tle->expr,
 												econtext,
 												&isNull,
 												&itemIsDone[resind]);
@@ -2434,7 +2356,6 @@ exit:
 	if (nodomains > NPREALLOCDOMAINS)
 	{
 		pfree(nulls);
-		pfree(fjIsNull);
 		pfree(itemIsDone);
 	}
 
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index f5a6863b1ac77e736e7f18f6072cd1e0611a4599..eecc108fb1c1f453a0a47f47b420c215d8c59868 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.61 2002/12/05 15:50:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.62 2002/12/12 15:49:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -576,93 +576,15 @@ ExecTypeFromTL(List *targetList, bool hasoid)
 	foreach(tlitem, targetList)
 	{
 		TargetEntry *tle = lfirst(tlitem);
-		Resdom	   *resdom;
-		Oid			restype;
-
-		if (tle->resdom != NULL)
-		{
-			resdom = tle->resdom;
-			restype = resdom->restype;
-
-			TupleDescInitEntry(typeInfo,
-							   resdom->resno,
-							   resdom->resname,
-							   restype,
-							   resdom->restypmod,
-							   0,
-							   false);
-
-#ifdef NOT_USED
-			ExecSetTypeInfo(resdom->resno - 1,
-							typeInfo,
-							(Oid) restype,
-							resdom->resno,
-							resdom->reslen,
-							NameStr(*resdom->resname),
-							get_typbyval(restype),
-							get_typalign(restype));
-#endif
-		}
-		else
-		{
-			/* XXX this branch looks fairly broken ... tgl 12/2000 */
-			Resdom	   *fjRes;
-			List	   *fjTlistP;
-			List	   *fjList = lfirst(tlitem);
-
-#ifdef SETS_FIXED
-			TargetEntry *tle;
-			Fjoin	   *fjNode = ((TargetEntry *) lfirst(fjList))->fjoin;
-
-			tle = fjNode->fj_innerNode; /* ??? */
-#endif
-			fjRes = tle->resdom;
-			restype = fjRes->restype;
-
-			TupleDescInitEntry(typeInfo,
-							   fjRes->resno,
-							   fjRes->resname,
-							   restype,
-							   fjRes->restypmod,
-							   0,
-							   false);
-#ifdef NOT_USED
-			ExecSetTypeInfo(fjRes->resno - 1,
-							typeInfo,
-							(Oid) restype,
-							fjRes->resno,
-							fjRes->reslen,
-							(char *) fjRes->resname,
-							get_typbyval(restype),
-							get_typalign(restype));
-#endif
-
-			foreach(fjTlistP, lnext(fjList))
-			{
-				TargetEntry *fjTle = lfirst(fjTlistP);
-
-				fjRes = fjTle->resdom;
-
-				TupleDescInitEntry(typeInfo,
-								   fjRes->resno,
-								   fjRes->resname,
-								   restype,
-								   fjRes->restypmod,
-								   0,
-								   false);
-
-#ifdef NOT_USED
-				ExecSetTypeInfo(fjRes->resno - 1,
-								typeInfo,
-								(Oid) fjRes->restype,
-								fjRes->resno,
-								fjRes->reslen,
-								(char *) fjRes->resname,
-								get_typbyval(fjRes->restype),
-								get_typalign(fjRes->restype));
-#endif
-			}
-		}
+		Resdom	   *resdom = tle->resdom;
+
+		TupleDescInitEntry(typeInfo,
+						   resdom->resno,
+						   resdom->resname,
+						   resdom->restype,
+						   resdom->restypmod,
+						   0,
+						   false);
 	}
 
 	return typeInfo;
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index bdbe61cb10ac94d2bf50f0a2bbbc6fd480da7d1f..73e4a8044ef332ff4028842cf3705029b65b68eb 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -45,7 +45,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.98 2002/12/05 15:50:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.99 2002/12/12 15:49:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -415,7 +415,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
 		Datum		newVal;
 		bool		isNull;
 
-		newVal = ExecEvalExprSwitchContext(aggref->target, econtext,
+		newVal = ExecEvalExprSwitchContext((Node *) aggref->target, econtext,
 										   &isNull, NULL);
 
 		if (aggref->aggdistinct)
@@ -1298,7 +1298,7 @@ ExecInitAgg(Agg *node, EState *estate)
 			 * pg_proc.proargtypes, because the latter might be 0.
 			 * (Consider COUNT(*).)
 			 */
-			Oid			inputType = exprType(aggref->target);
+			Oid			inputType = exprType((Node *) aggref->target);
 
 			if (!IsBinaryCoercible(inputType, aggform->aggtranstype))
 				elog(ERROR, "Aggregate %u needs to have compatible input type and transition type",
@@ -1312,7 +1312,7 @@ ExecInitAgg(Agg *node, EState *estate)
 			 * pg_proc.proargtypes, because the latter might be a pseudotype.
 			 * (Consider COUNT(*).)
 			 */
-			Oid			inputType = exprType(aggref->target);
+			Oid			inputType = exprType((Node *) aggref->target);
 			Oid			eq_function;
 
 			/* We don't implement DISTINCT aggs in the HASHED case */
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index e9888c4d3f533db8313ef4fe36b7870687835377..0112d3641dea3871b48db1336c3eb02399362e0d 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.72 2002/12/05 15:50:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.73 2002/12/12 15:49:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -703,28 +703,26 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 		listscan = qual;
 		for (j = 0; j < n_keys; j++)
 		{
-			Expr	   *clause; /* one clause of index qual */
-			Oper	   *op;		/* operator used in clause */
+			OpExpr	   *clause; /* one clause of index qual */
 			Node	   *leftop; /* expr on lhs of operator */
 			Node	   *rightop;	/* expr on rhs ... */
 			bits16		flags = 0;
 
 			int			scanvar;	/* which var identifies varattno */
 			AttrNumber	varattno = 0;	/* att number used in scan */
-			Oid			opid;	/* operator id used in scan */
+			Oid			opfuncid;		/* operator id used in scan */
 			Datum		scanvalue = 0;	/* value used in scan (if const) */
 
 			/*
 			 * extract clause information from the qualification
 			 */
-			clause = lfirst(listscan);
+			clause = (OpExpr *) lfirst(listscan);
 			listscan = lnext(listscan);
 
-			op = (Oper *) clause->oper;
-			if (!IsA(clause, Expr) ||!IsA(op, Oper))
+			if (!IsA(clause, OpExpr))
 				elog(ERROR, "ExecInitIndexScan: indxqual not an opclause!");
 
-			opid = op->opid;
+			opfuncid = clause->opfuncid;
 
 			/*
 			 * Here we figure out the contents of the index qual. The
@@ -767,10 +765,10 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 			/*
 			 * determine information in leftop
 			 */
-			leftop = (Node *) get_leftop(clause);
+			leftop = (Node *) get_leftop((Expr *) clause);
 
 			if (leftop && IsA(leftop, RelabelType))
-				leftop = ((RelabelType *) leftop)->arg;
+				leftop = (Node *) ((RelabelType *) leftop)->arg;
 
 			Assert(leftop != NULL);
 
@@ -834,10 +832,10 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 			/*
 			 * now determine information in rightop
 			 */
-			rightop = (Node *) get_rightop(clause);
+			rightop = (Node *) get_rightop((Expr *) clause);
 
 			if (rightop && IsA(rightop, RelabelType))
-				rightop = ((RelabelType *) rightop)->arg;
+				rightop = (Node *) ((RelabelType *) rightop)->arg;
 
 			Assert(rightop != NULL);
 
@@ -921,7 +919,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 								   flags,
 								   varattno,	/* attribute number to
 												 * scan */
-								   (RegProcedure) opid, /* reg proc to use */
+								   opfuncid,	/* reg proc to use */
 								   scanvalue);	/* constant */
 		}
 
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 171738dd34917876e3a8afd31787746b4a87a50d..e6c2c86be19672d15c37f4f7ed94bdaf4819ff8c 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.52 2002/12/05 15:50:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.53 2002/12/12 15:49:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -119,16 +119,14 @@ MJFormSkipQuals(List *qualList, List **ltQuals, List **gtQuals)
 	ltcdr = *ltQuals;
 	foreach(gtcdr, *gtQuals)
 	{
-		Expr	   *ltqual = (Expr *) lfirst(ltcdr);
-		Expr	   *gtqual = (Expr *) lfirst(gtcdr);
-		Oper	   *ltop = (Oper *) ltqual->oper;
-		Oper	   *gtop = (Oper *) gtqual->oper;
+		OpExpr	   *ltop = (OpExpr *) lfirst(ltcdr);
+		OpExpr	   *gtop = (OpExpr *) lfirst(gtcdr);
 
 		/*
 		 * The two ops should be identical, so use either one for lookup.
 		 */
-		if (!IsA(ltop, Oper))
-			elog(ERROR, "MJFormSkipQuals: op not an Oper!");
+		if (!IsA(ltop, OpExpr))
+			elog(ERROR, "MJFormSkipQuals: op not an OpExpr!");
 
 		/*
 		 * Lookup the operators, and replace the data in the copied
@@ -137,8 +135,8 @@ MJFormSkipQuals(List *qualList, List **ltQuals, List **gtQuals)
 		op_mergejoin_crossops(ltop->opno,
 							  &ltop->opno,
 							  &gtop->opno,
-							  &ltop->opid,
-							  &gtop->opid);
+							  &ltop->opfuncid,
+							  &gtop->opfuncid);
 		ltop->op_fcache = NULL;
 		gtop->op_fcache = NULL;
 
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 195634c128982bc0b19c3704ebe8669060bbdc44..880a6233db287da218f64337b13c4226d63906e0 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.35 2002/12/05 15:50:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.36 2002/12/12 15:49:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,7 +34,7 @@ ExecSubPlan(SubPlanState *node, List *pvar,
 			ExprContext *econtext, bool *isNull)
 {
 	PlanState  *planstate = node->planstate;
-	SubPlan	   *subplan = (SubPlan *) node->ps.plan;
+	SubPlanExpr *subplan = (SubPlanExpr *) node->ps.plan;
 	SubLink    *sublink = subplan->sublink;
 	SubLinkType subLinkType = sublink->subLinkType;
 	bool		useor = sublink->useor;
@@ -151,7 +151,7 @@ ExecSubPlan(SubPlanState *node, List *pvar,
 		 */
 		foreach(lst, sublink->oper)
 		{
-			Expr	   *expr = (Expr *) lfirst(lst);
+			OpExpr	   *expr = (OpExpr *) lfirst(lst);
 			Param	   *prm = lsecond(expr->args);
 			ParamExecData *prmdata;
 			Datum		expresult;
@@ -172,8 +172,8 @@ ExecSubPlan(SubPlanState *node, List *pvar,
 			{
 				switch (nodeTag(prm))
 				{
-					case T_Expr:
-						prm = lfirst(((Expr *) prm)->args);
+					case T_FuncExpr:
+						prm = lfirst(((FuncExpr *) prm)->args);
 						break;
 					case T_RelabelType:
 						prm = (Param *) (((RelabelType *) prm)->arg);
@@ -288,7 +288,7 @@ ExecSubPlan(SubPlanState *node, List *pvar,
  * ----------------------------------------------------------------
  */
 SubPlanState *
-ExecInitSubPlan(SubPlan *node, EState *estate)
+ExecInitSubPlan(SubPlanExpr *node, EState *estate)
 {
 	SubPlanState *subplanstate;
 	EState	   *sp_estate;
@@ -374,7 +374,7 @@ void
 ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 {
 	PlanState  *planstate = node->planstate;
-	SubPlan	   *subplan = (SubPlan *) node->ps.plan;
+	SubPlanExpr *subplan = (SubPlanExpr *) node->ps.plan;
 	SubLink    *sublink = subplan->sublink;
 	EState	   *estate = node->ps.state;
 	MemoryContext oldcontext;
@@ -497,7 +497,7 @@ void
 ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
 {
 	PlanState  *planstate = node->planstate;
-	SubPlan	   *subplan = (SubPlan *) node->ps.plan;
+	SubPlanExpr *subplan = (SubPlanExpr *) node->ps.plan;
 	EState	   *estate = node->ps.state;
 	List	   *lst;
 
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index a978e233e3dfecdd970e0cb3b053096e6e3d63d9..f7aa8fcb7ec83771c8310905551f563e5e0925fd 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.229 2002/12/06 05:00:18 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.230 2002/12/12 15:49:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -563,21 +563,6 @@ _copyLimit(Limit *from)
 	return newnode;
 }
 
-static SubPlan *
-_copySubPlan(SubPlan *from)
-{
-	SubPlan    *newnode = makeNode(SubPlan);
-
-	COPY_NODE_FIELD(plan);
-	COPY_SCALAR_FIELD(plan_id);
-	COPY_NODE_FIELD(rtable);
-	COPY_INTLIST_FIELD(setParam);
-	COPY_INTLIST_FIELD(parParam);
-	COPY_NODE_FIELD(sublink);
-
-	return newnode;
-}
-
 /* ****************************************************************
  *					   primnodes.h copy functions
  * ****************************************************************
@@ -603,20 +588,9 @@ _copyResdom(Resdom *from)
 	return newnode;
 }
 
-static Fjoin *
-_copyFjoin(Fjoin *from)
-{
-	Fjoin	   *newnode = makeNode(Fjoin);
-
-	COPY_SCALAR_FIELD(fj_initialized);
-	COPY_SCALAR_FIELD(fj_nNodes);
-	COPY_NODE_FIELD(fj_innerNode);
-	COPY_POINTER_FIELD(fj_results, from->fj_nNodes * sizeof(Datum));
-	COPY_POINTER_FIELD(fj_alwaysDone, from->fj_nNodes * sizeof(bool));
-
-	return newnode;
-}
-
+/*
+ * _copyAlias
+ */
 static Alias *
 _copyAlias(Alias *from)
 {
@@ -628,6 +602,9 @@ _copyAlias(Alias *from)
 	return newnode;
 }
 
+/*
+ * _copyRangeVar
+ */
 static RangeVar *
 _copyRangeVar(RangeVar *from)
 {
@@ -644,20 +621,11 @@ _copyRangeVar(RangeVar *from)
 }
 
 /*
- * _copyExpr
+ * We don't need a _copyExpr because Expr is an abstract supertype which
+ * should never actually get instantiated.  Also, since it has no common
+ * fields except NodeTag, there's no need for a helper routine to factor
+ * out copying the common fields...
  */
-static Expr *
-_copyExpr(Expr *from)
-{
-	Expr	   *newnode = makeNode(Expr);
-
-	COPY_SCALAR_FIELD(typeOid);
-	COPY_SCALAR_FIELD(opType);
-	COPY_NODE_FIELD(oper);
-	COPY_NODE_FIELD(args);
-
-	return newnode;
-}
 
 /*
  * _copyVar
@@ -678,25 +646,6 @@ _copyVar(Var *from)
 	return newnode;
 }
 
-/*
- * _copyOper
- */
-static Oper *
-_copyOper(Oper *from)
-{
-	Oper	   *newnode = makeNode(Oper);
-
-	COPY_SCALAR_FIELD(opno);
-	COPY_SCALAR_FIELD(opid);
-	COPY_SCALAR_FIELD(opresulttype);
-	COPY_SCALAR_FIELD(opretset);
-
-	/* Do not copy the run-time state, if any */
-	newnode->op_fcache = NULL;
-
-	return newnode;
-}
-
 /*
  * _copyConst
  */
@@ -749,17 +698,57 @@ _copyParam(Param *from)
 }
 
 /*
- * _copyFunc
+ * _copyAggref
  */
-static Func *
-_copyFunc(Func *from)
+static Aggref *
+_copyAggref(Aggref *from)
 {
-	Func	   *newnode = makeNode(Func);
+	Aggref	   *newnode = makeNode(Aggref);
+
+	COPY_SCALAR_FIELD(aggfnoid);
+	COPY_SCALAR_FIELD(aggtype);
+	COPY_NODE_FIELD(target);
+	COPY_SCALAR_FIELD(aggstar);
+	COPY_SCALAR_FIELD(aggdistinct);
+	COPY_SCALAR_FIELD(aggno);	/* will go away soon */
+
+	return newnode;
+}
+
+/*
+ * _copyArrayRef
+ */
+static ArrayRef *
+_copyArrayRef(ArrayRef *from)
+{
+	ArrayRef   *newnode = makeNode(ArrayRef);
+
+	COPY_SCALAR_FIELD(refrestype);
+	COPY_SCALAR_FIELD(refattrlength);
+	COPY_SCALAR_FIELD(refelemlength);
+	COPY_SCALAR_FIELD(refelembyval);
+	COPY_SCALAR_FIELD(refelemalign);
+	COPY_NODE_FIELD(refupperindexpr);
+	COPY_NODE_FIELD(reflowerindexpr);
+	COPY_NODE_FIELD(refexpr);
+	COPY_NODE_FIELD(refassgnexpr);
+
+	return newnode;
+}
+
+/*
+ * _copyFuncExpr
+ */
+static FuncExpr *
+_copyFuncExpr(FuncExpr *from)
+{
+	FuncExpr	   *newnode = makeNode(FuncExpr);
 
 	COPY_SCALAR_FIELD(funcid);
 	COPY_SCALAR_FIELD(funcresulttype);
 	COPY_SCALAR_FIELD(funcretset);
 	COPY_SCALAR_FIELD(funcformat);
+	COPY_NODE_FIELD(args);
 
 	/* Do not copy the run-time state, if any */
 	newnode->func_fcache = NULL;
@@ -768,19 +757,55 @@ _copyFunc(Func *from)
 }
 
 /*
- * _copyAggref
+ * _copyOpExpr
  */
-static Aggref *
-_copyAggref(Aggref *from)
+static OpExpr *
+_copyOpExpr(OpExpr *from)
 {
-	Aggref	   *newnode = makeNode(Aggref);
+	OpExpr	   *newnode = makeNode(OpExpr);
 
-	COPY_SCALAR_FIELD(aggfnoid);
-	COPY_SCALAR_FIELD(aggtype);
-	COPY_NODE_FIELD(target);
-	COPY_SCALAR_FIELD(aggstar);
-	COPY_SCALAR_FIELD(aggdistinct);
-	COPY_SCALAR_FIELD(aggno);	/* probably not necessary */
+	COPY_SCALAR_FIELD(opno);
+	COPY_SCALAR_FIELD(opfuncid);
+	COPY_SCALAR_FIELD(opresulttype);
+	COPY_SCALAR_FIELD(opretset);
+	COPY_NODE_FIELD(args);
+
+	/* Do not copy the run-time state, if any */
+	newnode->op_fcache = NULL;
+
+	return newnode;
+}
+
+/*
+ * _copyDistinctExpr
+ */
+static DistinctExpr *
+_copyDistinctExpr(DistinctExpr *from)
+{
+	DistinctExpr	   *newnode = makeNode(DistinctExpr);
+
+	COPY_SCALAR_FIELD(opno);
+	COPY_SCALAR_FIELD(opfuncid);
+	COPY_SCALAR_FIELD(opresulttype);
+	COPY_SCALAR_FIELD(opretset);
+	COPY_NODE_FIELD(args);
+
+	/* Do not copy the run-time state, if any */
+	newnode->op_fcache = NULL;
+
+	return newnode;
+}
+
+/*
+ * _copyBoolExpr
+ */
+static BoolExpr *
+_copyBoolExpr(BoolExpr *from)
+{
+	BoolExpr	   *newnode = makeNode(BoolExpr);
+
+	COPY_SCALAR_FIELD(boolop);
+	COPY_NODE_FIELD(args);
 
 	return newnode;
 }
@@ -802,6 +827,26 @@ _copySubLink(SubLink *from)
 	return newnode;
 }
 
+/*
+ * _copySubPlanExpr
+ */
+static SubPlanExpr *
+_copySubPlanExpr(SubPlanExpr *from)
+{
+	SubPlanExpr    *newnode = makeNode(SubPlanExpr);
+
+	COPY_SCALAR_FIELD(typeOid);
+	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;
+}
+
 /*
  * _copyFieldSelect
  */
@@ -834,6 +879,112 @@ _copyRelabelType(RelabelType *from)
 	return newnode;
 }
 
+/*
+ * _copyCaseExpr
+ */
+static CaseExpr *
+_copyCaseExpr(CaseExpr *from)
+{
+	CaseExpr   *newnode = makeNode(CaseExpr);
+
+	COPY_SCALAR_FIELD(casetype);
+	COPY_NODE_FIELD(arg);
+	COPY_NODE_FIELD(args);
+	COPY_NODE_FIELD(defresult);
+
+	return newnode;
+}
+
+/*
+ * _copyCaseWhen
+ */
+static CaseWhen *
+_copyCaseWhen(CaseWhen *from)
+{
+	CaseWhen   *newnode = makeNode(CaseWhen);
+
+	COPY_NODE_FIELD(expr);
+	COPY_NODE_FIELD(result);
+
+	return newnode;
+}
+
+/*
+ * _copyNullTest
+ */
+static NullTest *
+_copyNullTest(NullTest *from)
+{
+	NullTest   *newnode = makeNode(NullTest);
+
+	COPY_NODE_FIELD(arg);
+	COPY_SCALAR_FIELD(nulltesttype);
+
+	return newnode;
+}
+
+/*
+ * _copyBooleanTest
+ */
+static BooleanTest *
+_copyBooleanTest(BooleanTest *from)
+{
+	BooleanTest *newnode = makeNode(BooleanTest);
+
+	COPY_NODE_FIELD(arg);
+	COPY_SCALAR_FIELD(booltesttype);
+
+	return newnode;
+}
+
+/*
+ * _copyConstraintTest
+ */
+static ConstraintTest *
+_copyConstraintTest(ConstraintTest *from)
+{
+	ConstraintTest *newnode = makeNode(ConstraintTest);
+
+	COPY_NODE_FIELD(arg);
+	COPY_SCALAR_FIELD(testtype);
+	COPY_STRING_FIELD(name);
+	COPY_STRING_FIELD(domname);
+	COPY_NODE_FIELD(check_expr);
+
+	return newnode;
+}
+
+/*
+ * _copyConstraintTestValue
+ */
+static ConstraintTestValue *
+_copyConstraintTestValue(ConstraintTestValue *from)
+{
+	ConstraintTestValue *newnode = makeNode(ConstraintTestValue);
+
+	COPY_SCALAR_FIELD(typeId);
+	COPY_SCALAR_FIELD(typeMod);
+
+	return newnode;
+}
+
+/*
+ * _copyTargetEntry
+ */
+static TargetEntry *
+_copyTargetEntry(TargetEntry *from)
+{
+	TargetEntry *newnode = makeNode(TargetEntry);
+
+	COPY_NODE_FIELD(resdom);
+	COPY_NODE_FIELD(expr);
+
+	return newnode;
+}
+
+/*
+ * _copyRangeTblRef
+ */
 static RangeTblRef *
 _copyRangeTblRef(RangeTblRef *from)
 {
@@ -844,6 +995,9 @@ _copyRangeTblRef(RangeTblRef *from)
 	return newnode;
 }
 
+/*
+ * _copyJoinExpr
+ */
 static JoinExpr *
 _copyJoinExpr(JoinExpr *from)
 {
@@ -861,6 +1015,9 @@ _copyJoinExpr(JoinExpr *from)
 	return newnode;
 }
 
+/*
+ * _copyFromExpr
+ */
 static FromExpr *
 _copyFromExpr(FromExpr *from)
 {
@@ -872,24 +1029,6 @@ _copyFromExpr(FromExpr *from)
 	return newnode;
 }
 
-static ArrayRef *
-_copyArrayRef(ArrayRef *from)
-{
-	ArrayRef   *newnode = makeNode(ArrayRef);
-
-	COPY_SCALAR_FIELD(refrestype);
-	COPY_SCALAR_FIELD(refattrlength);
-	COPY_SCALAR_FIELD(refelemlength);
-	COPY_SCALAR_FIELD(refelembyval);
-	COPY_SCALAR_FIELD(refelemalign);
-	COPY_NODE_FIELD(refupperindexpr);
-	COPY_NODE_FIELD(reflowerindexpr);
-	COPY_NODE_FIELD(refexpr);
-	COPY_NODE_FIELD(refassgnexpr);
-
-	return newnode;
-}
-
 /* ****************************************************************
  *						relation.h copy functions
  *
@@ -964,18 +1103,6 @@ _copyJoinInfo(JoinInfo *from)
  * ****************************************************************
  */
 
-static TargetEntry *
-_copyTargetEntry(TargetEntry *from)
-{
-	TargetEntry *newnode = makeNode(TargetEntry);
-
-	COPY_NODE_FIELD(resdom);
-	COPY_NODE_FIELD(fjoin);
-	COPY_NODE_FIELD(expr);
-
-	return newnode;
-}
-
 static RangeTblEntry *
 _copyRangeTblEntry(RangeTblEntry *from)
 {
@@ -1170,6 +1297,14 @@ _copyTypeName(TypeName *from)
 	return newnode;
 }
 
+static DomainConstraintValue *
+_copyDomainConstraintValue(DomainConstraintValue *from)
+{
+	DomainConstraintValue *newnode = makeNode(DomainConstraintValue);
+
+	return newnode;
+}
+
 static SortGroupBy *
 _copySortGroupBy(SortGroupBy *from)
 {
@@ -1260,85 +1395,6 @@ _copyConstraint(Constraint *from)
 	return newnode;
 }
 
-static CaseExpr *
-_copyCaseExpr(CaseExpr *from)
-{
-	CaseExpr   *newnode = makeNode(CaseExpr);
-
-	COPY_SCALAR_FIELD(casetype);
-	COPY_NODE_FIELD(arg);
-	COPY_NODE_FIELD(args);
-	COPY_NODE_FIELD(defresult);
-
-	return newnode;
-}
-
-static CaseWhen *
-_copyCaseWhen(CaseWhen *from)
-{
-	CaseWhen   *newnode = makeNode(CaseWhen);
-
-	COPY_NODE_FIELD(expr);
-	COPY_NODE_FIELD(result);
-
-	return newnode;
-}
-
-static NullTest *
-_copyNullTest(NullTest *from)
-{
-	NullTest   *newnode = makeNode(NullTest);
-
-	COPY_NODE_FIELD(arg);
-	COPY_SCALAR_FIELD(nulltesttype);
-
-	return newnode;
-}
-
-static BooleanTest *
-_copyBooleanTest(BooleanTest *from)
-{
-	BooleanTest *newnode = makeNode(BooleanTest);
-
-	COPY_NODE_FIELD(arg);
-	COPY_SCALAR_FIELD(booltesttype);
-
-	return newnode;
-}
-
-static ConstraintTest *
-_copyConstraintTest(ConstraintTest *from)
-{
-	ConstraintTest *newnode = makeNode(ConstraintTest);
-
-	COPY_NODE_FIELD(arg);
-	COPY_SCALAR_FIELD(testtype);
-	COPY_STRING_FIELD(name);
-	COPY_STRING_FIELD(domname);
-	COPY_NODE_FIELD(check_expr);
-
-	return newnode;
-}
-
-static DomainConstraintValue *
-_copyDomainConstraintValue(DomainConstraintValue *from)
-{
-	DomainConstraintValue *newnode = makeNode(DomainConstraintValue);
-
-	return newnode;
-}
-
-static ConstraintTestValue *
-_copyConstraintTestValue(ConstraintTestValue *from)
-{
-	ConstraintTestValue *newnode = makeNode(ConstraintTestValue);
-
-	COPY_SCALAR_FIELD(typeId);
-	COPY_SCALAR_FIELD(typeMod);
-
-	return newnode;
-}
-
 static DefElem *
 _copyDefElem(DefElem *from)
 {
@@ -2350,9 +2406,6 @@ copyObject(void *from)
 		case T_Limit:
 			retval = _copyLimit(from);
 			break;
-		case T_SubPlan:
-			retval = _copySubPlan(from);
-			break;
 
 			/*
 			 * PRIMITIVE NODES
@@ -2360,45 +2413,72 @@ copyObject(void *from)
 		case T_Resdom:
 			retval = _copyResdom(from);
 			break;
-		case T_Fjoin:
-			retval = _copyFjoin(from);
-			break;
 		case T_Alias:
 			retval = _copyAlias(from);
 			break;
 		case T_RangeVar:
 			retval = _copyRangeVar(from);
 			break;
-		case T_Expr:
-			retval = _copyExpr(from);
-			break;
 		case T_Var:
 			retval = _copyVar(from);
 			break;
-		case T_Oper:
-			retval = _copyOper(from);
-			break;
 		case T_Const:
 			retval = _copyConst(from);
 			break;
 		case T_Param:
 			retval = _copyParam(from);
 			break;
-		case T_Func:
-			retval = _copyFunc(from);
-			break;
 		case T_Aggref:
 			retval = _copyAggref(from);
 			break;
+		case T_ArrayRef:
+			retval = _copyArrayRef(from);
+			break;
+		case T_FuncExpr:
+			retval = _copyFuncExpr(from);
+			break;
+		case T_OpExpr:
+			retval = _copyOpExpr(from);
+			break;
+		case T_DistinctExpr:
+			retval = _copyDistinctExpr(from);
+			break;
+		case T_BoolExpr:
+			retval = _copyBoolExpr(from);
+			break;
 		case T_SubLink:
 			retval = _copySubLink(from);
 			break;
+		case T_SubPlanExpr:
+			retval = _copySubPlanExpr(from);
+			break;
 		case T_FieldSelect:
 			retval = _copyFieldSelect(from);
 			break;
 		case T_RelabelType:
 			retval = _copyRelabelType(from);
 			break;
+		case T_CaseExpr:
+			retval = _copyCaseExpr(from);
+			break;
+		case T_CaseWhen:
+			retval = _copyCaseWhen(from);
+			break;
+		case T_NullTest:
+			retval = _copyNullTest(from);
+			break;
+		case T_BooleanTest:
+			retval = _copyBooleanTest(from);
+			break;
+		case T_ConstraintTest:
+			retval = _copyConstraintTest(from);
+			break;
+		case T_ConstraintTestValue:
+			retval = _copyConstraintTestValue(from);
+			break;
+		case T_TargetEntry:
+			retval = _copyTargetEntry(from);
+			break;
 		case T_RangeTblRef:
 			retval = _copyRangeTblRef(from);
 			break;
@@ -2408,9 +2488,6 @@ copyObject(void *from)
 		case T_FromExpr:
 			retval = _copyFromExpr(from);
 			break;
-		case T_ArrayRef:
-			retval = _copyArrayRef(from);
-			break;
 
 			/*
 			 * RELATION NODES
@@ -2686,6 +2763,9 @@ copyObject(void *from)
 		case T_TypeCast:
 			retval = _copyTypeCast(from);
 			break;
+		case T_DomainConstraintValue:
+			retval = _copyDomainConstraintValue(from);
+			break;
 		case T_SortGroupBy:
 			retval = _copySortGroupBy(from);
 			break;
@@ -2710,9 +2790,6 @@ copyObject(void *from)
 		case T_DefElem:
 			retval = _copyDefElem(from);
 			break;
-		case T_TargetEntry:
-			retval = _copyTargetEntry(from);
-			break;
 		case T_RangeTblEntry:
 			retval = _copyRangeTblEntry(from);
 			break;
@@ -2722,24 +2799,6 @@ copyObject(void *from)
 		case T_GroupClause:
 			retval = _copyGroupClause(from);
 			break;
-		case T_CaseExpr:
-			retval = _copyCaseExpr(from);
-			break;
-		case T_CaseWhen:
-			retval = _copyCaseWhen(from);
-			break;
-		case T_NullTest:
-			retval = _copyNullTest(from);
-			break;
-		case T_BooleanTest:
-			retval = _copyBooleanTest(from);
-			break;
-		case T_ConstraintTest:
-			retval = _copyConstraintTest(from);
-			break;
-		case T_ConstraintTestValue:
-			retval = _copyConstraintTestValue(from);
-			break;
 		case T_FkConstraint:
 			retval = _copyFkConstraint(from);
 			break;
@@ -2752,9 +2811,6 @@ copyObject(void *from)
 		case T_InsertDefault:
 			retval = _copyInsertDefault(from);
 			break;
-		case T_DomainConstraintValue:
-			retval = _copyDomainConstraintValue(from);
-			break;
 
 		default:
 			elog(ERROR, "copyObject: don't know how to copy node type %d",
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7122709710476ee3ef5329595dee0d01823d2a49..3b5103820688fc065bcb7bbd08087b7eae9eddf1 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.174 2002/12/06 05:00:18 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.175 2002/12/12 15:49:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,7 +27,6 @@
 
 #include "nodes/params.h"
 #include "nodes/parsenodes.h"
-#include "nodes/plannodes.h"
 #include "nodes/relation.h"
 #include "utils/datum.h"
 
@@ -98,18 +97,6 @@ _equalResdom(Resdom *a, Resdom *b)
 	return true;
 }
 
-static bool
-_equalFjoin(Fjoin *a, Fjoin *b)
-{
-	COMPARE_SCALAR_FIELD(fj_initialized);
-	COMPARE_SCALAR_FIELD(fj_nNodes);
-	COMPARE_NODE_FIELD(fj_innerNode);
-	COMPARE_POINTER_FIELD(fj_results, a->fj_nNodes * sizeof(Datum));
-	COMPARE_POINTER_FIELD(fj_alwaysDone, a->fj_nNodes * sizeof(bool));
-
-	return true;
-}
-
 static bool
 _equalAlias(Alias *a, Alias *b)
 {
@@ -132,20 +119,12 @@ _equalRangeVar(RangeVar *a, RangeVar *b)
 	return true;
 }
 
-static bool
-_equalExpr(Expr *a, Expr *b)
-{
-	/*
-	 * We do not examine typeOid, since the optimizer often doesn't bother
-	 * to set it in created nodes, and it is logically a derivative of the
-	 * oper field anyway.
-	 */
-	COMPARE_SCALAR_FIELD(opType);
-	COMPARE_NODE_FIELD(oper);
-	COMPARE_NODE_FIELD(args);
-
-	return true;
-}
+/*
+ * We don't need an _equalExpr because Expr is an abstract supertype which
+ * should never actually get instantiated.  Also, since it has no common
+ * fields except NodeTag, there's no need for a helper routine to factor
+ * out comparing the common fields...
+ */
 
 static bool
 _equalVar(Var *a, Var *b)
@@ -161,28 +140,6 @@ _equalVar(Var *a, Var *b)
 	return true;
 }
 
-static bool
-_equalOper(Oper *a, Oper *b)
-{
-	COMPARE_SCALAR_FIELD(opno);
-	COMPARE_SCALAR_FIELD(opresulttype);
-	COMPARE_SCALAR_FIELD(opretset);
-
-	/*
-	 * We do not examine opid or op_fcache, since these are logically
-	 * derived from opno, and they may not be set yet depending on how far
-	 * along the node is in the parse/plan pipeline.
-	 *
-	 * (Besides, op_fcache is executor state, which we don't check --- see
-	 * notes at head of file.)
-	 *
-	 * It's probably not really necessary to check opresulttype or opretset,
-	 * either...
-	 */
-
-	return true;
-}
-
 static bool
 _equalConst(Const *a, Const *b)
 {
@@ -226,7 +183,35 @@ _equalParam(Param *a, Param *b)
 }
 
 static bool
-_equalFunc(Func *a, Func *b)
+_equalAggref(Aggref *a, Aggref *b)
+{
+	COMPARE_SCALAR_FIELD(aggfnoid);
+	COMPARE_SCALAR_FIELD(aggtype);
+	COMPARE_NODE_FIELD(target);
+	COMPARE_SCALAR_FIELD(aggstar);
+	COMPARE_SCALAR_FIELD(aggdistinct);
+
+	return true;
+}
+
+static bool
+_equalArrayRef(ArrayRef *a, ArrayRef *b)
+{
+	COMPARE_SCALAR_FIELD(refrestype);
+	COMPARE_SCALAR_FIELD(refattrlength);
+	COMPARE_SCALAR_FIELD(refelemlength);
+	COMPARE_SCALAR_FIELD(refelembyval);
+	COMPARE_SCALAR_FIELD(refelemalign);
+	COMPARE_NODE_FIELD(refupperindexpr);
+	COMPARE_NODE_FIELD(reflowerindexpr);
+	COMPARE_NODE_FIELD(refexpr);
+	COMPARE_NODE_FIELD(refassgnexpr);
+
+	return true;
+}
+
+static bool
+_equalFuncExpr(FuncExpr *a, FuncExpr *b)
 {
 	COMPARE_SCALAR_FIELD(funcid);
 	COMPARE_SCALAR_FIELD(funcresulttype);
@@ -240,20 +225,60 @@ _equalFunc(Func *a, Func *b)
 		b->funcformat != COERCE_DONTCARE)
 		return false;
 
-	/* Note we do not look at func_fcache; see notes for _equalOper */
+	COMPARE_NODE_FIELD(args);
 
 	return true;
 }
 
 static bool
-_equalAggref(Aggref *a, Aggref *b)
+_equalOpExpr(OpExpr *a, OpExpr *b)
 {
-	COMPARE_SCALAR_FIELD(aggfnoid);
-	COMPARE_SCALAR_FIELD(aggtype);
-	COMPARE_NODE_FIELD(target);
-	COMPARE_SCALAR_FIELD(aggstar);
-	COMPARE_SCALAR_FIELD(aggdistinct);
-	/* ignore aggno, which is only a private field for the executor */
+	COMPARE_SCALAR_FIELD(opno);
+	/*
+	 * Special-case opfuncid: it is allowable for it to differ if one
+	 * node contains zero and the other doesn't.  This just means that the
+	 * one node isn't as far along in the parse/plan pipeline and hasn't
+	 * had the opfuncid cache filled yet.
+	 */
+	if (a->opfuncid != b->opfuncid &&
+		a->opfuncid != 0 &&
+		b->opfuncid != 0)
+		return false;
+
+	COMPARE_SCALAR_FIELD(opresulttype);
+	COMPARE_SCALAR_FIELD(opretset);
+	COMPARE_NODE_FIELD(args);
+
+	return true;
+}
+
+static bool
+_equalDistinctExpr(DistinctExpr *a, DistinctExpr *b)
+{
+	COMPARE_SCALAR_FIELD(opno);
+	/*
+	 * Special-case opfuncid: it is allowable for it to differ if one
+	 * node contains zero and the other doesn't.  This just means that the
+	 * one node isn't as far along in the parse/plan pipeline and hasn't
+	 * had the opfuncid cache filled yet.
+	 */
+	if (a->opfuncid != b->opfuncid &&
+		a->opfuncid != 0 &&
+		b->opfuncid != 0)
+		return false;
+
+	COMPARE_SCALAR_FIELD(opresulttype);
+	COMPARE_SCALAR_FIELD(opretset);
+	COMPARE_NODE_FIELD(args);
+
+	return true;
+}
+
+static bool
+_equalBoolExpr(BoolExpr *a, BoolExpr *b)
+{
+	COMPARE_SCALAR_FIELD(boolop);
+	COMPARE_NODE_FIELD(args);
 
 	return true;
 }
@@ -270,6 +295,21 @@ _equalSubLink(SubLink *a, SubLink *b)
 	return true;
 }
 
+static bool
+_equalSubPlanExpr(SubPlanExpr *a, SubPlanExpr *b)
+{
+	COMPARE_SCALAR_FIELD(typeOid);
+	/* 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;
+}
+
 static bool
 _equalFieldSelect(FieldSelect *a, FieldSelect *b)
 {
@@ -300,66 +340,101 @@ _equalRelabelType(RelabelType *a, RelabelType *b)
 }
 
 static bool
-_equalRangeTblRef(RangeTblRef *a, RangeTblRef *b)
+_equalCaseExpr(CaseExpr *a, CaseExpr *b)
 {
-	COMPARE_SCALAR_FIELD(rtindex);
+	COMPARE_SCALAR_FIELD(casetype);
+	COMPARE_NODE_FIELD(arg);
+	COMPARE_NODE_FIELD(args);
+	COMPARE_NODE_FIELD(defresult);
 
 	return true;
 }
 
 static bool
-_equalJoinExpr(JoinExpr *a, JoinExpr *b)
+_equalCaseWhen(CaseWhen *a, CaseWhen *b)
 {
-	COMPARE_SCALAR_FIELD(jointype);
-	COMPARE_SCALAR_FIELD(isNatural);
-	COMPARE_NODE_FIELD(larg);
-	COMPARE_NODE_FIELD(rarg);
-	COMPARE_NODE_FIELD(using);
-	COMPARE_NODE_FIELD(quals);
-	COMPARE_NODE_FIELD(alias);
-	COMPARE_SCALAR_FIELD(rtindex);
+	COMPARE_NODE_FIELD(expr);
+	COMPARE_NODE_FIELD(result);
 
 	return true;
 }
 
 static bool
-_equalFromExpr(FromExpr *a, FromExpr *b)
+_equalNullTest(NullTest *a, NullTest *b)
 {
-	COMPARE_NODE_FIELD(fromlist);
-	COMPARE_NODE_FIELD(quals);
+	COMPARE_NODE_FIELD(arg);
+	COMPARE_SCALAR_FIELD(nulltesttype);
 
 	return true;
 }
 
 static bool
-_equalArrayRef(ArrayRef *a, ArrayRef *b)
+_equalBooleanTest(BooleanTest *a, BooleanTest *b)
 {
-	COMPARE_SCALAR_FIELD(refrestype);
-	COMPARE_SCALAR_FIELD(refattrlength);
-	COMPARE_SCALAR_FIELD(refelemlength);
-	COMPARE_SCALAR_FIELD(refelembyval);
-	COMPARE_SCALAR_FIELD(refelemalign);
-	COMPARE_NODE_FIELD(refupperindexpr);
-	COMPARE_NODE_FIELD(reflowerindexpr);
-	COMPARE_NODE_FIELD(refexpr);
-	COMPARE_NODE_FIELD(refassgnexpr);
+	COMPARE_NODE_FIELD(arg);
+	COMPARE_SCALAR_FIELD(booltesttype);
 
 	return true;
 }
 
+static bool
+_equalConstraintTest(ConstraintTest *a, ConstraintTest *b)
+{
+	COMPARE_NODE_FIELD(arg);
+	COMPARE_SCALAR_FIELD(testtype);
+	COMPARE_STRING_FIELD(name);
+	COMPARE_STRING_FIELD(domname);
+	COMPARE_NODE_FIELD(check_expr);
 
-/*
- * Stuff from plannodes.h
- */
+	return true;
+}
 
 static bool
-_equalSubPlan(SubPlan *a, SubPlan *b)
+_equalConstraintTestValue(ConstraintTestValue *a, ConstraintTestValue *b)
 {
-	/* should compare plans, but have to settle for comparing plan IDs */
-	COMPARE_SCALAR_FIELD(plan_id);
+	COMPARE_SCALAR_FIELD(typeId);
+	COMPARE_SCALAR_FIELD(typeMod);
 
-	COMPARE_NODE_FIELD(rtable);
-	COMPARE_NODE_FIELD(sublink);
+	return true;
+}
+
+static bool
+_equalTargetEntry(TargetEntry *a, TargetEntry *b)
+{
+	COMPARE_NODE_FIELD(resdom);
+	COMPARE_NODE_FIELD(expr);
+
+	return true;
+}
+
+static bool
+_equalRangeTblRef(RangeTblRef *a, RangeTblRef *b)
+{
+	COMPARE_SCALAR_FIELD(rtindex);
+
+	return true;
+}
+
+static bool
+_equalJoinExpr(JoinExpr *a, JoinExpr *b)
+{
+	COMPARE_SCALAR_FIELD(jointype);
+	COMPARE_SCALAR_FIELD(isNatural);
+	COMPARE_NODE_FIELD(larg);
+	COMPARE_NODE_FIELD(rarg);
+	COMPARE_NODE_FIELD(using);
+	COMPARE_NODE_FIELD(quals);
+	COMPARE_NODE_FIELD(alias);
+	COMPARE_SCALAR_FIELD(rtindex);
+
+	return true;
+}
+
+static bool
+_equalFromExpr(FromExpr *a, FromExpr *b)
+{
+	COMPARE_NODE_FIELD(fromlist);
+	COMPARE_NODE_FIELD(quals);
 
 	return true;
 }
@@ -573,6 +648,12 @@ _equalInsertDefault(InsertDefault *a, InsertDefault *b)
 	return true;
 }
 
+static bool
+_equalDomainConstraintValue(DomainConstraintValue *a, DomainConstraintValue *b)
+{
+	return true;
+}
+
 static bool
 _equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b)
 {
@@ -1340,16 +1421,6 @@ _equalDefElem(DefElem *a, DefElem *b)
 	return true;
 }
 
-static bool
-_equalTargetEntry(TargetEntry *a, TargetEntry *b)
-{
-	COMPARE_NODE_FIELD(resdom);
-	COMPARE_NODE_FIELD(fjoin);
-	COMPARE_NODE_FIELD(expr);
-
-	return true;
-}
-
 static bool
 _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
 {
@@ -1397,71 +1468,6 @@ _equalFkConstraint(FkConstraint *a, FkConstraint *b)
 	return true;
 }
 
-static bool
-_equalCaseExpr(CaseExpr *a, CaseExpr *b)
-{
-	COMPARE_SCALAR_FIELD(casetype);
-	COMPARE_NODE_FIELD(arg);
-	COMPARE_NODE_FIELD(args);
-	COMPARE_NODE_FIELD(defresult);
-
-	return true;
-}
-
-static bool
-_equalCaseWhen(CaseWhen *a, CaseWhen *b)
-{
-	COMPARE_NODE_FIELD(expr);
-	COMPARE_NODE_FIELD(result);
-
-	return true;
-}
-
-static bool
-_equalNullTest(NullTest *a, NullTest *b)
-{
-	COMPARE_NODE_FIELD(arg);
-	COMPARE_SCALAR_FIELD(nulltesttype);
-
-	return true;
-}
-
-static bool
-_equalBooleanTest(BooleanTest *a, BooleanTest *b)
-{
-	COMPARE_NODE_FIELD(arg);
-	COMPARE_SCALAR_FIELD(booltesttype);
-
-	return true;
-}
-
-static bool
-_equalConstraintTest(ConstraintTest *a, ConstraintTest *b)
-{
-	COMPARE_NODE_FIELD(arg);
-	COMPARE_SCALAR_FIELD(testtype);
-	COMPARE_STRING_FIELD(name);
-	COMPARE_STRING_FIELD(domname);
-	COMPARE_NODE_FIELD(check_expr);
-
-	return true;
-}
-
-static bool
-_equalDomainConstraintValue(DomainConstraintValue *a, DomainConstraintValue *b)
-{
-	return true;
-}
-
-static bool
-_equalConstraintTestValue(ConstraintTestValue *a, ConstraintTestValue *b)
-{
-	COMPARE_SCALAR_FIELD(typeId);
-	COMPARE_SCALAR_FIELD(typeMod);
-
-	return true;
-}
-
 
 /*
  * Stuff from pg_list.h
@@ -1519,25 +1525,21 @@ equal(void *a, void *b)
 
 	switch (nodeTag(a))
 	{
-		case T_SubPlan:
-			retval = _equalSubPlan(a, b);
-			break;
-
+		/*
+		 * PRIMITIVE NODES
+		 */
 		case T_Resdom:
 			retval = _equalResdom(a, b);
 			break;
-		case T_Fjoin:
-			retval = _equalFjoin(a, b);
+		case T_Alias:
+			retval = _equalAlias(a, b);
 			break;
-		case T_Expr:
-			retval = _equalExpr(a, b);
+		case T_RangeVar:
+			retval = _equalRangeVar(a, b);
 			break;
 		case T_Var:
 			retval = _equalVar(a, b);
 			break;
-		case T_Oper:
-			retval = _equalOper(a, b);
-			break;
 		case T_Const:
 			retval = _equalConst(a, b);
 			break;
@@ -1547,21 +1549,54 @@ equal(void *a, void *b)
 		case T_Aggref:
 			retval = _equalAggref(a, b);
 			break;
+		case T_ArrayRef:
+			retval = _equalArrayRef(a, b);
+			break;
+		case T_FuncExpr:
+			retval = _equalFuncExpr(a, b);
+			break;
+		case T_OpExpr:
+			retval = _equalOpExpr(a, b);
+			break;
+		case T_DistinctExpr:
+			retval = _equalDistinctExpr(a, b);
+			break;
+		case T_BoolExpr:
+			retval = _equalBoolExpr(a, b);
+			break;
 		case T_SubLink:
 			retval = _equalSubLink(a, b);
 			break;
-		case T_Func:
-			retval = _equalFunc(a, b);
+		case T_SubPlanExpr:
+			retval = _equalSubPlanExpr(a, b);
 			break;
 		case T_FieldSelect:
 			retval = _equalFieldSelect(a, b);
 			break;
-		case T_ArrayRef:
-			retval = _equalArrayRef(a, b);
-			break;
 		case T_RelabelType:
 			retval = _equalRelabelType(a, b);
 			break;
+		case T_CaseExpr:
+			retval = _equalCaseExpr(a, b);
+			break;
+		case T_CaseWhen:
+			retval = _equalCaseWhen(a, b);
+			break;
+		case T_NullTest:
+			retval = _equalNullTest(a, b);
+			break;
+		case T_BooleanTest:
+			retval = _equalBooleanTest(a, b);
+			break;
+		case T_ConstraintTest:
+			retval = _equalConstraintTest(a, b);
+			break;
+		case T_ConstraintTestValue:
+			retval = _equalConstraintTestValue(a, b);
+			break;
+		case T_TargetEntry:
+			retval = _equalTargetEntry(a, b);
+			break;
 		case T_RangeTblRef:
 			retval = _equalRangeTblRef(a, b);
 			break;
@@ -1572,6 +1607,9 @@ equal(void *a, void *b)
 			retval = _equalJoinExpr(a, b);
 			break;
 
+			/*
+			 * RELATION NODES
+			 */
 		case T_PathKeyItem:
 			retval = _equalPathKeyItem(a, b);
 			break;
@@ -1582,6 +1620,9 @@ equal(void *a, void *b)
 			retval = _equalJoinInfo(a, b);
 			break;
 
+			/*
+			 * LIST NODES
+			 */
 		case T_List:
 			{
 				List	   *la = (List *) a;
@@ -1612,6 +1653,9 @@ equal(void *a, void *b)
 			retval = _equalValue(a, b);
 			break;
 
+			/*
+			 * PARSE NODES
+			 */
 		case T_Query:
 			retval = _equalQuery(a, b);
 			break;
@@ -1844,12 +1888,6 @@ equal(void *a, void *b)
 		case T_SortGroupBy:
 			retval = _equalSortGroupBy(a, b);
 			break;
-		case T_Alias:
-			retval = _equalAlias(a, b);
-			break;
-		case T_RangeVar:
-			retval = _equalRangeVar(a, b);
-			break;
 		case T_RangeSubselect:
 			retval = _equalRangeSubselect(a, b);
 			break;
@@ -1871,9 +1909,6 @@ equal(void *a, void *b)
 		case T_DefElem:
 			retval = _equalDefElem(a, b);
 			break;
-		case T_TargetEntry:
-			retval = _equalTargetEntry(a, b);
-			break;
 		case T_RangeTblEntry:
 			retval = _equalRangeTblEntry(a, b);
 			break;
@@ -1884,24 +1919,6 @@ equal(void *a, void *b)
 			/* GroupClause is equivalent to SortClause */
 			retval = _equalSortClause(a, b);
 			break;
-		case T_CaseExpr:
-			retval = _equalCaseExpr(a, b);
-			break;
-		case T_CaseWhen:
-			retval = _equalCaseWhen(a, b);
-			break;
-		case T_NullTest:
-			retval = _equalNullTest(a, b);
-			break;
-		case T_BooleanTest:
-			retval = _equalBooleanTest(a, b);
-			break;
-		case T_ConstraintTest:
-			retval = _equalConstraintTest(a, b);
-			break;
-		case T_ConstraintTestValue:
-			retval = _equalConstraintTestValue(a, b);
-			break;
 		case T_FkConstraint:
 			retval = _equalFkConstraint(a, b);
 			break;
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index a97a6df2fda3d0ae366b352bc33d80f02fca31f6..de13e943d5e22f2b5023e9d8d506f25111365123 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -1,4 +1,5 @@
-/*
+/*-------------------------------------------------------------------------
+ *
  * makefuncs.c
  *	  creator functions for primitive nodes. The functions here are for
  *	  the most frequently created nodes.
@@ -8,7 +9,9 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.36 2002/11/25 21:29:36 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.37 2002/12/12 15:49:28 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
@@ -49,30 +52,9 @@ makeSimpleA_Expr(int oper, const char *name,
 	return a;
 }
 
-/*
- * makeOper -
- *	  creates an Oper node
- */
-Oper *
-makeOper(Oid opno,
-		 Oid opid,
-		 Oid opresulttype,
-		 bool opretset)
-{
-	Oper	   *oper = makeNode(Oper);
-
-	oper->opno = opno;
-	oper->opid = opid;
-	oper->opresulttype = opresulttype;
-	oper->opretset = opretset;
-	oper->op_fcache = NULL;
-	return oper;
-}
-
 /*
  * makeVar -
  *	  creates a Var node
- *
  */
 Var *
 makeVar(Index varno,
@@ -104,10 +86,10 @@ makeVar(Index varno,
 
 /*
  * makeTargetEntry -
- *	  creates a TargetEntry node(contains a Resdom)
+ *	  creates a TargetEntry node (contains a Resdom)
  */
 TargetEntry *
-makeTargetEntry(Resdom *resdom, Node *expr)
+makeTargetEntry(Resdom *resdom, Expr *expr)
 {
 	TargetEntry *rt = makeNode(TargetEntry);
 
@@ -188,6 +170,21 @@ makeNullConst(Oid consttype)
 					 typByVal);
 }
 
+/*
+ * makeBoolExpr -
+ *	  creates a BoolExpr node
+ */
+Expr *
+makeBoolExpr(BoolExprType boolop, List *args)
+{
+	BoolExpr   *b = makeNode(BoolExpr);
+
+	b->boolop = boolop;
+	b->args = args;
+
+	return (Expr *) b;
+}
+
 /*
  * makeAlias -
  *	  creates an Alias node
@@ -210,7 +207,7 @@ makeAlias(const char *aliasname, List *colnames)
  *	  creates a RelabelType node
  */
 RelabelType *
-makeRelabelType(Node *arg, Oid rtype, int32 rtypmod, CoercionForm rformat)
+makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, CoercionForm rformat)
 {
 	RelabelType *r = makeNode(RelabelType);
 
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index f2bfb0a7d2d6b0c62725c6ffa8902825f02389c2..299c910cc3bd9f349796d5d158066c8efe3516c4 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -8,12 +8,10 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/nodeFuncs.c,v 1.19 2002/09/02 02:47:02 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/nodeFuncs.c,v 1.20 2002/12/12 15:49:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-
-
 #include "postgres.h"
 
 #include "nodes/nodeFuncs.h"
@@ -21,6 +19,7 @@
 
 static bool var_is_inner(Var *var);
 
+
 /*
  * single_node -
  *	  Returns t if node corresponds to a single-noded expression
@@ -79,41 +78,15 @@ var_is_rel(Var *var)
  *****************************************************************************/
 
 /*
- * replace_opid -
- *
- *		Given a oper node, resets the opfid field with the
- *		procedure OID (regproc id).
- *
- *		Returns the modified oper node.
+ * set_opfuncid -
  *
+ *		Set the opfuncid (procedure OID) in an OpExpr node,
+ *		if it hasn't been set already.
  */
-Oper *
-replace_opid(Oper *oper)
+void
+set_opfuncid(OpExpr *opexpr)
 {
-	oper->opid = get_opcode(oper->opno);
-	oper->op_fcache = NULL;
-	return oper;
+	if (opexpr->opfuncid == InvalidOid)
+		opexpr->opfuncid = get_opcode(opexpr->opno);
+	opexpr->op_fcache = NULL;		/* XXX will go away soon */
 }
-
-/*****************************************************************************
- *		constant (CONST, PARAM) nodes
- *****************************************************************************/
-
-#ifdef NOT_USED
-/*
- * non_null -
- *		Returns t if the node is a non-null constant, e.g., if the node has a
- *		valid `constvalue' field.
- */
-bool
-non_null(Expr *c)
-{
-
-	if (IsA(c, Const) &&
-		!((Const *) c)->constisnull)
-		return true;
-	else
-		return false;
-}
-
-#endif
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 2c254001eec926522737828c579f710819e17ee2..bd44816e6fab60020e9e05814a5308382e70195b 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.186 2002/12/05 15:50:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.187 2002/12/12 15:49:28 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -99,9 +99,9 @@
 
 #define booltostr(x)  ((x) ? "true" : "false")
 
-static void _outDatum(StringInfo str, Datum value, int typlen, bool typbyval);
 static void _outNode(StringInfo str, void *obj);
 
+
 /*
  * _outToken
  *	  Convert an ordinary string (eg, an identifier) into a form that
@@ -172,196 +172,41 @@ _outOidList(StringInfo str, List *list)
 	appendStringInfoChar(str, ')');
 }
 
+/*
+ * Print the value of a Datum given its type.
+ */
 static void
-_outCreateStmt(StringInfo str, CreateStmt *node)
-{
-	WRITE_NODE_TYPE("CREATE");
-
-	WRITE_NODE_FIELD(relation);
-	WRITE_NODE_FIELD(tableElts);
-	WRITE_NODE_FIELD(inhRelations);
-	WRITE_NODE_FIELD(constraints);
-	WRITE_BOOL_FIELD(hasoids);
-	WRITE_ENUM_FIELD(oncommit, OnCommitAction);
-}
-
-static void
-_outIndexStmt(StringInfo str, IndexStmt *node)
-{
-	WRITE_NODE_TYPE("INDEX");
-
-	WRITE_STRING_FIELD(idxname);
-	WRITE_NODE_FIELD(relation);
-	WRITE_STRING_FIELD(accessMethod);
-	WRITE_NODE_FIELD(indexParams);
-	WRITE_NODE_FIELD(whereClause);
-	WRITE_NODE_FIELD(rangetable);
-	WRITE_BOOL_FIELD(unique);
-	WRITE_BOOL_FIELD(primary);
-	WRITE_BOOL_FIELD(isconstraint);
-}
-
-static void
-_outNotifyStmt(StringInfo str, NotifyStmt *node)
-{
-	WRITE_NODE_TYPE("NOTIFY");
-
-	WRITE_NODE_FIELD(relation);
-}
-
-static void
-_outSelectStmt(StringInfo str, SelectStmt *node)
-{
-	WRITE_NODE_TYPE("SELECT");
-
-	/* XXX this is pretty durn incomplete */
-	WRITE_NODE_FIELD(whereClause);
-}
-
-static void
-_outFuncCall(StringInfo str, FuncCall *node)
-{
-	WRITE_NODE_TYPE("FUNCCALL");
-
-	WRITE_NODE_FIELD(funcname);
-	WRITE_NODE_FIELD(args);
-	WRITE_BOOL_FIELD(agg_star);
-	WRITE_BOOL_FIELD(agg_distinct);
-}
-
-static void
-_outColumnDef(StringInfo str, ColumnDef *node)
-{
-	WRITE_NODE_TYPE("COLUMNDEF");
-
-	WRITE_STRING_FIELD(colname);
-	WRITE_NODE_FIELD(typename);
-	WRITE_INT_FIELD(inhcount);
-	WRITE_BOOL_FIELD(is_local);
-	WRITE_BOOL_FIELD(is_not_null);
-	WRITE_NODE_FIELD(raw_default);
-	WRITE_STRING_FIELD(cooked_default);
-	WRITE_NODE_FIELD(constraints);
-	WRITE_NODE_FIELD(support);
-}
-
-static void
-_outTypeName(StringInfo str, TypeName *node)
-{
-	WRITE_NODE_TYPE("TYPENAME");
-
-	WRITE_NODE_FIELD(names);
-	WRITE_OID_FIELD(typeid);
-	WRITE_BOOL_FIELD(timezone);
-	WRITE_BOOL_FIELD(setof);
-	WRITE_BOOL_FIELD(pct_type);
-	WRITE_INT_FIELD(typmod);
-	WRITE_NODE_FIELD(arrayBounds);
-}
-
-static void
-_outTypeCast(StringInfo str, TypeCast *node)
-{
-	WRITE_NODE_TYPE("TYPECAST");
-
-	WRITE_NODE_FIELD(arg);
-	WRITE_NODE_FIELD(typename);
-}
-
-static void
-_outIndexElem(StringInfo str, IndexElem *node)
-{
-	WRITE_NODE_TYPE("INDEXELEM");
-
-	WRITE_STRING_FIELD(name);
-	WRITE_NODE_FIELD(funcname);
-	WRITE_NODE_FIELD(args);
-	WRITE_NODE_FIELD(opclass);
-}
-
-static void
-_outQuery(StringInfo str, Query *node)
+_outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
 {
-	WRITE_NODE_TYPE("QUERY");
+	Size		length,
+				i;
+	char	   *s;
 
-	WRITE_ENUM_FIELD(commandType, CmdType);
-	WRITE_ENUM_FIELD(querySource, QuerySource);
+	length = datumGetSize(value, typbyval, typlen);
 
-	/*
-	 * Hack to work around missing outfuncs routines for a lot of the
-	 * utility-statement node types.  (The only one we actually *need* for
-	 * rules support is NotifyStmt.)  Someday we ought to support 'em all,
-	 * but for the meantime do this to avoid getting lots of warnings when
-	 * running with debug_print_parse on.
-	 */
-	if (node->utilityStmt)
+	if (typbyval)
 	{
-		switch (nodeTag(node->utilityStmt))
+		s = (char *) (&value);
+		appendStringInfo(str, "%u [ ", (unsigned int) length);
+		for (i = 0; i < (Size) sizeof(Datum); i++)
+			appendStringInfo(str, "%d ", (int) (s[i]));
+		appendStringInfo(str, "]");
+	}
+	else
+	{
+		s = (char *) DatumGetPointer(value);
+		if (!PointerIsValid(s))
+			appendStringInfo(str, "0 [ ]");
+		else
 		{
-			case T_CreateStmt:
-			case T_IndexStmt:
-			case T_NotifyStmt:
-				WRITE_NODE_FIELD(utilityStmt);
-				break;
-			default:
-				appendStringInfo(str, " :utilityStmt ?");
-				break;
+			appendStringInfo(str, "%u [ ", (unsigned int) length);
+			for (i = 0; i < length; i++)
+				appendStringInfo(str, "%d ", (int) (s[i]));
+			appendStringInfo(str, "]");
 		}
 	}
-	else
-		appendStringInfo(str, " :utilityStmt <>");
-
-	WRITE_INT_FIELD(resultRelation);
-	WRITE_NODE_FIELD(into);
-	WRITE_BOOL_FIELD(isPortal);
-	WRITE_BOOL_FIELD(isBinary);
-	WRITE_BOOL_FIELD(hasAggs);
-	WRITE_BOOL_FIELD(hasSubLinks);
-	WRITE_NODE_FIELD(rtable);
-	WRITE_NODE_FIELD(jointree);
-	WRITE_INTLIST_FIELD(rowMarks);
-	WRITE_NODE_FIELD(targetList);
-	WRITE_NODE_FIELD(groupClause);
-	WRITE_NODE_FIELD(havingQual);
-	WRITE_NODE_FIELD(distinctClause);
-	WRITE_NODE_FIELD(sortClause);
-	WRITE_NODE_FIELD(limitOffset);
-	WRITE_NODE_FIELD(limitCount);
-	WRITE_NODE_FIELD(setOperations);
-	WRITE_INTLIST_FIELD(resultRelations);
-
-	/* planner-internal fields are not written out */
-}
-
-static void
-_outSortClause(StringInfo str, SortClause *node)
-{
-	WRITE_NODE_TYPE("SORTCLAUSE");
-
-	WRITE_UINT_FIELD(tleSortGroupRef);
-	WRITE_OID_FIELD(sortop);
-}
-
-static void
-_outGroupClause(StringInfo str, GroupClause *node)
-{
-	WRITE_NODE_TYPE("GROUPCLAUSE");
-
-	WRITE_UINT_FIELD(tleSortGroupRef);
-	WRITE_OID_FIELD(sortop);
 }
 
-static void
-_outSetOperationStmt(StringInfo str, SetOperationStmt *node)
-{
-	WRITE_NODE_TYPE("SETOPERATIONSTMT");
-
-	WRITE_ENUM_FIELD(op, SetOperation);
-	WRITE_BOOL_FIELD(all);
-	WRITE_NODE_FIELD(larg);
-	WRITE_NODE_FIELD(rarg);
-	WRITE_OIDLIST_FIELD(colTypes);
-}
 
 /*
  *	Stuff from plannodes.h
@@ -631,19 +476,6 @@ _outHash(StringInfo str, Hash *node)
 	WRITE_NODE_FIELD(hashkeys);
 }
 
-static void
-_outSubPlan(StringInfo str, SubPlan *node)
-{
-	WRITE_NODE_TYPE("SUBPLAN");
-
-	WRITE_NODE_FIELD(plan);
-	WRITE_INT_FIELD(plan_id);
-	WRITE_NODE_FIELD(rtable);
-	WRITE_INTLIST_FIELD(setParam);
-	WRITE_INTLIST_FIELD(parParam);
-	WRITE_NODE_FIELD(sublink);
-}
-
 /*****************************************************************************
  *
  *	Stuff from primnodes.h.
@@ -666,58 +498,42 @@ _outResdom(StringInfo str, Resdom *node)
 }
 
 static void
-_outExpr(StringInfo str, Expr *node)
+_outAlias(StringInfo str, Alias *node)
 {
-	char	   *opstr = NULL;
-
-	WRITE_NODE_TYPE("EXPR");
-
-	WRITE_OID_FIELD(typeOid);
-
-	/* do-it-yourself enum representation */
-	switch (node->opType)
-	{
-		case OP_EXPR:
-			opstr = "op";
-			break;
-		case DISTINCT_EXPR:
-			opstr = "distinct";
-			break;
-		case FUNC_EXPR:
-			opstr = "func";
-			break;
-		case OR_EXPR:
-			opstr = "or";
-			break;
-		case AND_EXPR:
-			opstr = "and";
-			break;
-		case NOT_EXPR:
-			opstr = "not";
-			break;
-		case SUBPLAN_EXPR:
-			opstr = "subp";
-			break;
-	}
-	appendStringInfo(str, " :opType ");
-	_outToken(str, opstr);
+	WRITE_NODE_TYPE("ALIAS");
 
-	WRITE_NODE_FIELD(oper);
-	WRITE_NODE_FIELD(args);
+	WRITE_STRING_FIELD(aliasname);
+	WRITE_NODE_FIELD(colnames);
 }
 
 static void
-_outVar(StringInfo str, Var *node)
+_outRangeVar(StringInfo str, RangeVar *node)
 {
-	WRITE_NODE_TYPE("VAR");
+	WRITE_NODE_TYPE("RANGEVAR");
 
-	WRITE_UINT_FIELD(varno);
-	WRITE_INT_FIELD(varattno);
-	WRITE_OID_FIELD(vartype);
-	WRITE_INT_FIELD(vartypmod);
-	WRITE_UINT_FIELD(varlevelsup);
-	WRITE_UINT_FIELD(varnoold);
-	WRITE_INT_FIELD(varoattno);
+	/*
+	 * we deliberately ignore catalogname here, since it is presently not
+	 * semantically meaningful
+	 */
+	WRITE_STRING_FIELD(schemaname);
+	WRITE_STRING_FIELD(relname);
+	WRITE_ENUM_FIELD(inhOpt, InhOption);
+	WRITE_BOOL_FIELD(istemp);
+	WRITE_NODE_FIELD(alias);
+}
+
+static void
+_outVar(StringInfo str, Var *node)
+{
+	WRITE_NODE_TYPE("VAR");
+
+	WRITE_UINT_FIELD(varno);
+	WRITE_INT_FIELD(varattno);
+	WRITE_OID_FIELD(vartype);
+	WRITE_INT_FIELD(vartypmod);
+	WRITE_UINT_FIELD(varlevelsup);
+	WRITE_UINT_FIELD(varnoold);
+	WRITE_INT_FIELD(varoattno);
 }
 
 static void
@@ -737,6 +553,17 @@ _outConst(StringInfo str, Const *node)
 		_outDatum(str, node->constvalue, node->constlen, node->constbyval);
 }
 
+static void
+_outParam(StringInfo str, Param *node)
+{
+	WRITE_NODE_TYPE("PARAM");
+
+	WRITE_INT_FIELD(paramkind);
+	WRITE_INT_FIELD(paramid);
+	WRITE_STRING_FIELD(paramname);
+	WRITE_OID_FIELD(paramtype);
+}
+
 static void
 _outAggref(StringInfo str, Aggref *node)
 {
@@ -747,19 +574,6 @@ _outAggref(StringInfo str, Aggref *node)
 	WRITE_NODE_FIELD(target);
 	WRITE_BOOL_FIELD(aggstar);
 	WRITE_BOOL_FIELD(aggdistinct);
-	/* aggno is not saved since it is just executor state */
-}
-
-static void
-_outSubLink(StringInfo str, SubLink *node)
-{
-	WRITE_NODE_TYPE("SUBLINK");
-
-	WRITE_ENUM_FIELD(subLinkType, SubLinkType);
-	WRITE_BOOL_FIELD(useor);
-	WRITE_NODE_FIELD(lefthand);
-	WRITE_NODE_FIELD(oper);
-	WRITE_NODE_FIELD(subselect);
 }
 
 static void
@@ -779,36 +593,92 @@ _outArrayRef(StringInfo str, ArrayRef *node)
 }
 
 static void
-_outFunc(StringInfo str, Func *node)
+_outFuncExpr(StringInfo str, FuncExpr *node)
 {
-	WRITE_NODE_TYPE("FUNC");
+	WRITE_NODE_TYPE("FUNCEXPR");
 
 	WRITE_OID_FIELD(funcid);
 	WRITE_OID_FIELD(funcresulttype);
 	WRITE_BOOL_FIELD(funcretset);
 	WRITE_ENUM_FIELD(funcformat, CoercionForm);
+	WRITE_NODE_FIELD(args);
+}
+
+static void
+_outOpExpr(StringInfo str, OpExpr *node)
+{
+	WRITE_NODE_TYPE("OPEXPR");
+
+	WRITE_OID_FIELD(opno);
+	WRITE_OID_FIELD(opfuncid);
+	WRITE_OID_FIELD(opresulttype);
+	WRITE_BOOL_FIELD(opretset);
+	WRITE_NODE_FIELD(args);
 }
 
 static void
-_outOper(StringInfo str, Oper *node)
+_outDistinctExpr(StringInfo str, DistinctExpr *node)
 {
-	WRITE_NODE_TYPE("OPER");
+	WRITE_NODE_TYPE("DISTINCTEXPR");
 
 	WRITE_OID_FIELD(opno);
-	WRITE_OID_FIELD(opid);
+	WRITE_OID_FIELD(opfuncid);
 	WRITE_OID_FIELD(opresulttype);
 	WRITE_BOOL_FIELD(opretset);
+	WRITE_NODE_FIELD(args);
 }
 
 static void
-_outParam(StringInfo str, Param *node)
+_outBoolExpr(StringInfo str, BoolExpr *node)
 {
-	WRITE_NODE_TYPE("PARAM");
+	char	   *opstr = NULL;
 
-	WRITE_INT_FIELD(paramkind);
-	WRITE_INT_FIELD(paramid);
-	WRITE_STRING_FIELD(paramname);
-	WRITE_OID_FIELD(paramtype);
+	WRITE_NODE_TYPE("BOOLEXPR");
+
+	/* do-it-yourself enum representation */
+	switch (node->boolop)
+	{
+		case AND_EXPR:
+			opstr = "and";
+			break;
+		case OR_EXPR:
+			opstr = "or";
+			break;
+		case NOT_EXPR:
+			opstr = "not";
+			break;
+	}
+	appendStringInfo(str, " :boolop ");
+	_outToken(str, opstr);
+
+	WRITE_NODE_FIELD(args);
+}
+
+static void
+_outSubLink(StringInfo str, SubLink *node)
+{
+	WRITE_NODE_TYPE("SUBLINK");
+
+	WRITE_ENUM_FIELD(subLinkType, SubLinkType);
+	WRITE_BOOL_FIELD(useor);
+	WRITE_NODE_FIELD(lefthand);
+	WRITE_NODE_FIELD(oper);
+	WRITE_NODE_FIELD(subselect);
+}
+
+static void
+_outSubPlanExpr(StringInfo str, SubPlanExpr *node)
+{
+	WRITE_NODE_TYPE("SUBPLANEXPR");
+
+	WRITE_OID_FIELD(typeOid);
+	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
@@ -834,35 +704,62 @@ _outRelabelType(StringInfo str, RelabelType *node)
 }
 
 static void
-_outRangeTblRef(StringInfo str, RangeTblRef *node)
+_outCaseExpr(StringInfo str, CaseExpr *node)
 {
-	WRITE_NODE_TYPE("RANGETBLREF");
+	WRITE_NODE_TYPE("CASE");
 
-	WRITE_INT_FIELD(rtindex);
+	WRITE_OID_FIELD(casetype);
+	WRITE_NODE_FIELD(arg);
+	WRITE_NODE_FIELD(args);
+	WRITE_NODE_FIELD(defresult);
 }
 
 static void
-_outJoinExpr(StringInfo str, JoinExpr *node)
+_outCaseWhen(StringInfo str, CaseWhen *node)
 {
-	WRITE_NODE_TYPE("JOINEXPR");
+	WRITE_NODE_TYPE("WHEN");
 
-	WRITE_ENUM_FIELD(jointype, JoinType);
-	WRITE_BOOL_FIELD(isNatural);
-	WRITE_NODE_FIELD(larg);
-	WRITE_NODE_FIELD(rarg);
-	WRITE_NODE_FIELD(using);
-	WRITE_NODE_FIELD(quals);
-	WRITE_NODE_FIELD(alias);
-	WRITE_INT_FIELD(rtindex);
+	WRITE_NODE_FIELD(expr);
+	WRITE_NODE_FIELD(result);
 }
 
 static void
-_outFromExpr(StringInfo str, FromExpr *node)
+_outNullTest(StringInfo str, NullTest *node)
 {
-	WRITE_NODE_TYPE("FROMEXPR");
+	WRITE_NODE_TYPE("NULLTEST");
 
-	WRITE_NODE_FIELD(fromlist);
-	WRITE_NODE_FIELD(quals);
+	WRITE_NODE_FIELD(arg);
+	WRITE_ENUM_FIELD(nulltesttype, NullTestType);
+}
+
+static void
+_outBooleanTest(StringInfo str, BooleanTest *node)
+{
+	WRITE_NODE_TYPE("BOOLEANTEST");
+
+	WRITE_NODE_FIELD(arg);
+	WRITE_ENUM_FIELD(booltesttype, BoolTestType);
+}
+
+static void
+_outConstraintTest(StringInfo str, ConstraintTest *node)
+{
+	WRITE_NODE_TYPE("CONSTRAINTTEST");
+
+	WRITE_NODE_FIELD(arg);
+	WRITE_ENUM_FIELD(testtype, ConstraintTestType);
+	WRITE_STRING_FIELD(name);
+	WRITE_STRING_FIELD(domname);
+	WRITE_NODE_FIELD(check_expr);
+}
+
+static void
+_outConstraintTestValue(StringInfo str, ConstraintTestValue *node)
+{
+	WRITE_NODE_TYPE("CONSTRAINTTESTVALUE");
+
+	WRITE_OID_FIELD(typeId);
+	WRITE_INT_FIELD(typeMod);
 }
 
 static void
@@ -871,58 +768,47 @@ _outTargetEntry(StringInfo str, TargetEntry *node)
 	WRITE_NODE_TYPE("TARGETENTRY");
 
 	WRITE_NODE_FIELD(resdom);
-	/* fjoin not supported ... */
 	WRITE_NODE_FIELD(expr);
 }
 
 static void
-_outAlias(StringInfo str, Alias *node)
+_outRangeTblRef(StringInfo str, RangeTblRef *node)
 {
-	WRITE_NODE_TYPE("ALIAS");
+	WRITE_NODE_TYPE("RANGETBLREF");
 
-	WRITE_STRING_FIELD(aliasname);
-	WRITE_NODE_FIELD(colnames);
+	WRITE_INT_FIELD(rtindex);
 }
 
 static void
-_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
+_outJoinExpr(StringInfo str, JoinExpr *node)
 {
-	WRITE_NODE_TYPE("RTE");
+	WRITE_NODE_TYPE("JOINEXPR");
 
-	/* put alias + eref first to make dump more legible */
+	WRITE_ENUM_FIELD(jointype, JoinType);
+	WRITE_BOOL_FIELD(isNatural);
+	WRITE_NODE_FIELD(larg);
+	WRITE_NODE_FIELD(rarg);
+	WRITE_NODE_FIELD(using);
+	WRITE_NODE_FIELD(quals);
 	WRITE_NODE_FIELD(alias);
-	WRITE_NODE_FIELD(eref);
-	WRITE_ENUM_FIELD(rtekind, RTEKind);
+	WRITE_INT_FIELD(rtindex);
+}
 
-	switch (node->rtekind)
-	{
-		case RTE_RELATION:
-		case RTE_SPECIAL:
-			WRITE_OID_FIELD(relid);
-			break;
-		case RTE_SUBQUERY:
-			WRITE_NODE_FIELD(subquery);
-			break;
-		case RTE_FUNCTION:
-			WRITE_NODE_FIELD(funcexpr);
-			WRITE_NODE_FIELD(coldeflist);
-			break;
-		case RTE_JOIN:
-			WRITE_ENUM_FIELD(jointype, JoinType);
-			WRITE_NODE_FIELD(joinaliasvars);
-			break;
-		default:
-			elog(ERROR, "bogus rte kind %d", (int) node->rtekind);
-			break;
-	}
+static void
+_outFromExpr(StringInfo str, FromExpr *node)
+{
+	WRITE_NODE_TYPE("FROMEXPR");
 
-	WRITE_BOOL_FIELD(inh);
-	WRITE_BOOL_FIELD(inFromCl);
-	WRITE_BOOL_FIELD(checkForRead);
-	WRITE_BOOL_FIELD(checkForWrite);
-	WRITE_OID_FIELD(checkAsUser);
+	WRITE_NODE_FIELD(fromlist);
+	WRITE_NODE_FIELD(quals);
 }
 
+/*****************************************************************************
+ *
+ *	Stuff from relation.h.
+ *
+ *****************************************************************************/
+
 /*
  * print the basic stuff of all nodes that inherit from Path
  *
@@ -1078,39 +964,240 @@ _outJoinInfo(StringInfo str, JoinInfo *node)
 	WRITE_NODE_FIELD(jinfo_restrictinfo);
 }
 
-/*
- * Print the value of a Datum given its type.
- */
+/*****************************************************************************
+ *
+ *	Stuff from parsenodes.h.
+ *
+ *****************************************************************************/
+
 static void
-_outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
+_outCreateStmt(StringInfo str, CreateStmt *node)
 {
-	Size		length,
-				i;
-	char	   *s;
+	WRITE_NODE_TYPE("CREATE");
 
-	length = datumGetSize(value, typbyval, typlen);
+	WRITE_NODE_FIELD(relation);
+	WRITE_NODE_FIELD(tableElts);
+	WRITE_NODE_FIELD(inhRelations);
+	WRITE_NODE_FIELD(constraints);
+	WRITE_BOOL_FIELD(hasoids);
+	WRITE_ENUM_FIELD(oncommit, OnCommitAction);
+}
 
-	if (typbyval)
-	{
-		s = (char *) (&value);
-		appendStringInfo(str, "%u [ ", (unsigned int) length);
-		for (i = 0; i < (Size) sizeof(Datum); i++)
-			appendStringInfo(str, "%d ", (int) (s[i]));
-		appendStringInfo(str, "]");
-	}
-	else
+static void
+_outIndexStmt(StringInfo str, IndexStmt *node)
+{
+	WRITE_NODE_TYPE("INDEX");
+
+	WRITE_STRING_FIELD(idxname);
+	WRITE_NODE_FIELD(relation);
+	WRITE_STRING_FIELD(accessMethod);
+	WRITE_NODE_FIELD(indexParams);
+	WRITE_NODE_FIELD(whereClause);
+	WRITE_NODE_FIELD(rangetable);
+	WRITE_BOOL_FIELD(unique);
+	WRITE_BOOL_FIELD(primary);
+	WRITE_BOOL_FIELD(isconstraint);
+}
+
+static void
+_outNotifyStmt(StringInfo str, NotifyStmt *node)
+{
+	WRITE_NODE_TYPE("NOTIFY");
+
+	WRITE_NODE_FIELD(relation);
+}
+
+static void
+_outSelectStmt(StringInfo str, SelectStmt *node)
+{
+	WRITE_NODE_TYPE("SELECT");
+
+	/* XXX this is pretty durn incomplete */
+	WRITE_NODE_FIELD(whereClause);
+}
+
+static void
+_outFuncCall(StringInfo str, FuncCall *node)
+{
+	WRITE_NODE_TYPE("FUNCCALL");
+
+	WRITE_NODE_FIELD(funcname);
+	WRITE_NODE_FIELD(args);
+	WRITE_BOOL_FIELD(agg_star);
+	WRITE_BOOL_FIELD(agg_distinct);
+}
+
+static void
+_outColumnDef(StringInfo str, ColumnDef *node)
+{
+	WRITE_NODE_TYPE("COLUMNDEF");
+
+	WRITE_STRING_FIELD(colname);
+	WRITE_NODE_FIELD(typename);
+	WRITE_INT_FIELD(inhcount);
+	WRITE_BOOL_FIELD(is_local);
+	WRITE_BOOL_FIELD(is_not_null);
+	WRITE_NODE_FIELD(raw_default);
+	WRITE_STRING_FIELD(cooked_default);
+	WRITE_NODE_FIELD(constraints);
+	WRITE_NODE_FIELD(support);
+}
+
+static void
+_outTypeName(StringInfo str, TypeName *node)
+{
+	WRITE_NODE_TYPE("TYPENAME");
+
+	WRITE_NODE_FIELD(names);
+	WRITE_OID_FIELD(typeid);
+	WRITE_BOOL_FIELD(timezone);
+	WRITE_BOOL_FIELD(setof);
+	WRITE_BOOL_FIELD(pct_type);
+	WRITE_INT_FIELD(typmod);
+	WRITE_NODE_FIELD(arrayBounds);
+}
+
+static void
+_outTypeCast(StringInfo str, TypeCast *node)
+{
+	WRITE_NODE_TYPE("TYPECAST");
+
+	WRITE_NODE_FIELD(arg);
+	WRITE_NODE_FIELD(typename);
+}
+
+static void
+_outIndexElem(StringInfo str, IndexElem *node)
+{
+	WRITE_NODE_TYPE("INDEXELEM");
+
+	WRITE_STRING_FIELD(name);
+	WRITE_NODE_FIELD(funcname);
+	WRITE_NODE_FIELD(args);
+	WRITE_NODE_FIELD(opclass);
+}
+
+static void
+_outQuery(StringInfo str, Query *node)
+{
+	WRITE_NODE_TYPE("QUERY");
+
+	WRITE_ENUM_FIELD(commandType, CmdType);
+	WRITE_ENUM_FIELD(querySource, QuerySource);
+
+	/*
+	 * Hack to work around missing outfuncs routines for a lot of the
+	 * utility-statement node types.  (The only one we actually *need* for
+	 * rules support is NotifyStmt.)  Someday we ought to support 'em all,
+	 * but for the meantime do this to avoid getting lots of warnings when
+	 * running with debug_print_parse on.
+	 */
+	if (node->utilityStmt)
 	{
-		s = (char *) DatumGetPointer(value);
-		if (!PointerIsValid(s))
-			appendStringInfo(str, "0 [ ]");
-		else
+		switch (nodeTag(node->utilityStmt))
 		{
-			appendStringInfo(str, "%u [ ", (unsigned int) length);
-			for (i = 0; i < length; i++)
-				appendStringInfo(str, "%d ", (int) (s[i]));
-			appendStringInfo(str, "]");
+			case T_CreateStmt:
+			case T_IndexStmt:
+			case T_NotifyStmt:
+				WRITE_NODE_FIELD(utilityStmt);
+				break;
+			default:
+				appendStringInfo(str, " :utilityStmt ?");
+				break;
 		}
 	}
+	else
+		appendStringInfo(str, " :utilityStmt <>");
+
+	WRITE_INT_FIELD(resultRelation);
+	WRITE_NODE_FIELD(into);
+	WRITE_BOOL_FIELD(isPortal);
+	WRITE_BOOL_FIELD(isBinary);
+	WRITE_BOOL_FIELD(hasAggs);
+	WRITE_BOOL_FIELD(hasSubLinks);
+	WRITE_NODE_FIELD(rtable);
+	WRITE_NODE_FIELD(jointree);
+	WRITE_INTLIST_FIELD(rowMarks);
+	WRITE_NODE_FIELD(targetList);
+	WRITE_NODE_FIELD(groupClause);
+	WRITE_NODE_FIELD(havingQual);
+	WRITE_NODE_FIELD(distinctClause);
+	WRITE_NODE_FIELD(sortClause);
+	WRITE_NODE_FIELD(limitOffset);
+	WRITE_NODE_FIELD(limitCount);
+	WRITE_NODE_FIELD(setOperations);
+	WRITE_INTLIST_FIELD(resultRelations);
+
+	/* planner-internal fields are not written out */
+}
+
+static void
+_outSortClause(StringInfo str, SortClause *node)
+{
+	WRITE_NODE_TYPE("SORTCLAUSE");
+
+	WRITE_UINT_FIELD(tleSortGroupRef);
+	WRITE_OID_FIELD(sortop);
+}
+
+static void
+_outGroupClause(StringInfo str, GroupClause *node)
+{
+	WRITE_NODE_TYPE("GROUPCLAUSE");
+
+	WRITE_UINT_FIELD(tleSortGroupRef);
+	WRITE_OID_FIELD(sortop);
+}
+
+static void
+_outSetOperationStmt(StringInfo str, SetOperationStmt *node)
+{
+	WRITE_NODE_TYPE("SETOPERATIONSTMT");
+
+	WRITE_ENUM_FIELD(op, SetOperation);
+	WRITE_BOOL_FIELD(all);
+	WRITE_NODE_FIELD(larg);
+	WRITE_NODE_FIELD(rarg);
+	WRITE_OIDLIST_FIELD(colTypes);
+}
+
+static void
+_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
+{
+	WRITE_NODE_TYPE("RTE");
+
+	/* put alias + eref first to make dump more legible */
+	WRITE_NODE_FIELD(alias);
+	WRITE_NODE_FIELD(eref);
+	WRITE_ENUM_FIELD(rtekind, RTEKind);
+
+	switch (node->rtekind)
+	{
+		case RTE_RELATION:
+		case RTE_SPECIAL:
+			WRITE_OID_FIELD(relid);
+			break;
+		case RTE_SUBQUERY:
+			WRITE_NODE_FIELD(subquery);
+			break;
+		case RTE_FUNCTION:
+			WRITE_NODE_FIELD(funcexpr);
+			WRITE_NODE_FIELD(coldeflist);
+			break;
+		case RTE_JOIN:
+			WRITE_ENUM_FIELD(jointype, JoinType);
+			WRITE_NODE_FIELD(joinaliasvars);
+			break;
+		default:
+			elog(ERROR, "bogus rte kind %d", (int) node->rtekind);
+			break;
+	}
+
+	WRITE_BOOL_FIELD(inh);
+	WRITE_BOOL_FIELD(inFromCl);
+	WRITE_BOOL_FIELD(checkForRead);
+	WRITE_BOOL_FIELD(checkForWrite);
+	WRITE_OID_FIELD(checkAsUser);
 }
 
 static void
@@ -1174,22 +1261,6 @@ _outValue(StringInfo str, Value *value)
 	}
 }
 
-static void
-_outRangeVar(StringInfo str, RangeVar *node)
-{
-	WRITE_NODE_TYPE("RANGEVAR");
-
-	/*
-	 * we deliberately ignore catalogname here, since it is presently not
-	 * semantically meaningful
-	 */
-	WRITE_STRING_FIELD(schemaname);
-	WRITE_STRING_FIELD(relname);
-	WRITE_ENUM_FIELD(inhOpt, InhOption);
-	WRITE_BOOL_FIELD(istemp);
-	WRITE_NODE_FIELD(alias);
-}
-
 static void
 _outColumnRef(StringInfo str, ColumnRef *node)
 {
@@ -1228,6 +1299,12 @@ _outExprFieldSelect(StringInfo str, ExprFieldSelect *node)
 	WRITE_NODE_FIELD(indirection);
 }
 
+static void
+_outDomainConstraintValue(StringInfo str, DomainConstraintValue *node)
+{
+	WRITE_NODE_TYPE("DOMAINCONSTRAINTVALUE");
+}
+
 static void
 _outConstraint(StringInfo str, Constraint *node)
 {
@@ -1287,71 +1364,6 @@ _outFkConstraint(StringInfo str, FkConstraint *node)
 	WRITE_BOOL_FIELD(skip_validation);
 }
 
-static void
-_outCaseExpr(StringInfo str, CaseExpr *node)
-{
-	WRITE_NODE_TYPE("CASE");
-
-	WRITE_OID_FIELD(casetype);
-	WRITE_NODE_FIELD(arg);
-	WRITE_NODE_FIELD(args);
-	WRITE_NODE_FIELD(defresult);
-}
-
-static void
-_outCaseWhen(StringInfo str, CaseWhen *node)
-{
-	WRITE_NODE_TYPE("WHEN");
-
-	WRITE_NODE_FIELD(expr);
-	WRITE_NODE_FIELD(result);
-}
-
-static void
-_outNullTest(StringInfo str, NullTest *node)
-{
-	WRITE_NODE_TYPE("NULLTEST");
-
-	WRITE_NODE_FIELD(arg);
-	WRITE_ENUM_FIELD(nulltesttype, NullTestType);
-}
-
-static void
-_outBooleanTest(StringInfo str, BooleanTest *node)
-{
-	WRITE_NODE_TYPE("BOOLEANTEST");
-
-	WRITE_NODE_FIELD(arg);
-	WRITE_ENUM_FIELD(booltesttype, BoolTestType);
-}
-
-static void
-_outConstraintTest(StringInfo str, ConstraintTest *node)
-{
-	WRITE_NODE_TYPE("CONSTRAINTTEST");
-
-	WRITE_NODE_FIELD(arg);
-	WRITE_ENUM_FIELD(testtype, ConstraintTestType);
-	WRITE_STRING_FIELD(name);
-	WRITE_STRING_FIELD(domname);
-	WRITE_NODE_FIELD(check_expr);
-}
-
-static void
-_outDomainConstraintValue(StringInfo str, DomainConstraintValue *node)
-{
-	WRITE_NODE_TYPE("DOMAINCONSTRAINTVALUE");
-}
-
-static void
-_outConstraintTestValue(StringInfo str, ConstraintTestValue *node)
-{
-	WRITE_NODE_TYPE("CONSTRAINTTESTVALUE");
-
-	WRITE_OID_FIELD(typeId);
-	WRITE_INT_FIELD(typeMod);
-}
-
 
 /*
  * _outNode -
@@ -1392,42 +1404,6 @@ _outNode(StringInfo str, void *obj)
 		appendStringInfoChar(str, '{');
 		switch (nodeTag(obj))
 		{
-			case T_CreateStmt:
-				_outCreateStmt(str, obj);
-				break;
-			case T_IndexStmt:
-				_outIndexStmt(str, obj);
-				break;
-			case T_NotifyStmt:
-				_outNotifyStmt(str, obj);
-				break;
-			case T_SelectStmt:
-				_outSelectStmt(str, obj);
-				break;
-			case T_ColumnDef:
-				_outColumnDef(str, obj);
-				break;
-			case T_TypeName:
-				_outTypeName(str, obj);
-				break;
-			case T_TypeCast:
-				_outTypeCast(str, obj);
-				break;
-			case T_IndexElem:
-				_outIndexElem(str, obj);
-				break;
-			case T_Query:
-				_outQuery(str, obj);
-				break;
-			case T_SortClause:
-				_outSortClause(str, obj);
-				break;
-			case T_GroupClause:
-				_outGroupClause(str, obj);
-				break;
-			case T_SetOperationStmt:
-				_outSetOperationStmt(str, obj);
-				break;
 			case T_Plan:
 				_outPlan(str, obj);
 				break;
@@ -1437,18 +1413,6 @@ _outNode(StringInfo str, void *obj)
 			case T_Append:
 				_outAppend(str, obj);
 				break;
-			case T_Join:
-				_outJoin(str, obj);
-				break;
-			case T_NestLoop:
-				_outNestLoop(str, obj);
-				break;
-			case T_MergeJoin:
-				_outMergeJoin(str, obj);
-				break;
-			case T_HashJoin:
-				_outHashJoin(str, obj);
-				break;
 			case T_Scan:
 				_outScan(str, obj);
 				break;
@@ -1467,11 +1431,17 @@ _outNode(StringInfo str, void *obj)
 			case T_FunctionScan:
 				_outFunctionScan(str, obj);
 				break;
-			case T_Material:
-				_outMaterial(str, obj);
+			case T_Join:
+				_outJoin(str, obj);
 				break;
-			case T_Sort:
-				_outSort(str, obj);
+			case T_NestLoop:
+				_outNestLoop(str, obj);
+				break;
+			case T_MergeJoin:
+				_outMergeJoin(str, obj);
+				break;
+			case T_HashJoin:
+				_outHashJoin(str, obj);
 				break;
 			case T_Agg:
 				_outAgg(str, obj);
@@ -1479,6 +1449,12 @@ _outNode(StringInfo str, void *obj)
 			case T_Group:
 				_outGroup(str, obj);
 				break;
+			case T_Material:
+				_outMaterial(str, obj);
+				break;
+			case T_Sort:
+				_outSort(str, obj);
+				break;
 			case T_Unique:
 				_outUnique(str, obj);
 				break;
@@ -1491,14 +1467,14 @@ _outNode(StringInfo str, void *obj)
 			case T_Hash:
 				_outHash(str, obj);
 				break;
-			case T_SubPlan:
-				_outSubPlan(str, obj);
-				break;
 			case T_Resdom:
 				_outResdom(str, obj);
 				break;
-			case T_Expr:
-				_outExpr(str, obj);
+			case T_Alias:
+				_outAlias(str, obj);
+				break;
+			case T_RangeVar:
+				_outRangeVar(str, obj);
 				break;
 			case T_Var:
 				_outVar(str, obj);
@@ -1506,23 +1482,32 @@ _outNode(StringInfo str, void *obj)
 			case T_Const:
 				_outConst(str, obj);
 				break;
+			case T_Param:
+				_outParam(str, obj);
+				break;
 			case T_Aggref:
 				_outAggref(str, obj);
 				break;
-			case T_SubLink:
-				_outSubLink(str, obj);
-				break;
 			case T_ArrayRef:
 				_outArrayRef(str, obj);
 				break;
-			case T_Func:
-				_outFunc(str, obj);
+			case T_FuncExpr:
+				_outFuncExpr(str, obj);
 				break;
-			case T_Oper:
-				_outOper(str, obj);
+			case T_OpExpr:
+				_outOpExpr(str, obj);
 				break;
-			case T_Param:
-				_outParam(str, obj);
+			case T_DistinctExpr:
+				_outDistinctExpr(str, obj);
+				break;
+			case T_BoolExpr:
+				_outBoolExpr(str, obj);
+				break;
+			case T_SubLink:
+				_outSubLink(str, obj);
+				break;
+			case T_SubPlanExpr:
+				_outSubPlanExpr(str, obj);
 				break;
 			case T_FieldSelect:
 				_outFieldSelect(str, obj);
@@ -1530,24 +1515,37 @@ _outNode(StringInfo str, void *obj)
 			case T_RelabelType:
 				_outRelabelType(str, obj);
 				break;
-			case T_RangeTblRef:
-				_outRangeTblRef(str, obj);
+			case T_CaseExpr:
+				_outCaseExpr(str, obj);
 				break;
-			case T_FromExpr:
-				_outFromExpr(str, obj);
+			case T_CaseWhen:
+				_outCaseWhen(str, obj);
 				break;
-			case T_JoinExpr:
-				_outJoinExpr(str, obj);
+			case T_NullTest:
+				_outNullTest(str, obj);
+				break;
+			case T_BooleanTest:
+				_outBooleanTest(str, obj);
+				break;
+			case T_ConstraintTest:
+				_outConstraintTest(str, obj);
+				break;
+			case T_ConstraintTestValue:
+				_outConstraintTestValue(str, obj);
 				break;
 			case T_TargetEntry:
 				_outTargetEntry(str, obj);
 				break;
-			case T_Alias:
-				_outAlias(str, obj);
+			case T_RangeTblRef:
+				_outRangeTblRef(str, obj);
 				break;
-			case T_RangeTblEntry:
-				_outRangeTblEntry(str, obj);
+			case T_JoinExpr:
+				_outJoinExpr(str, obj);
+				break;
+			case T_FromExpr:
+				_outFromExpr(str, obj);
 				break;
+
 			case T_Path:
 				_outPath(str, obj);
 				break;
@@ -1584,12 +1582,49 @@ _outNode(StringInfo str, void *obj)
 			case T_JoinInfo:
 				_outJoinInfo(str, obj);
 				break;
+
+			case T_CreateStmt:
+				_outCreateStmt(str, obj);
+				break;
+			case T_IndexStmt:
+				_outIndexStmt(str, obj);
+				break;
+			case T_NotifyStmt:
+				_outNotifyStmt(str, obj);
+				break;
+			case T_SelectStmt:
+				_outSelectStmt(str, obj);
+				break;
+			case T_ColumnDef:
+				_outColumnDef(str, obj);
+				break;
+			case T_TypeName:
+				_outTypeName(str, obj);
+				break;
+			case T_TypeCast:
+				_outTypeCast(str, obj);
+				break;
+			case T_IndexElem:
+				_outIndexElem(str, obj);
+				break;
+			case T_Query:
+				_outQuery(str, obj);
+				break;
+			case T_SortClause:
+				_outSortClause(str, obj);
+				break;
+			case T_GroupClause:
+				_outGroupClause(str, obj);
+				break;
+			case T_SetOperationStmt:
+				_outSetOperationStmt(str, obj);
+				break;
+			case T_RangeTblEntry:
+				_outRangeTblEntry(str, obj);
+				break;
 			case T_A_Expr:
 				_outAExpr(str, obj);
 				break;
-			case T_RangeVar:
-				_outRangeVar(str, obj);
-				break;
 			case T_ColumnRef:
 				_outColumnRef(str, obj);
 				break;
@@ -1602,36 +1637,18 @@ _outNode(StringInfo str, void *obj)
 			case T_ExprFieldSelect:
 				_outExprFieldSelect(str, obj);
 				break;
+			case T_DomainConstraintValue:
+				_outDomainConstraintValue(str, obj);
+				break;
 			case T_Constraint:
 				_outConstraint(str, obj);
 				break;
 			case T_FkConstraint:
 				_outFkConstraint(str, obj);
 				break;
-			case T_CaseExpr:
-				_outCaseExpr(str, obj);
-				break;
-			case T_CaseWhen:
-				_outCaseWhen(str, obj);
-				break;
-			case T_NullTest:
-				_outNullTest(str, obj);
-				break;
-			case T_BooleanTest:
-				_outBooleanTest(str, obj);
-				break;
-			case T_ConstraintTest:
-				_outConstraintTest(str, obj);
-				break;
-			case T_ConstraintTestValue:
-				_outConstraintTestValue(str, obj);
-				break;
 			case T_FuncCall:
 				_outFuncCall(str, obj);
 				break;
-			case T_DomainConstraintValue:
-				_outDomainConstraintValue(str, obj);
-				break;
 
 			default:
 				elog(WARNING, "_outNode: don't know how to print type %d",
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index e8afda6b20835eb9abb0b7cad8a55d6b8bffe7ab..dd5186860bfe33fb37ed3427e60904ef24ec3177 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.57 2002/09/04 20:31:20 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.58 2002/12/12 15:49:28 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -371,7 +371,7 @@ print_expr(Node *expr, List *rtable)
 			char	   *opname;
 
 			print_expr((Node *) get_leftop(e), rtable);
-			opname = get_opname(((Oper *) e->oper)->opno);
+			opname = get_opname(((OpExpr *) e)->opno);
 			printf(" %s ", ((opname != NULL) ? opname : "(invalid operator)"));
 			print_expr((Node *) get_rightop(e), rtable);
 		}
@@ -432,7 +432,7 @@ print_tl(List *tlist, List *rtable)
 			printf("(%d):\t", tle->resdom->reskey);
 		else
 			printf("    :\t");
-		print_expr(tle->expr, rtable);
+		print_expr((Node *) tle->expr, rtable);
 		printf("\n");
 	}
 	printf(")\n");
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index eca2e3017b07b5e43d35baa5cbf8168f0ab9211a..bb4a565a8b54213895f102f84d9ff28240da9811 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.140 2002/11/25 21:29:38 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.141 2002/12/12 15:49:28 tgl Exp $
  *
  * NOTES
  *	  Path and Plan nodes do not have any readfuncs support, because we
@@ -302,38 +302,30 @@ _readResdom(void)
 	READ_DONE();
 }
 
-/*
- * _readExpr
- */
-static Expr *
-_readExpr(void)
+static Alias *
+_readAlias(void)
 {
-	READ_LOCALS(Expr);
+	READ_LOCALS(Alias);
 
-	READ_OID_FIELD(typeOid);
+	READ_STRING_FIELD(aliasname);
+	READ_NODE_FIELD(colnames);
 
-	/* do-it-yourself enum representation */
-	token = pg_strtok(&length); /* skip :opType */
-	token = pg_strtok(&length); /* get field value */
-	if (strncmp(token, "op", 2) == 0)
-		local_node->opType = OP_EXPR;
-	else if (strncmp(token, "distinct", 8) == 0)
-		local_node->opType = DISTINCT_EXPR;
-	else if (strncmp(token, "func", 4) == 0)
-		local_node->opType = FUNC_EXPR;
-	else if (strncmp(token, "or", 2) == 0)
-		local_node->opType = OR_EXPR;
-	else if (strncmp(token, "and", 3) == 0)
-		local_node->opType = AND_EXPR;
-	else if (strncmp(token, "not", 3) == 0)
-		local_node->opType = NOT_EXPR;
-	else if (strncmp(token, "subp", 4) == 0)
-		local_node->opType = SUBPLAN_EXPR;
-	else
-		elog(ERROR, "_readExpr: unknown opType \"%.*s\"", length, token);
+	READ_DONE();
+}
 
-	READ_NODE_FIELD(oper);
-	READ_NODE_FIELD(args);
+static RangeVar *
+_readRangeVar(void)
+{
+	READ_LOCALS(RangeVar);
+
+	local_node->catalogname = NULL;		/* not currently saved in output
+										 * format */
+
+	READ_STRING_FIELD(schemaname);
+	READ_STRING_FIELD(relname);
+	READ_ENUM_FIELD(inhOpt, InhOption);
+	READ_BOOL_FIELD(istemp);
+	READ_NODE_FIELD(alias);
 
 	READ_DONE();
 }
@@ -357,27 +349,6 @@ _readVar(void)
 	READ_DONE();
 }
 
-/*
- * _readArrayRef
- */
-static ArrayRef *
-_readArrayRef(void)
-{
-	READ_LOCALS(ArrayRef);
-
-	READ_OID_FIELD(refrestype);
-	READ_INT_FIELD(refattrlength);
-	READ_INT_FIELD(refelemlength);
-	READ_BOOL_FIELD(refelembyval);
-	READ_CHAR_FIELD(refelemalign);
-	READ_NODE_FIELD(refupperindexpr);
-	READ_NODE_FIELD(reflowerindexpr);
-	READ_NODE_FIELD(refexpr);
-	READ_NODE_FIELD(refassgnexpr);
-
-	READ_DONE();
-}
-
 /*
  * _readConst
  */
@@ -401,17 +372,72 @@ _readConst(void)
 }
 
 /*
- * _readFunc
+ * _readParam
+ */
+static Param *
+_readParam(void)
+{
+	READ_LOCALS(Param);
+
+	READ_INT_FIELD(paramkind);
+	READ_INT_FIELD(paramid);
+	READ_STRING_FIELD(paramname);
+	READ_OID_FIELD(paramtype);
+
+	READ_DONE();
+}
+
+/*
+ * _readAggref
+ */
+static Aggref *
+_readAggref(void)
+{
+	READ_LOCALS(Aggref);
+
+	READ_OID_FIELD(aggfnoid);
+	READ_OID_FIELD(aggtype);
+	READ_NODE_FIELD(target);
+	READ_BOOL_FIELD(aggstar);
+	READ_BOOL_FIELD(aggdistinct);
+
+	READ_DONE();
+}
+
+/*
+ * _readArrayRef
  */
-static Func *
-_readFunc(void)
+static ArrayRef *
+_readArrayRef(void)
 {
-	READ_LOCALS(Func);
+	READ_LOCALS(ArrayRef);
+
+	READ_OID_FIELD(refrestype);
+	READ_INT_FIELD(refattrlength);
+	READ_INT_FIELD(refelemlength);
+	READ_BOOL_FIELD(refelembyval);
+	READ_CHAR_FIELD(refelemalign);
+	READ_NODE_FIELD(refupperindexpr);
+	READ_NODE_FIELD(reflowerindexpr);
+	READ_NODE_FIELD(refexpr);
+	READ_NODE_FIELD(refassgnexpr);
+
+	READ_DONE();
+}
+
+/*
+ * _readFuncExpr
+ */
+static FuncExpr *
+_readFuncExpr(void)
+{
+	READ_LOCALS(FuncExpr);
 
 	READ_OID_FIELD(funcid);
 	READ_OID_FIELD(funcresulttype);
 	READ_BOOL_FIELD(funcretset);
 	READ_ENUM_FIELD(funcformat, CoercionForm);
+	READ_NODE_FIELD(args);
 
 	local_node->func_fcache = NULL;
 
@@ -419,17 +445,28 @@ _readFunc(void)
 }
 
 /*
- * _readOper
+ * _readOpExpr
  */
-static Oper *
-_readOper(void)
+static OpExpr *
+_readOpExpr(void)
 {
-	READ_LOCALS(Oper);
+	READ_LOCALS(OpExpr);
 
 	READ_OID_FIELD(opno);
-	READ_OID_FIELD(opid);
+	READ_OID_FIELD(opfuncid);
+	/*
+	 * The opfuncid is stored in the textual format primarily for debugging
+	 * and documentation reasons.  We want to always read it as zero to force
+	 * it to be re-looked-up in the pg_operator entry.  This ensures that
+	 * stored rules don't have hidden dependencies on operators' functions.
+	 * (We don't currently support an ALTER OPERATOR command, but might
+	 * someday.)
+	 */
+	local_node->opfuncid = InvalidOid;
+
 	READ_OID_FIELD(opresulttype);
 	READ_BOOL_FIELD(opretset);
+	READ_NODE_FIELD(args);
 
 	local_node->op_fcache = NULL;
 
@@ -437,52 +474,55 @@ _readOper(void)
 }
 
 /*
- * _readParam
+ * _readDistinctExpr
  */
-static Param *
-_readParam(void)
+static DistinctExpr *
+_readDistinctExpr(void)
 {
-	READ_LOCALS(Param);
-
-	READ_INT_FIELD(paramkind);
-	READ_INT_FIELD(paramid);
-	READ_STRING_FIELD(paramname);
-	READ_OID_FIELD(paramtype);
+	READ_LOCALS(DistinctExpr);
 
-	READ_DONE();
-}
+	READ_OID_FIELD(opno);
+	READ_OID_FIELD(opfuncid);
+	/*
+	 * The opfuncid is stored in the textual format primarily for debugging
+	 * and documentation reasons.  We want to always read it as zero to force
+	 * it to be re-looked-up in the pg_operator entry.  This ensures that
+	 * stored rules don't have hidden dependencies on operators' functions.
+	 * (We don't currently support an ALTER OPERATOR command, but might
+	 * someday.)
+	 */
+	local_node->opfuncid = InvalidOid;
 
-/*
- * _readAggref
- */
-static Aggref *
-_readAggref(void)
-{
-	READ_LOCALS(Aggref);
+	READ_OID_FIELD(opresulttype);
+	READ_BOOL_FIELD(opretset);
+	READ_NODE_FIELD(args);
 
-	READ_OID_FIELD(aggfnoid);
-	READ_OID_FIELD(aggtype);
-	READ_NODE_FIELD(target);
-	READ_BOOL_FIELD(aggstar);
-	READ_BOOL_FIELD(aggdistinct);
-	/* aggno is not saved since it is just executor state */
+	local_node->op_fcache = NULL;
 
 	READ_DONE();
 }
 
-static RangeVar *
-_readRangeVar(void)
+/*
+ * _readBoolExpr
+ */
+static BoolExpr *
+_readBoolExpr(void)
 {
-	READ_LOCALS(RangeVar);
+	READ_LOCALS(BoolExpr);
 
-	local_node->catalogname = NULL;		/* not currently saved in output
-										 * format */
+	/* do-it-yourself enum representation */
+	token = pg_strtok(&length); /* skip :boolop */
+	token = pg_strtok(&length); /* get field value */
+	if (strncmp(token, "and", 3) == 0)
+		local_node->boolop = AND_EXPR;
+	else if (strncmp(token, "or", 2) == 0)
+		local_node->boolop = OR_EXPR;
+	else if (strncmp(token, "not", 3) == 0)
+		local_node->boolop = NOT_EXPR;
+	else
+		elog(ERROR, "_readBoolExpr: unknown boolop \"%.*s\"", length, token);
 
-	READ_STRING_FIELD(schemaname);
-	READ_STRING_FIELD(relname);
-	READ_ENUM_FIELD(inhOpt, InhOption);
-	READ_BOOL_FIELD(istemp);
-	READ_NODE_FIELD(alias);
+	READ_NODE_FIELD(args);
 
 	READ_DONE();
 }
@@ -504,6 +544,10 @@ _readSubLink(void)
 	READ_DONE();
 }
 
+/*
+ * _readSubPlanExpr is not needed since it doesn't appear in stored rules.
+ */
+
 /*
  * _readFieldSelect
  */
@@ -536,58 +580,6 @@ _readRelabelType(void)
 	READ_DONE();
 }
 
-/*
- * _readRangeTblRef
- */
-static RangeTblRef *
-_readRangeTblRef(void)
-{
-	READ_LOCALS(RangeTblRef);
-
-	READ_INT_FIELD(rtindex);
-
-	READ_DONE();
-}
-
-/*
- * _readJoinExpr
- */
-static JoinExpr *
-_readJoinExpr(void)
-{
-	READ_LOCALS(JoinExpr);
-
-	READ_ENUM_FIELD(jointype, JoinType);
-	READ_BOOL_FIELD(isNatural);
-	READ_NODE_FIELD(larg);
-	READ_NODE_FIELD(rarg);
-	READ_NODE_FIELD(using);
-	READ_NODE_FIELD(quals);
-	READ_NODE_FIELD(alias);
-	READ_INT_FIELD(rtindex);
-
-	READ_DONE();
-}
-
-/*
- * _readFromExpr
- */
-static FromExpr *
-_readFromExpr(void)
-{
-	READ_LOCALS(FromExpr);
-
-	READ_NODE_FIELD(fromlist);
-	READ_NODE_FIELD(quals);
-
-	READ_DONE();
-}
-
-
-/*
- *	Stuff from parsenodes.h.
- */
-
 /*
  * _readCaseExpr
  */
@@ -663,17 +655,6 @@ _readConstraintTest(void)
 	READ_DONE();
 }
 
-/*
- * _readDomainConstraintValue
- */
-static DomainConstraintValue *
-_readDomainConstraintValue(void)
-{
-	READ_LOCALS_NO_FIELDS(DomainConstraintValue);
-
-	READ_DONE();
-}
-
 /*
  * _readConstraintTestValue
  */
@@ -697,12 +678,63 @@ _readTargetEntry(void)
 	READ_LOCALS(TargetEntry);
 
 	READ_NODE_FIELD(resdom);
-	/* fjoin not supported ... */
 	READ_NODE_FIELD(expr);
 
 	READ_DONE();
 }
 
+/*
+ * _readRangeTblRef
+ */
+static RangeTblRef *
+_readRangeTblRef(void)
+{
+	READ_LOCALS(RangeTblRef);
+
+	READ_INT_FIELD(rtindex);
+
+	READ_DONE();
+}
+
+/*
+ * _readJoinExpr
+ */
+static JoinExpr *
+_readJoinExpr(void)
+{
+	READ_LOCALS(JoinExpr);
+
+	READ_ENUM_FIELD(jointype, JoinType);
+	READ_BOOL_FIELD(isNatural);
+	READ_NODE_FIELD(larg);
+	READ_NODE_FIELD(rarg);
+	READ_NODE_FIELD(using);
+	READ_NODE_FIELD(quals);
+	READ_NODE_FIELD(alias);
+	READ_INT_FIELD(rtindex);
+
+	READ_DONE();
+}
+
+/*
+ * _readFromExpr
+ */
+static FromExpr *
+_readFromExpr(void)
+{
+	READ_LOCALS(FromExpr);
+
+	READ_NODE_FIELD(fromlist);
+	READ_NODE_FIELD(quals);
+
+	READ_DONE();
+}
+
+
+/*
+ *	Stuff from parsenodes.h.
+ */
+
 static ColumnRef *
 _readColumnRef(void)
 {
@@ -760,13 +792,13 @@ _readExprFieldSelect(void)
 	READ_DONE();
 }
 
-static Alias *
-_readAlias(void)
+/*
+ * _readDomainConstraintValue
+ */
+static DomainConstraintValue *
+_readDomainConstraintValue(void)
 {
-	READ_LOCALS(Alias);
-
-	READ_STRING_FIELD(aliasname);
-	READ_NODE_FIELD(colnames);
+	READ_LOCALS_NO_FIELDS(DomainConstraintValue);
 
 	READ_DONE();
 }
@@ -835,53 +867,7 @@ parseNodeString(void)
 #define MATCH(tokname, namelen) \
 	(length == namelen && strncmp(token, tokname, namelen) == 0)
 
-	if (MATCH("AGGREF", 6))
-		return_value = _readAggref();
-	else if (MATCH("SUBLINK", 7))
-		return_value = _readSubLink();
-	else if (MATCH("FIELDSELECT", 11))
-		return_value = _readFieldSelect();
-	else if (MATCH("RELABELTYPE", 11))
-		return_value = _readRelabelType();
-	else if (MATCH("RANGETBLREF", 11))
-		return_value = _readRangeTblRef();
-	else if (MATCH("FROMEXPR", 8))
-		return_value = _readFromExpr();
-	else if (MATCH("JOINEXPR", 8))
-		return_value = _readJoinExpr();
-	else if (MATCH("RESDOM", 6))
-		return_value = _readResdom();
-	else if (MATCH("EXPR", 4))
-		return_value = _readExpr();
-	else if (MATCH("ARRAYREF", 8))
-		return_value = _readArrayRef();
-	else if (MATCH("VAR", 3))
-		return_value = _readVar();
-	else if (MATCH("CONST", 5))
-		return_value = _readConst();
-	else if (MATCH("FUNC", 4))
-		return_value = _readFunc();
-	else if (MATCH("OPER", 4))
-		return_value = _readOper();
-	else if (MATCH("PARAM", 5))
-		return_value = _readParam();
-	else if (MATCH("TARGETENTRY", 11))
-		return_value = _readTargetEntry();
-	else if (MATCH("RANGEVAR", 8))
-		return_value = _readRangeVar();
-	else if (MATCH("COLUMNREF", 9))
-		return_value = _readColumnRef();
-	else if (MATCH("COLUMNDEF", 9))
-		return_value = _readColumnDef();
-	else if (MATCH("TYPENAME", 8))
-		return_value = _readTypeName();
-	else if (MATCH("EXPRFIELDSELECT", 15))
-		return_value = _readExprFieldSelect();
-	else if (MATCH("ALIAS", 5))
-		return_value = _readAlias();
-	else if (MATCH("RTE", 3))
-		return_value = _readRangeTblEntry();
-	else if (MATCH("QUERY", 5))
+	if (MATCH("QUERY", 5))
 		return_value = _readQuery();
 	else if (MATCH("NOTIFY", 6))
 		return_value = _readNotifyStmt();
@@ -891,6 +877,36 @@ parseNodeString(void)
 		return_value = _readGroupClause();
 	else if (MATCH("SETOPERATIONSTMT", 16))
 		return_value = _readSetOperationStmt();
+	else if (MATCH("RESDOM", 6))
+		return_value = _readResdom();
+	else if (MATCH("ALIAS", 5))
+		return_value = _readAlias();
+	else if (MATCH("RANGEVAR", 8))
+		return_value = _readRangeVar();
+	else if (MATCH("VAR", 3))
+		return_value = _readVar();
+	else if (MATCH("CONST", 5))
+		return_value = _readConst();
+	else if (MATCH("PARAM", 5))
+		return_value = _readParam();
+	else if (MATCH("AGGREF", 6))
+		return_value = _readAggref();
+	else if (MATCH("ARRAYREF", 8))
+		return_value = _readArrayRef();
+	else if (MATCH("FUNCEXPR", 8))
+		return_value = _readFuncExpr();
+	else if (MATCH("OPEXPR", 6))
+		return_value = _readOpExpr();
+	else if (MATCH("DISTINCTEXPR", 12))
+		return_value = _readDistinctExpr();
+	else if (MATCH("BOOLEXPR", 8))
+		return_value = _readBoolExpr();
+	else if (MATCH("SUBLINK", 7))
+		return_value = _readSubLink();
+	else if (MATCH("FIELDSELECT", 11))
+		return_value = _readFieldSelect();
+	else if (MATCH("RELABELTYPE", 11))
+		return_value = _readRelabelType();
 	else if (MATCH("CASE", 4))
 		return_value = _readCaseExpr();
 	else if (MATCH("WHEN", 4))
@@ -901,10 +917,28 @@ parseNodeString(void)
 		return_value = _readBooleanTest();
 	else if (MATCH("CONSTRAINTTEST", 14))
 		return_value = _readConstraintTest();
-	else if (MATCH("DOMAINCONSTRAINTVALUE", 21))
-		return_value = _readDomainConstraintValue();
 	else if (MATCH("CONSTRAINTTESTVALUE", 19))
 		return_value = _readConstraintTestValue();
+	else if (MATCH("TARGETENTRY", 11))
+		return_value = _readTargetEntry();
+	else if (MATCH("RANGETBLREF", 11))
+		return_value = _readRangeTblRef();
+	else if (MATCH("JOINEXPR", 8))
+		return_value = _readJoinExpr();
+	else if (MATCH("FROMEXPR", 8))
+		return_value = _readFromExpr();
+	else if (MATCH("COLUMNREF", 9))
+		return_value = _readColumnRef();
+	else if (MATCH("COLUMNDEF", 9))
+		return_value = _readColumnDef();
+	else if (MATCH("TYPENAME", 8))
+		return_value = _readTypeName();
+	else if (MATCH("EXPRFIELDSELECT", 15))
+		return_value = _readExprFieldSelect();
+	else if (MATCH("DOMAINCONSTRAINTVALUE", 21))
+		return_value = _readDomainConstraintValue();
+	else if (MATCH("RTE", 3))
+		return_value = _readRangeTblEntry();
 	else
 	{
 		elog(ERROR, "badly formatted node string \"%.32s\"...", token);
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index d0976ca4219b866e37eaa68b88d760c904294659..0294c828124e4ea9ee07a1337264e3105c8450bc 100644
--- a/src/backend/optimizer/path/clausesel.c
+++ b/src/backend/optimizer/path/clausesel.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.53 2002/11/25 21:29:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.54 2002/12/12 15:49:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -141,7 +141,7 @@ clauselist_selectivity(Query *root,
 		if (is_opclause(clause) &&
 			(varRelid != 0 || NumRelids(clause) == 1))
 		{
-			Expr	   *expr = (Expr *) clause;
+			OpExpr	   *expr = (OpExpr *) clause;
 
 			if (length(expr->args) == 2)
 			{
@@ -151,7 +151,7 @@ clauselist_selectivity(Query *root,
 					(varonleft = false,
 					 is_pseudo_constant_clause(lfirst(expr->args))))
 				{
-					Oid			opno = ((Oper *) expr->oper)->opno;
+					Oid			opno = expr->opno;
 					RegProcedure oprrest = get_oprrest(opno);
 
 					s2 = restriction_selectivity(root, opno,
@@ -430,7 +430,7 @@ clause_selectivity(Query *root,
 	{
 		/* share code with clauselist_selectivity() */
 		s1 = clauselist_selectivity(root,
-									((Expr *) clause)->args,
+									((BoolExpr *) clause)->args,
 									varRelid);
 	}
 	else if (or_clause(clause))
@@ -443,7 +443,7 @@ clause_selectivity(Query *root,
 		List	   *arg;
 
 		s1 = 0.0;
-		foreach(arg, ((Expr *) clause)->args)
+		foreach(arg, ((BoolExpr *) clause)->args)
 		{
 			Selectivity s2 = clause_selectivity(root,
 												(Node *) lfirst(arg),
@@ -454,7 +454,7 @@ clause_selectivity(Query *root,
 	}
 	else if (is_opclause(clause))
 	{
-		Oid			opno = ((Oper *) ((Expr *) clause)->oper)->opno;
+		Oid			opno = ((OpExpr *) clause)->opno;
 		bool		is_join_clause;
 
 		if (varRelid != 0)
@@ -479,13 +479,14 @@ clause_selectivity(Query *root,
 		{
 			/* Estimate selectivity for a join clause. */
 			s1 = join_selectivity(root, opno,
-								  ((Expr *) clause)->args);
+								  ((OpExpr *) clause)->args);
 		}
 		else
 		{
 			/* Estimate selectivity for a restriction clause. */
 			s1 = restriction_selectivity(root, opno,
-									  ((Expr *) clause)->args, varRelid);
+										 ((OpExpr *) clause)->args,
+										 varRelid);
 		}
 	}
 	else if (is_funcclause(clause))
@@ -509,7 +510,7 @@ clause_selectivity(Query *root,
 		/* Use node specific selectivity calculation function */
 		s1 = nulltestsel(root,
 						 ((NullTest *) clause)->nulltesttype,
-						 ((NullTest *) clause)->arg,
+						 (Node *) ((NullTest *) clause)->arg,
 						 varRelid);
 	}
 	else if (IsA(clause, BooleanTest))
@@ -517,14 +518,14 @@ clause_selectivity(Query *root,
 		/* Use node specific selectivity calculation function */
 		s1 = booltestsel(root,
 						 ((BooleanTest *) clause)->booltesttype,
-						 ((BooleanTest *) clause)->arg,
+						 (Node *) ((BooleanTest *) clause)->arg,
 						 varRelid);
 	}
 	else if (IsA(clause, RelabelType))
 	{
 		/* Not sure this case is needed, but it can't hurt */
 		s1 = clause_selectivity(root,
-								((RelabelType *) clause)->arg,
+								(Node *) ((RelabelType *) clause)->arg,
 								varRelid);
 	}
 
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 1db310fc52e763221ddadf5e2030551a93b25649..2125ff034f3644f52f80b6cedf810d06042b1a79 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.93 2002/11/30 05:21:02 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.94 2002/12/12 15:49:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1220,63 +1220,48 @@ cost_qual_eval_walker(Node *node, Cost *total)
 	 * Should we try to account for the possibility of short-circuit
 	 * evaluation of AND/OR?
 	 */
-	if (IsA(node, Expr))
+	if (IsA(node, FuncExpr) ||
+		IsA(node, OpExpr) ||
+		IsA(node, DistinctExpr))
+		*total += cpu_operator_cost;
+	else if (IsA(node, SubPlanExpr))
 	{
-		Expr	   *expr = (Expr *) node;
+		/*
+		 * A subplan node in an expression indicates that the
+		 * subplan will be executed on each evaluation, so charge
+		 * accordingly. (We assume that sub-selects that can be
+		 * executed as InitPlans have already been removed from
+		 * the expression.)
+		 *
+		 * NOTE: this logic should agree with the estimates used by
+		 * make_subplan() in plan/subselect.c.
+		 */
+		SubPlanExpr *subplan = (SubPlanExpr *) node;
+		Plan	   *plan = subplan->plan;
+		Cost		subcost;
 
-		switch (expr->opType)
+		if (subplan->sublink->subLinkType == EXISTS_SUBLINK)
 		{
-			case OP_EXPR:
-			case DISTINCT_EXPR:
-			case FUNC_EXPR:
-				*total += cpu_operator_cost;
-				break;
-			case OR_EXPR:
-			case AND_EXPR:
-			case NOT_EXPR:
-				break;
-			case SUBPLAN_EXPR:
-
-				/*
-				 * A subplan node in an expression indicates that the
-				 * subplan will be executed on each evaluation, so charge
-				 * accordingly. (We assume that sub-selects that can be
-				 * executed as InitPlans have already been removed from
-				 * the expression.)
-				 *
-				 * NOTE: this logic should agree with the estimates used by
-				 * make_subplan() in plan/subselect.c.
-				 */
-				{
-					SubPlan    *subplan = (SubPlan *) expr->oper;
-					Plan	   *plan = subplan->plan;
-					Cost		subcost;
-
-					if (subplan->sublink->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)
-					{
-						/* assume we need 50% of the tuples */
-						subcost = plan->startup_cost +
-							0.50 * (plan->total_cost - plan->startup_cost);
-						/* XXX what if subplan has been materialized? */
-					}
-					else
-					{
-						/* assume we need all tuples */
-						subcost = plan->total_cost;
-					}
-					*total += subcost;
-				}
-				break;
+			/* we only need to fetch 1 tuple */
+			subcost = plan->startup_cost +
+				(plan->total_cost - plan->startup_cost) / plan->plan_rows;
 		}
-		/* fall through to examine args of Expr node */
+		else if (subplan->sublink->subLinkType == ALL_SUBLINK ||
+				 subplan->sublink->subLinkType == ANY_SUBLINK)
+		{
+			/* assume we need 50% of the tuples */
+			subcost = plan->startup_cost +
+				0.50 * (plan->total_cost - plan->startup_cost);
+			/* XXX what if subplan has been materialized? */
+		}
+		else
+		{
+			/* assume we need all tuples */
+			subcost = plan->total_cost;
+		}
+		*total += subcost;
 	}
+
 	return expression_tree_walker(node, cost_qual_eval_walker,
 								  (void *) total);
 }
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index c0241bb9ef3665976fd20b4d4b3d0ed892955f71..7a20de8c1c1bc0a1b29aa6fcb8a5f42bf42e29b8 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.126 2002/11/25 21:29:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.127 2002/12/12 15:49:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,6 +73,8 @@ static bool match_clause_to_indexkey(RelOptInfo *rel, IndexOptInfo *index,
 									 int indexkey, Oid opclass, Expr *clause);
 static bool match_join_clause_to_indexkey(RelOptInfo *rel, IndexOptInfo *index,
 						 int indexkey, Oid opclass, Expr *clause);
+static Oid indexable_operator(Expr *clause, Oid opclass,
+				   bool indexkey_on_left);
 static bool pred_test(List *predicate_list, List *restrictinfo_list,
 		  List *joininfo_list, int relvarno);
 static bool pred_test_restrict_list(Expr *predicate, List *restrictinfo_list);
@@ -280,7 +282,7 @@ match_index_orclauses(RelOptInfo *rel,
 			 */
 			restrictinfo->subclauseindices =
 				match_index_orclause(rel, index,
-									 restrictinfo->clause->args,
+									 ((BoolExpr *) restrictinfo->clause)->args,
 									 restrictinfo->subclauseindices);
 		}
 	}
@@ -377,7 +379,7 @@ match_or_subclause_to_indexkey(RelOptInfo *rel,
 	{
 		List	   *item;
 
-		foreach(item, clause->args)
+		foreach(item, ((BoolExpr *) clause)->args)
 		{
 			if (match_clause_to_indexkey(rel, index, indexkey, opclass,
 										 lfirst(item)))
@@ -443,7 +445,7 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
 
 		if (and_clause((Node *) orsubclause))
 		{
-			foreach(item, orsubclause->args)
+			foreach(item, ((BoolExpr *) orsubclause)->args)
 			{
 				Expr	   *subsubclause = (Expr *) lfirst(item);
 
@@ -715,7 +717,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
 			   *rightop;
 
 	/* Clause must be a binary opclause. */
-	if (!is_opclause((Node *) clause))
+	if (!is_opclause(clause))
 		return false;
 	leftop = get_leftop(clause);
 	rightop = get_rightop(clause);
@@ -803,7 +805,7 @@ match_join_clause_to_indexkey(RelOptInfo *rel,
 			   *rightop;
 
 	/* Clause must be a binary opclause. */
-	if (!is_opclause((Node *) clause))
+	if (!is_opclause(clause))
 		return false;
 	leftop = get_leftop(clause);
 	rightop = get_rightop(clause);
@@ -857,10 +859,10 @@ match_join_clause_to_indexkey(RelOptInfo *rel,
  * (Formerly, this routine might return a binary-compatible operator
  * rather than the original one, but that kluge is history.)
  */
-Oid
+static Oid
 indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
 {
-	Oid			expr_op = ((Oper *) clause->oper)->opno;
+	Oid			expr_op = ((OpExpr *) clause)->opno;
 	Oid			commuted_op;
 
 	/* Get the commuted operator if necessary */
@@ -985,7 +987,7 @@ pred_test_recurse_clause(Expr *predicate, Node *clause)
 	Assert(clause != NULL);
 	if (or_clause(clause))
 	{
-		items = ((Expr *) clause)->args;
+		items = ((BoolExpr *) clause)->args;
 		foreach(item, items)
 		{
 			/* if any OR item doesn't imply the predicate, clause doesn't */
@@ -996,7 +998,7 @@ pred_test_recurse_clause(Expr *predicate, Node *clause)
 	}
 	else if (and_clause(clause))
 	{
-		items = ((Expr *) clause)->args;
+		items = ((BoolExpr *) clause)->args;
 		foreach(item, items)
 		{
 			/*
@@ -1029,7 +1031,7 @@ pred_test_recurse_pred(Expr *predicate, Node *clause)
 	Assert(predicate != NULL);
 	if (or_clause((Node *) predicate))
 	{
-		items = predicate->args;
+		items = ((BoolExpr *) predicate)->args;
 		foreach(item, items)
 		{
 			/* if any item is implied, the whole predicate is implied */
@@ -1040,7 +1042,7 @@ pred_test_recurse_pred(Expr *predicate, Node *clause)
 	}
 	else if (and_clause((Node *) predicate))
 	{
-		items = predicate->args;
+		items = ((BoolExpr *) predicate)->args;
 		foreach(item, items)
 		{
 			/*
@@ -1121,7 +1123,6 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
 	StrategyNumber pred_strategy = 0,
 				clause_strategy,
 				test_strategy;
-	Oper	   *test_oper;
 	Expr	   *test_expr;
 	Datum		test_result;
 	bool		isNull;
@@ -1140,7 +1141,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
 	 * Can't do anything more unless they are both binary opclauses with a
 	 * Var on the left and a Const on the right.
 	 */
-	if (!is_opclause((Node *) predicate))
+	if (!is_opclause(predicate))
 		return false;
 	pred_var = (Var *) get_leftop(predicate);
 	pred_const = (Const *) get_rightop(predicate);
@@ -1167,8 +1168,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
 		return false;
 
 	/* Get the operators for the two clauses we're comparing */
-	pred_op = ((Oper *) ((Expr *) predicate)->oper)->opno;
-	clause_op = ((Oper *) ((Expr *) clause)->oper)->opno;
+	pred_op = ((OpExpr *) predicate)->opno;
+	clause_op = ((OpExpr *) clause)->opno;
 
 	/*
 	 * 1. Find a "btree" strategy number for the pred_op
@@ -1267,14 +1268,12 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
 	/*
 	 * 5. Evaluate the test
 	 */
-	test_oper = makeOper(test_op,		/* opno */
-						 InvalidOid,	/* opid */
-						 BOOLOID,		/* opresulttype */
-						 false);	/* opretset */
-	replace_opid(test_oper);
-	test_expr = make_opclause(test_oper,
-							  (Var *) clause_const,
-							  (Var *) pred_const);
+	test_expr = make_opclause(test_op,
+							  BOOLOID,
+							  false,
+							  (Expr *) clause_const,
+							  (Expr *) pred_const);
+	set_opfuncid((OpExpr *) test_expr);
 
 	econtext = MakeExprContext(NULL, TransactionCommandContext);
 	test_result = ExecEvalExprSwitchContext((Node *) test_expr, econtext,
@@ -1627,7 +1626,7 @@ static bool
 function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index)
 {
 	int			relvarno = lfirsti(rel->relids);
-	Func	   *function;
+	FuncExpr   *function;
 	List	   *funcargs;
 	int		   *indexKeys = index->indexkeys;
 	List	   *arg;
@@ -1636,13 +1635,12 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index)
 	/*
 	 * sanity check, make sure we know what we're dealing with here.
 	 */
-	if (funcOpnd == NULL || !IsA(funcOpnd, Expr) ||
-		funcOpnd->opType != FUNC_EXPR ||
-		funcOpnd->oper == NULL || indexKeys == NULL)
+	if (funcOpnd == NULL || !IsA(funcOpnd, FuncExpr) ||
+		indexKeys == NULL)
 		return false;
 
-	function = (Func *) funcOpnd->oper;
-	funcargs = funcOpnd->args;
+	function = (FuncExpr *) funcOpnd;
+	funcargs = function->args;
 
 	if (function->funcid != index->indproc)
 		return false;
@@ -1752,7 +1750,7 @@ match_special_index_operator(Expr *clause, Oid opclass,
 	/* we know these will succeed */
 	leftop = get_leftop(clause);
 	rightop = get_rightop(clause);
-	expr_op = ((Oper *) clause->oper)->opno;
+	expr_op = ((OpExpr *) clause)->opno;
 
 	/* again, required for all current special ops: */
 	if (!IsA(rightop, Const) ||
@@ -1916,7 +1914,7 @@ expand_indexqual_conditions(List *indexquals)
 		/* we know these will succeed */
 		Var		   *leftop = get_leftop(clause);
 		Var		   *rightop = get_rightop(clause);
-		Oid			expr_op = ((Oper *) clause->oper)->opno;
+		Oid			expr_op = ((OpExpr *) clause)->opno;
 		Const	   *patt = (Const *) rightop;
 		Const	   *prefix = NULL;
 		Const	   *rest = NULL;
@@ -2011,7 +2009,6 @@ prefix_quals(Var *leftop, Oid expr_op,
 	Oid			oproid;
 	char	   *prefix;
 	Const	   *con;
-	Oper	   *op;
 	Expr	   *expr;
 	Const	   *greaterstr = NULL;
 
@@ -2070,8 +2067,8 @@ prefix_quals(Var *leftop, Oid expr_op,
 		if (oproid == InvalidOid)
 			elog(ERROR, "prefix_quals: no = operator for type %u", datatype);
 		con = string_to_const(prefix, datatype);
-		op = makeOper(oproid, InvalidOid, BOOLOID, false);
-		expr = make_opclause(op, leftop, (Var *) con);
+		expr = make_opclause(oproid, BOOLOID, false,
+							 (Expr *) leftop, (Expr *) con);
 		result = makeList1(expr);
 		return result;
 	}
@@ -2085,8 +2082,8 @@ prefix_quals(Var *leftop, Oid expr_op,
 	if (oproid == InvalidOid)
 		elog(ERROR, "prefix_quals: no >= operator for type %u", datatype);
 	con = string_to_const(prefix, datatype);
-	op = makeOper(oproid, InvalidOid, BOOLOID, false);
-	expr = make_opclause(op, leftop, (Var *) con);
+	expr = make_opclause(oproid, BOOLOID, false,
+						 (Expr *) leftop, (Expr *) con);
 	result = makeList1(expr);
 
 	/*-------
@@ -2100,8 +2097,8 @@ prefix_quals(Var *leftop, Oid expr_op,
 		oproid = find_operator("<", datatype);
 		if (oproid == InvalidOid)
 			elog(ERROR, "prefix_quals: no < operator for type %u", datatype);
-		op = makeOper(oproid, InvalidOid, BOOLOID, false);
-		expr = make_opclause(op, leftop, (Var *) greaterstr);
+		expr = make_opclause(oproid, BOOLOID, false,
+							 (Expr *) leftop, (Expr *) greaterstr);
 		result = lappend(result, expr);
 	}
 
@@ -2124,7 +2121,6 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop)
 	Oid			opr2oid;
 	List	   *result;
 	Oid			datatype;
-	Oper	   *op;
 	Expr	   *expr;
 
 	switch (expr_op)
@@ -2164,10 +2160,10 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop)
 
 	opr1right = network_scan_first(rightop);
 
-	op = makeOper(opr1oid, InvalidOid, BOOLOID, false);
-	expr = make_opclause(op, leftop,
-						 (Var *) makeConst(datatype, -1, opr1right,
-										   false, false));
+	expr = make_opclause(opr1oid, BOOLOID, false,
+						 (Expr *) leftop,
+						 (Expr *) makeConst(datatype, -1, opr1right,
+											false, false));
 	result = makeList1(expr);
 
 	/* create clause "key <= network_scan_last( rightop )" */
@@ -2179,10 +2175,10 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop)
 
 	opr2right = network_scan_last(rightop);
 
-	op = makeOper(opr2oid, InvalidOid, BOOLOID, false);
-	expr = make_opclause(op, leftop,
-						 (Var *) makeConst(datatype, -1, opr2right,
-										   false, false));
+	expr = make_opclause(opr2oid, BOOLOID, false,
+						 (Expr *) leftop,
+						 (Expr *) makeConst(datatype, -1, opr2right,
+											false, false));
 	result = lappend(result, expr);
 
 	return result;
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c
index 009afdff07919241a48dea8763b460c21cede0ba..101866867b9627a6f8c82fc572ce2adba277f435 100644
--- a/src/backend/optimizer/path/orindxpath.c
+++ b/src/backend/optimizer/path/orindxpath.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.48 2002/11/24 21:52:14 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.49 2002/12/12 15:49:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -96,7 +96,7 @@ create_or_index_paths(Query *root, RelOptInfo *rel)
 
 				best_or_subclause_indices(root,
 										  rel,
-										  restrictinfo->clause->args,
+										  ((BoolExpr *) restrictinfo->clause)->args,
 										  restrictinfo->subclauseindices,
 										  pathnode);
 
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 350c761165b4ff65505676f03591ac2d232c7f2e..af0b61a40347766139921361883f47ebc5e29b04 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.41 2002/09/18 21:35:21 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.42 2002/12/12 15:49:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -514,14 +514,16 @@ build_index_pathkeys(Query *root,
 	if (index->indproc)
 	{
 		/* Functional index: build a representation of the function call */
-		Func	   *funcnode = makeNode(Func);
+		Expr	   *funcnode;
 		List	   *funcargs = NIL;
 
-		funcnode->funcid = index->indproc;
-		funcnode->funcresulttype = get_func_rettype(index->indproc);
-		funcnode->funcretset = false;	/* can never be a set */
-		funcnode->funcformat = COERCE_DONTCARE;	/* to match any user expr */
-		funcnode->func_fcache = NULL;
+		sortop = *ordering;
+		if (ScanDirectionIsBackward(scandir))
+		{
+			sortop = get_commutator(sortop);
+			if (sortop == InvalidOid)
+				return NIL;		/* oops, no reverse sort operator? */
+		}
 
 		while (*indexkeys != 0)
 		{
@@ -530,17 +532,14 @@ build_index_pathkeys(Query *root,
 			indexkeys++;
 		}
 
-		sortop = *ordering;
-		if (ScanDirectionIsBackward(scandir))
-		{
-			sortop = get_commutator(sortop);
-			if (sortop == InvalidOid)
-				return NIL;		/* oops, no reverse sort operator? */
-		}
+		funcnode = make_funcclause(index->indproc,
+								   get_func_rettype(index->indproc),
+								   false, /* cannot be a set */
+								   COERCE_DONTCARE,	/* to match any user expr */
+								   funcargs);
 
 		/* Make a one-sublist pathkeys list for the function expression */
-		item = makePathKeyItem((Node *) make_funcclause(funcnode, funcargs),
-							   sortop);
+		item = makePathKeyItem((Node *) funcnode, sortop);
 		retval = makeList1(make_canonical_pathkey(root, item));
 	}
 	else
diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c
index 27fe9e281f3993657f21ce4f209352d283f1bda7..f11ff81ea410b2931cf091ccfe1a3ce648d7c9e4 100644
--- a/src/backend/optimizer/path/tidpath.c
+++ b/src/backend/optimizer/path/tidpath.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/tidpath.c,v 1.12 2002/11/24 21:52:14 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/tidpath.c,v 1.13 2002/12/12 15:49:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,15 +27,14 @@
 
 static List *TidqualFromRestrictinfo(List *relids, List *restrictinfo);
 static bool isEvaluable(int varno, Node *node);
-static Node *TidequalClause(int varno, Expr *node);
+static Node *TidequalClause(int varno, OpExpr *node);
 static List *TidqualFromExpr(int varno, Expr *expr);
 
-static
-bool
+static bool
 isEvaluable(int varno, Node *node)
 {
 	List	   *lst;
-	Expr	   *expr;
+	FuncExpr   *expr;
 
 	if (IsA(node, Const))
 		return true;
@@ -51,7 +50,7 @@ isEvaluable(int varno, Node *node)
 	}
 	if (!is_funcclause(node))
 		return false;
-	expr = (Expr *) node;
+	expr = (FuncExpr *) node;
 	foreach(lst, expr->args)
 	{
 		if (!isEvaluable(varno, lfirst(lst)))
@@ -66,33 +65,26 @@ isEvaluable(int varno, Node *node)
  *	Extract the right node if the opclause is CTID= ....
  *	  or	the left  node if the opclause is ....=CTID
  */
-static
-Node *
-TidequalClause(int varno, Expr *node)
+static Node *
+TidequalClause(int varno, OpExpr *node)
 {
-	Node	   *rnode = 0,
+	Node	   *rnode = NULL,
 			   *arg1,
 			   *arg2,
 			   *arg;
-	Oper	   *oper;
 	Var		   *var;
 	Const	   *aconst;
 	Param	   *param;
-	Expr	   *expr;
+	FuncExpr   *expr;
 
-	if (!node->oper)
-		return rnode;
-	if (!node->args)
+	if (node->opno != TIDEqualOperator)
 		return rnode;
 	if (length(node->args) != 2)
 		return rnode;
-	oper = (Oper *) node->oper;
-	if (oper->opno != TIDEqualOperator)
-		return rnode;
 	arg1 = lfirst(node->args);
 	arg2 = lsecond(node->args);
 
-	arg = (Node *) 0;
+	arg = NULL;
 	if (IsA(arg1, Var))
 	{
 		var = (Var *) arg1;
@@ -138,11 +130,9 @@ TidequalClause(int varno, Expr *node)
 				return rnode;
 			rnode = arg;
 			break;
-		case T_Expr:
-			expr = (Expr *) arg;
-			if (expr->typeOid != TIDOID)
-				return rnode;
-			if (expr->opType != FUNC_EXPR)
+		case T_FuncExpr:
+			expr = (FuncExpr *) arg;
+			if (expr->funcresulttype != TIDOID)
 				return rnode;
 			if (isEvaluable(varno, (Node *) expr))
 				rnode = arg;
@@ -162,8 +152,7 @@ TidequalClause(int varno, Expr *node)
  *	CTID values if we could extract the CTID values from a member
  *	node.
  */
-static
-List *
+static List *
 TidqualFromExpr(int varno, Expr *expr)
 {
 	List	   *rlst = NIL,
@@ -174,17 +163,15 @@ TidqualFromExpr(int varno, Expr *expr)
 
 	if (is_opclause(node))
 	{
-		rnode = TidequalClause(varno, expr);
+		rnode = TidequalClause(varno, (OpExpr *) expr);
 		if (rnode)
 			rlst = lcons(rnode, rlst);
 	}
 	else if (and_clause(node))
 	{
-		foreach(lst, expr->args)
+		foreach(lst, ((BoolExpr *) expr)->args)
 		{
 			node = lfirst(lst);
-			if (!IsA(node, Expr))
-				continue;
 			rlst = TidqualFromExpr(varno, (Expr *) node);
 			if (rlst)
 				break;
@@ -192,11 +179,11 @@ TidqualFromExpr(int varno, Expr *expr)
 	}
 	else if (or_clause(node))
 	{
-		foreach(lst, expr->args)
+		foreach(lst, ((BoolExpr *) expr)->args)
 		{
 			node = lfirst(lst);
-			if (IsA(node, Expr) &&
-				(frtn = TidqualFromExpr(varno, (Expr *) node)))
+			frtn = TidqualFromExpr(varno, (Expr *) node);
+			if (frtn)
 				rlst = nconc(rlst, frtn);
 			else
 			{
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 0414fdf2f3f1ced062251f73330294a75f75a79c..a67e23fbf200a0a49290d1cf0052084ba6bf7927 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.127 2002/12/05 15:50:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.128 2002/12/12 15:49:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1041,12 +1041,12 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
 
 	foreach(i, indexqual)
 	{
-		Expr	   *clause = (Expr *) lfirst(i);
-		Expr	   *newclause;
+		OpExpr	   *clause = (OpExpr *) lfirst(i);
+		OpExpr	   *newclause;
 		List	   *leftvarnos;
 		Oid			opclass;
 
-		if (!is_opclause((Node *) clause) || length(clause->args) != 2)
+		if (!IsA(clause, OpExpr) || length(clause->args) != 2)
 			elog(ERROR, "fix_indxqual_sublist: indexqual clause is not binary opclause");
 
 		/*
@@ -1056,7 +1056,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
 		 * is a subplan in the arguments of the opclause.  So just do a
 		 * full copy.
 		 */
-		newclause = (Expr *) copyObject((Node *) clause);
+		newclause = (OpExpr *) copyObject((Node *) clause);
 
 		/*
 		 * Check to see if the indexkey is on the right; if so, commute
@@ -1083,7 +1083,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
 		 * Finally, check to see if index is lossy for this operator. If
 		 * so, add (a copy of) original form of clause to recheck list.
 		 */
-		if (op_requires_recheck(((Oper *) newclause->oper)->opno, opclass))
+		if (op_requires_recheck(newclause->opno, opclass))
 			recheck_qual = lappend(recheck_qual,
 								   copyObject((Node *) clause));
 	}
@@ -1100,7 +1100,7 @@ fix_indxqual_operand(Node *node, int baserelid, IndexOptInfo *index,
 	 * Remove any binary-compatible relabeling of the indexkey
 	 */
 	if (IsA(node, RelabelType))
-		node = ((RelabelType *) node)->arg;
+		node = (Node *) ((RelabelType *) node)->arg;
 
 	/*
 	 * We represent index keys by Var nodes having the varno of the base
@@ -1168,11 +1168,11 @@ switch_outer(List *clauses)
 
 	foreach(i, clauses)
 	{
-		Expr	   *clause = (Expr *) lfirst(i);
+		OpExpr	   *clause = (OpExpr *) lfirst(i);
 		Var		   *op;
 
-		Assert(is_opclause((Node *) clause));
-		op = get_rightop(clause);
+		Assert(is_opclause(clause));
+		op = get_rightop((Expr *) clause);
 		Assert(op && IsA(op, Var));
 		if (var_is_outer(op))
 		{
@@ -1181,10 +1181,13 @@ switch_outer(List *clauses)
 			 * the clause without changing the original list.  Could use
 			 * copyObject, but a complete deep copy is overkill.
 			 */
-			Expr	   *temp;
+			OpExpr	   *temp = makeNode(OpExpr);
 
-			temp = make_clause(clause->opType, clause->oper,
-							   listCopy(clause->args));
+			temp->opno = clause->opno;
+			temp->opfuncid = InvalidOid;
+			temp->opresulttype = clause->opresulttype;
+			temp->opretset = clause->opretset;
+			temp->args = listCopy(clause->args);
 			/* Commute it --- note this modifies the temp node in-place. */
 			CommuteClause(temp);
 			t_list = lappend(t_list, temp);
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 529ba712f411bc74a51a9a993b5ed7fb8efeabdf..aca2c6f4f67cefd0405955d072bac191f17b5452 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.77 2002/11/24 21:52:14 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.78 2002/12/12 15:49:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -761,14 +761,11 @@ process_implied_equality(Query *root, Node *item1, Node *item2,
 		elog(ERROR, "Equality operator for types '%s' and '%s' should be mergejoinable, but isn't",
 			 format_type_be(ltype), format_type_be(rtype));
 
-	clause = makeNode(Expr);
-	clause->typeOid = BOOLOID;
-	clause->opType = OP_EXPR;
-	clause->oper = (Node *) makeOper(oprid(eq_operator),		/* opno */
-									 InvalidOid,		/* opid */
-									 BOOLOID,	/* opresulttype */
-									 false);	/* opretset */
-	clause->args = makeList2(item1, item2);
+	clause = make_opclause(oprid(eq_operator), /* opno */
+						   BOOLOID,	/* opresulttype */
+						   false, /* opretset */
+						   (Expr *) item1,
+						   (Expr *) item2);
 
 	ReleaseSysCache(eq_operator);
 
@@ -969,7 +966,7 @@ check_mergejoinable(RestrictInfo *restrictinfo)
 				leftOp,
 				rightOp;
 
-	if (!is_opclause((Node *) clause))
+	if (!is_opclause(clause))
 		return;
 
 	left = get_leftop(clause);
@@ -978,10 +975,11 @@ check_mergejoinable(RestrictInfo *restrictinfo)
 	/* caution: is_opclause accepts more than I do, so check it */
 	if (!right)
 		return;					/* unary opclauses need not apply */
-	if (!IsA(left, Var) ||!IsA(right, Var))
+	if (!IsA(left, Var) ||
+		!IsA(right, Var))
 		return;
 
-	opno = ((Oper *) clause->oper)->opno;
+	opno = ((OpExpr *) clause)->opno;
 
 	if (op_mergejoinable(opno,
 						 left->vartype,
@@ -1012,7 +1010,7 @@ check_hashjoinable(RestrictInfo *restrictinfo)
 			   *right;
 	Oid			opno;
 
-	if (!is_opclause((Node *) clause))
+	if (!is_opclause(clause))
 		return;
 
 	left = get_leftop(clause);
@@ -1021,10 +1019,11 @@ check_hashjoinable(RestrictInfo *restrictinfo)
 	/* caution: is_opclause accepts more than I do, so check it */
 	if (!right)
 		return;					/* unary opclauses need not apply */
-	if (!IsA(left, Var) ||!IsA(right, Var))
+	if (!IsA(left, Var) ||
+		!IsA(right, Var))
 		return;
 
-	opno = ((Oper *) clause->oper)->opno;
+	opno = ((OpExpr *) clause)->opno;
 
 	if (op_hashjoinable(opno,
 						left->vartype,
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ebb9f3d2092f43c8db0b062ac28961c3b51293c8..b3d7b5303c4f46716b73ab8001823826ed157725 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.133 2002/12/05 21:46:37 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.134 2002/12/12 15:49:32 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 SubPlan nodes, and we want those IDs to be unique for
+	 * unique IDs to SubPlanExpr 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)
 		{
-			SubPlan    *subplan = (SubPlan *) lfirst(lst);
+			SubPlanExpr *subplan = (SubPlanExpr *) lfirst(lst);
 
 			plan->extParam = set_unioni(plan->extParam,
 										subplan->plan->extParam);
@@ -1015,7 +1015,7 @@ grouping_planner(Query *parse, double tuple_fraction)
 							  -1,
 							  0);
 
-				ctid = makeTargetEntry(resdom, (Node *) var);
+				ctid = makeTargetEntry(resdom, (Expr *) var);
 				tlist = lappend(tlist, ctid);
 			}
 		}
@@ -1707,7 +1707,7 @@ make_subplanTargetList(Query *parse,
 												exprTypmod(groupexpr),
 												NULL,
 												false),
-									 groupexpr);
+									 (Expr *) groupexpr);
 				sub_tlist = lappend(sub_tlist, te);
 			}
 
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index b23843a030cdcb7556d2f992ba2a9e17dc40cb17..0d66c97964c421e3b3bc79857d53a1b66582438a 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.84 2002/12/05 15:50:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.85 2002/12/12 15:49:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -52,7 +52,7 @@ static Node *replace_vars_with_subplan_refs(Node *node,
 							   bool tlist_has_non_vars);
 static Node *replace_vars_with_subplan_refs_mutator(Node *node,
 						replace_vars_with_subplan_refs_context *context);
-static bool fix_opids_walker(Node *node, void *context);
+static bool fix_opfuncids_walker(Node *node, void *context);
 
 /*****************************************************************************
  *
@@ -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 SubPlan
+	 * children.  Fortunately, that consideration doesn't apply to SubPlanExpr
 	 * 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)
 	{
-		SubPlan    *sp = (SubPlan *) lfirst(pl);
+		SubPlanExpr *sp = (SubPlanExpr *) lfirst(pl);
 
-		Assert(IsA(sp, SubPlan));
+		Assert(IsA(sp, SubPlanExpr));
 		set_plan_references(sp->plan, sp->rtable);
 	}
 }
@@ -238,8 +238,8 @@ set_plan_references(Plan *plan, List *rtable)
  * fix_expr_references
  *	  Do final cleanup on expressions (targetlists or quals).
  *
- * This consists of looking up operator opcode info for Oper nodes
- * and recursively performing set_plan_references on SubPlans.
+ * This consists of looking up operator opcode info for OpExpr nodes
+ * and recursively performing set_plan_references on subplans.
  *
  * The Plan argument is currently unused, but might be needed again someday.
  */
@@ -255,20 +255,15 @@ fix_expr_references_walker(Node *node, void *context)
 {
 	if (node == NULL)
 		return false;
-	if (IsA(node, Expr))
+	if (IsA(node, OpExpr))
+		set_opfuncid((OpExpr *) node);
+	else if (IsA(node, DistinctExpr))
+		set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
+	else if (IsA(node, SubPlanExpr))
 	{
-		Expr   *expr = (Expr *) node;
+		SubPlanExpr *sp = (SubPlanExpr *) node;
 
-		if (expr->opType == OP_EXPR ||
-			expr->opType == DISTINCT_EXPR)
-			replace_opid((Oper *) expr->oper);
-		else if (expr->opType == SUBPLAN_EXPR)
-		{
-			SubPlan	   *sp = (SubPlan *) expr->oper;
-
-			Assert(IsA(sp, SubPlan));
-			set_plan_references(sp->plan, sp->rtable);
-		}
+		set_plan_references(sp->plan, sp->rtable);
 	}
 	return expression_tree_walker(node, fix_expr_references_walker, context);
 }
@@ -362,12 +357,13 @@ set_uppernode_references(Plan *plan, Index subvarno)
 		TargetEntry *tle = (TargetEntry *) lfirst(l);
 		Node	   *newexpr;
 
-		newexpr = replace_vars_with_subplan_refs(tle->expr,
+		newexpr = replace_vars_with_subplan_refs((Node *) tle->expr,
 												 subvarno,
 												 subplan_targetlist,
 												 tlist_has_non_vars);
 		output_targetlist = lappend(output_targetlist,
-								  makeTargetEntry(tle->resdom, newexpr));
+								  makeTargetEntry(tle->resdom,
+												  (Expr *) newexpr));
 	}
 	plan->targetlist = output_targetlist;
 
@@ -570,8 +566,8 @@ replace_vars_with_subplan_refs_mutator(Node *node,
  *****************************************************************************/
 
 /*
- * fix_opids
- *	  Calculate opid field from opno for each Oper node in given tree.
+ * fix_opfuncids
+ *	  Calculate opfuncid field from opno for each OpExpr node in given tree.
  *	  The given tree can be anything expression_tree_walker handles.
  *
  * The argument is modified in-place.  (This is OK since we'd want the
@@ -579,24 +575,20 @@ replace_vars_with_subplan_refs_mutator(Node *node,
  * shared structure.)
  */
 void
-fix_opids(Node *node)
+fix_opfuncids(Node *node)
 {
 	/* This tree walk requires no special setup, so away we go... */
-	fix_opids_walker(node, NULL);
+	fix_opfuncids_walker(node, NULL);
 }
 
 static bool
-fix_opids_walker(Node *node, void *context)
+fix_opfuncids_walker(Node *node, void *context)
 {
 	if (node == NULL)
 		return false;
-	if (IsA(node, Expr))
-	{
-		Expr   *expr = (Expr *) node;
-
-		if (expr->opType == OP_EXPR ||
-			expr->opType == DISTINCT_EXPR)
-			replace_opid((Oper *) expr->oper);
-	}
-	return expression_tree_walker(node, fix_opids_walker, context);
+	if (IsA(node, OpExpr))
+		set_opfuncid((OpExpr *) node);
+	else if (IsA(node, DistinctExpr))
+		set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
+	return expression_tree_walker(node, fix_opfuncids_walker, context);
 }
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index a65de72c90b89c0f198df27c0dcff685dc23ce8e..fe17b8ebb018eab2e835a70d4ad59bf2d2c0a0bf 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.59 2002/12/05 15:50:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.60 2002/12/12 15:49:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -144,12 +144,12 @@ generate_new_param(Oid paramtype, int32 paramtypmod)
 }
 
 /*
- * Convert a bare SubLink (as created by the parser) into a SubPlan.
+ * Convert a bare SubLink (as created by the parser) into a SubPlanExpr.
  */
 static Node *
 make_subplan(SubLink *slink)
 {
-	SubPlan    *node = makeNode(SubPlan);
+	SubPlanExpr *node = makeNode(SubPlanExpr);
 	Query	   *subquery = (Query *) (slink->subselect);
 	Oid			result_type = exprType((Node *) slink);
 	double		tuple_fraction;
@@ -210,11 +210,13 @@ make_subplan(SubLink *slink)
 	node->plan = plan = subquery_planner(subquery, tuple_fraction);
 
 	node->plan_id = PlannerPlanId++;	/* Assign unique ID to this
-										 * SubPlan */
+										 * SubPlanExpr */
 
 	node->rtable = subquery->rtable;
 	node->sublink = slink;
 
+	node->typeOid = result_type;
+
 	slink->subselect = NULL;	/* cool ?! see error check above! */
 
 	/*
@@ -270,7 +272,6 @@ make_subplan(SubLink *slink)
 	}
 	else
 	{
-		Expr	   *expr = makeNode(Expr);
 		List	   *args = NIL;
 
 		/*
@@ -350,14 +351,7 @@ make_subplan(SubLink *slink)
 		convert_sublink_opers(slink, plan->targetlist, NULL);
 
 		/*
-		 * Make expression of SUBPLAN type
-		 */
-		expr->typeOid = result_type;
-		expr->opType = SUBPLAN_EXPR;
-		expr->oper = (Node *) node;
-
-		/*
-		 * Make expr->args from parParam.
+		 * Make node->args from parParam.
 		 */
 		foreach(lst, node->parParam)
 		{
@@ -373,9 +367,9 @@ make_subplan(SubLink *slink)
 			var->varlevelsup = 0;
 			args = lappend(args, var);
 		}
-		expr->args = args;
+		node->args = args;
 
-		result = (Node *) expr;
+		result = (Node *) node;
 	}
 
 	return result;
@@ -385,7 +379,7 @@ 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 Oper nodes.  We replace it
+ * 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
@@ -404,7 +398,7 @@ convert_sublink_opers(SubLink *slink, List *targetlist,
 
 	foreach(lst, slink->oper)
 	{
-		Oper	   *oper = (Oper *) lfirst(lst);
+		OpExpr	   *oper = (OpExpr *) lfirst(lst);
 		Node	   *lefthand = lfirst(leftlist);
 		TargetEntry *te = lfirst(targetlist);
 		Param	   *prm;
@@ -422,7 +416,7 @@ convert_sublink_opers(SubLink *slink, List *targetlist,
 			*setParams = lappendi(*setParams, prm->paramid);
 
 		/* Look up the operator to check its declared input types */
-		Assert(IsA(oper, Oper));
+		Assert(IsA(oper, OpExpr));
 		tup = SearchSysCache(OPEROID,
 							 ObjectIdGetDatum(oper->opno),
 							 0, 0, 0);
@@ -439,9 +433,11 @@ convert_sublink_opers(SubLink *slink, List *targetlist,
 		left = make_operand(lefthand, exprType(lefthand), opform->oprleft);
 		right = make_operand((Node *) prm, prm->paramtype, opform->oprright);
 		newoper = lappend(newoper,
-						  make_opclause(oper,
-										(Var *) left,
-										(Var *) right));
+						  make_opclause(oper->opno,
+										oper->opresulttype,
+										oper->opretset,
+										(Expr *) left,
+										(Expr *) right));
 
 		ReleaseSysCache(tup);
 
@@ -482,7 +478,7 @@ finalize_primnode(Node *node, finalize_primnode_results *results)
 	}
 	if (is_subplan(node))
 	{
-		SubPlan    *subplan = (SubPlan *) ((Expr *) node)->oper;
+		SubPlanExpr *subplan = (SubPlanExpr *) node;
 		List	   *lst;
 
 		/* Check extParam list for params to add to paramids */
@@ -559,12 +555,12 @@ process_sublinks_mutator(Node *node, void *context)
 		 */
 		sublink->lefthand = (List *)
 			process_sublinks_mutator((Node *) sublink->lefthand, context);
-		/* Now build the SubPlan node and make the expr to return */
+		/* Now build the SubPlanExpr node and make the expr to return */
 		return make_subplan(sublink);
 	}
 
 	/*
-	 * Note that we will never see a SubPlan expression in the input
+	 * Note that we will never see a SubPlanExpr 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.
diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c
index bb00555f69d9d02fb42112a230758017e0706de2..4016ba476deafc55e542eb2c3024317861db9ee1 100644
--- a/src/backend/optimizer/prep/prepqual.c
+++ b/src/backend/optimizer/prep/prepqual.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.33 2002/09/02 02:47:02 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.34 2002/12/12 15:49:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -294,7 +294,7 @@ flatten_andors(Expr *qual)
 		List	   *out_list = NIL;
 		List	   *arg;
 
-		foreach(arg, qual->args)
+		foreach(arg, ((BoolExpr *) qual)->args)
 		{
 			Expr	   *subexpr = flatten_andors((Expr *) lfirst(arg));
 
@@ -305,7 +305,7 @@ flatten_andors(Expr *qual)
 			 * with any other expr. Otherwise we'd need a listCopy here.
 			 */
 			if (and_clause((Node *) subexpr))
-				out_list = nconc(out_list, subexpr->args);
+				out_list = nconc(out_list, ((BoolExpr *) subexpr)->args);
 			else
 				out_list = lappend(out_list, subexpr);
 		}
@@ -316,7 +316,7 @@ flatten_andors(Expr *qual)
 		List	   *out_list = NIL;
 		List	   *arg;
 
-		foreach(arg, qual->args)
+		foreach(arg, ((BoolExpr *) qual)->args)
 		{
 			Expr	   *subexpr = flatten_andors((Expr *) lfirst(arg));
 
@@ -327,7 +327,7 @@ flatten_andors(Expr *qual)
 			 * with any other expr. Otherwise we'd need a listCopy here.
 			 */
 			if (or_clause((Node *) subexpr))
-				out_list = nconc(out_list, subexpr->args);
+				out_list = nconc(out_list, ((BoolExpr *) subexpr)->args);
 			else
 				out_list = lappend(out_list, subexpr);
 		}
@@ -335,20 +335,17 @@ flatten_andors(Expr *qual)
 	}
 	else if (not_clause((Node *) qual))
 		return make_notclause(flatten_andors(get_notclausearg(qual)));
-	else if (is_opclause((Node *) qual))
+	else if (is_opclause(qual))
 	{
+		OpExpr	   *opexpr = (OpExpr *) qual;
 		Expr	   *left = (Expr *) get_leftop(qual);
 		Expr	   *right = (Expr *) get_rightop(qual);
 
-		if (right)
-			return make_clause(qual->opType, qual->oper,
-							   lcons(flatten_andors(left),
-									 lcons(flatten_andors(right),
-										   NIL)));
-		else
-			return make_clause(qual->opType, qual->oper,
-							   lcons(flatten_andors(left),
-									 NIL));
+		return make_opclause(opexpr->opno,
+							 opexpr->opresulttype,
+							 opexpr->opretset,
+							 flatten_andors(left),
+							 flatten_andors(right));
 	}
 	else
 		return qual;
@@ -379,7 +376,8 @@ pull_ors(List *orlist)
 		 * we'd need a listCopy here.
 		 */
 		if (or_clause((Node *) subexpr))
-			out_list = nconc(out_list, pull_ors(subexpr->args));
+			out_list = nconc(out_list,
+							 pull_ors(((BoolExpr *) subexpr)->args));
 		else
 			out_list = lappend(out_list, subexpr);
 	}
@@ -410,7 +408,8 @@ pull_ands(List *andlist)
 		 * we'd need a listCopy here.
 		 */
 		if (and_clause((Node *) subexpr))
-			out_list = nconc(out_list, pull_ands(subexpr->args));
+			out_list = nconc(out_list,
+							 pull_ands(((BoolExpr *) subexpr)->args));
 		else
 			out_list = lappend(out_list, subexpr);
 	}
@@ -433,20 +432,17 @@ find_nots(Expr *qual)
 
 #ifdef NOT_USED
 	/* recursing into operator expressions is probably not worth it. */
-	if (is_opclause((Node *) qual))
+	if (is_opclause(qual))
 	{
+		OpExpr	   *opexpr = (OpExpr *) qual;
 		Expr	   *left = (Expr *) get_leftop(qual);
 		Expr	   *right = (Expr *) get_rightop(qual);
 
-		if (right)
-			return make_clause(qual->opType, qual->oper,
-							   lcons(find_nots(left),
-									 lcons(find_nots(right),
-										   NIL)));
-		else
-			return make_clause(qual->opType, qual->oper,
-							   lcons(find_nots(left),
-									 NIL));
+		return make_opclause(opexpr->opno,
+							 opexpr->opresulttype,
+							 opexpr->opretset,
+							 find_nots(left),
+							 find_nots(right));
 	}
 #endif
 	if (and_clause((Node *) qual))
@@ -454,7 +450,7 @@ find_nots(Expr *qual)
 		List	   *t_list = NIL;
 		List	   *temp;
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 			t_list = lappend(t_list, find_nots(lfirst(temp)));
 		return make_andclause(pull_ands(t_list));
 	}
@@ -463,7 +459,7 @@ find_nots(Expr *qual)
 		List	   *t_list = NIL;
 		List	   *temp;
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 			t_list = lappend(t_list, find_nots(lfirst(temp)));
 		return make_orclause(pull_ors(t_list));
 	}
@@ -492,20 +488,17 @@ push_nots(Expr *qual)
 	 * Otherwise, retain the clause as it is (the 'not' can't be pushed
 	 * down any farther).
 	 */
-	if (is_opclause((Node *) qual))
+	if (is_opclause(qual))
 	{
-		Oper	   *oper = (Oper *) ((Expr *) qual)->oper;
-		Oid			negator = get_negator(oper->opno);
+		OpExpr	   *opexpr = (OpExpr *) qual;
+		Oid			negator = get_negator(opexpr->opno);
 
 		if (negator)
-		{
-			Oper	   *op = (Oper *) makeOper(negator,
-											   InvalidOid,
-											   oper->opresulttype,
-											   oper->opretset);
-
-			return make_opclause(op, get_leftop(qual), get_rightop(qual));
-		}
+			return make_opclause(negator,
+								 opexpr->opresulttype,
+								 opexpr->opretset,
+								 (Expr *) get_leftop(qual),
+								 (Expr *) get_rightop(qual));
 		else
 			return make_notclause(qual);
 	}
@@ -521,7 +514,7 @@ push_nots(Expr *qual)
 		List	   *t_list = NIL;
 		List	   *temp;
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 			t_list = lappend(t_list, push_nots(lfirst(temp)));
 		return make_orclause(pull_ors(t_list));
 	}
@@ -530,7 +523,7 @@ push_nots(Expr *qual)
 		List	   *t_list = NIL;
 		List	   *temp;
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 			t_list = lappend(t_list, push_nots(lfirst(temp)));
 		return make_andclause(pull_ands(t_list));
 	}
@@ -576,7 +569,7 @@ find_ors(Expr *qual)
 		List	   *andlist = NIL;
 		List	   *temp;
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 			andlist = lappend(andlist, find_ors(lfirst(temp)));
 		return make_andclause(pull_ands(andlist));
 	}
@@ -585,7 +578,7 @@ find_ors(Expr *qual)
 		List	   *orlist = NIL;
 		List	   *temp;
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 			orlist = lappend(orlist, find_ors(lfirst(temp)));
 		return or_normalize(pull_ors(orlist));
 	}
@@ -629,7 +622,7 @@ or_normalize(List *orlist)
 
 		if (and_clause((Node *) clause))
 		{
-			int			nclauses = length(clause->args);
+			int			nclauses = length(((BoolExpr *) clause)->args);
 
 			if (nclauses > num_subclauses)
 			{
@@ -650,7 +643,7 @@ or_normalize(List *orlist)
 	 */
 	orlist = lremove(distributable, orlist);
 
-	foreach(temp, distributable->args)
+	foreach(temp, ((BoolExpr *) distributable)->args)
 	{
 		Expr	   *andclause = lfirst(temp);
 		List	   *neworlist;
@@ -703,7 +696,7 @@ find_ands(Expr *qual)
 		List	   *orlist = NIL;
 		List	   *temp;
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 			orlist = lappend(orlist, find_ands(lfirst(temp)));
 		return make_orclause(pull_ors(orlist));
 	}
@@ -712,7 +705,7 @@ find_ands(Expr *qual)
 		List	   *andlist = NIL;
 		List	   *temp;
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 			andlist = lappend(andlist, find_ands(lfirst(temp)));
 		return and_normalize(pull_ands(andlist));
 	}
@@ -757,7 +750,7 @@ and_normalize(List *andlist)
 
 		if (or_clause((Node *) clause))
 		{
-			int			nclauses = length(clause->args);
+			int			nclauses = length(((BoolExpr *) clause)->args);
 
 			if (nclauses > num_subclauses)
 			{
@@ -778,7 +771,7 @@ and_normalize(List *andlist)
 	 */
 	andlist = lremove(distributable, andlist);
 
-	foreach(temp, distributable->args)
+	foreach(temp, ((BoolExpr *) distributable)->args)
 	{
 		Expr	   *orclause = lfirst(temp);
 		List	   *newandlist;
@@ -829,7 +822,7 @@ qual_cleanup(Expr *qual)
 		List	   *andlist = NIL;
 		List	   *temp;
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 			andlist = lappend(andlist, qual_cleanup(lfirst(temp)));
 
 		andlist = remove_duplicates(pull_ands(andlist));
@@ -844,7 +837,7 @@ qual_cleanup(Expr *qual)
 		List	   *orlist = NIL;
 		List	   *temp;
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 			orlist = lappend(orlist, qual_cleanup(lfirst(temp)));
 
 		orlist = remove_duplicates(pull_ors(orlist));
@@ -910,7 +903,7 @@ count_bool_nodes(Expr *qual,
 		*nodes = *cnfnodes = 0.0;
 		*dnfnodes = 1.0;		/* DNF nodes will be product of sub-counts */
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 		{
 			count_bool_nodes(lfirst(temp),
 							 &subnodes, &subcnfnodes, &subdnfnodes);
@@ -931,7 +924,7 @@ count_bool_nodes(Expr *qual,
 		*nodes = *dnfnodes = 0.0;
 		*cnfnodes = 1.0;		/* CNF nodes will be product of sub-counts */
 
-		foreach(temp, qual->args)
+		foreach(temp, ((BoolExpr *) qual)->args)
 		{
 			count_bool_nodes(lfirst(temp),
 							 &subnodes, &subcnfnodes, &subdnfnodes);
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index 68895143061b5e4ffeced0db43882fbbf7c7543e..87d3c983a70830684c9be6547a63fb568e48d26f 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.58 2002/11/25 21:29:40 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.59 2002/12/12 15:49:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -96,7 +96,7 @@ preprocess_targetlist(List *tlist,
 		if (command_type == CMD_DELETE)
 			tlist = listCopy(tlist);
 
-		tlist = lappend(tlist, makeTargetEntry(resdom, (Node *) var));
+		tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) var));
 	}
 
 	return tlist;
@@ -215,7 +215,7 @@ expand_targetlist(List *tlist, int command_type,
 												 atttypmod,
 									  pstrdup(NameStr(att_tup->attname)),
 												 false),
-									  new_expr);
+									  (Expr *) new_expr);
 		}
 
 		new_tlist = lappend(new_tlist, new_tle);
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 79063c02806945194f3ba96b0fce2c973cd04654..a55af2e2d060d3094fb1dae91ca26bbcf13bc200 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.81 2002/11/25 21:29:40 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.82 2002/12/12 15:49:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -406,7 +406,7 @@ generate_setop_tlist(List *colTypes, int flag,
 		 * the output tlists of upper-level nodes!
 		 */
 		if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
-			expr = inputtle->expr;
+			expr = (Node *) inputtle->expr;
 		else
 			expr = (Node *) makeVar(0,
 									inputtle->resdom->resno,
@@ -430,7 +430,7 @@ generate_setop_tlist(List *colTypes, int flag,
 							colTypmod,
 							pstrdup(reftle->resdom->resname),
 							false);
-		tlist = lappend(tlist, makeTargetEntry(resdom, expr));
+		tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
 		input_tlist = lnext(input_tlist);
 		refnames_tlist = lnext(refnames_tlist);
 	}
@@ -449,7 +449,7 @@ generate_setop_tlist(List *colTypes, int flag,
 								  Int32GetDatum(flag),
 								  false,
 								  true);
-		tlist = lappend(tlist, makeTargetEntry(resdom, expr));
+		tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
 	}
 
 	return tlist;
@@ -543,7 +543,7 @@ generate_append_tlist(List *colTypes, bool flag,
 							colTypmod,
 							pstrdup(reftle->resdom->resname),
 							false);
-		tlist = lappend(tlist, makeTargetEntry(resdom, expr));
+		tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
 		refnames_tlist = lnext(refnames_tlist);
 	}
 
@@ -561,7 +561,7 @@ generate_append_tlist(List *colTypes, bool flag,
 								INT4OID,
 								-1,
 								0);
-		tlist = lappend(tlist, makeTargetEntry(resdom, expr));
+		tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
 	}
 
 	pfree(colTypmods);
@@ -872,13 +872,13 @@ adjust_inherited_attrs_mutator(Node *node,
 	 */
 	if (is_subplan(node))
 	{
-		SubPlan    *subplan;
+		SubPlanExpr *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 = (SubPlan *) ((Expr *) node)->oper;
+		subplan = (SubPlanExpr *) 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 a0d1b752bc4d5133eb3d73deba99775a20db102d..ef317c5b2231ee007affa2b8eacdfafd700b8ec0 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.115 2002/12/01 21:05:14 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.116 2002/12/12 15:49:32 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -70,84 +70,41 @@ static bool contain_mutable_functions_walker(Node *node, void *context);
 static bool contain_volatile_functions_walker(Node *node, void *context);
 static bool contain_nonstrict_functions_walker(Node *node, void *context);
 static Node *eval_const_expressions_mutator(Node *node, List *active_fns);
-static Expr *simplify_op_or_func(Expr *expr, List *args, bool allow_inline,
-								 List *active_fns);
-static Expr *evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple);
-static Expr *inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple,
+static Expr *simplify_function(Oid funcid, List *args, bool allow_inline,
 							   List *active_fns);
+static Expr *evaluate_function(Oid funcid, List *args, HeapTuple func_tuple);
+static Expr *inline_function(Oid funcid, List *args, HeapTuple func_tuple,
+							 List *active_fns);
 static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,
 										  int *usecounts);
 static Node *substitute_actual_parameters_mutator(Node *node,
 					 substitute_actual_parameters_context *context);
 
 
-Expr *
-make_clause(int type, Node *oper, List *args)
-{
-	Expr	   *expr = makeNode(Expr);
-
-	switch (type)
-	{
-		case AND_EXPR:
-		case OR_EXPR:
-		case NOT_EXPR:
-			expr->typeOid = BOOLOID;
-			break;
-		case OP_EXPR:
-		case DISTINCT_EXPR:
-			expr->typeOid = ((Oper *) oper)->opresulttype;
-			break;
-		case FUNC_EXPR:
-			expr->typeOid = ((Func *) oper)->funcresulttype;
-			break;
-		default:
-			elog(ERROR, "make_clause: unsupported type %d", type);
-			break;
-	}
-	expr->opType = type;
-	expr->oper = oper;			/* ignored for AND, OR, NOT */
-	expr->args = args;
-	return expr;
-}
-
-
 /*****************************************************************************
  *		OPERATOR clause functions
  *****************************************************************************/
 
-
-/*
- * is_opclause
- *
- * Returns t iff the clause is an operator clause:
- *				(op expr expr) or (op expr).
- */
-bool
-is_opclause(Node *clause)
-{
-	return (clause != NULL &&
-			IsA(clause, Expr) &&
-			((Expr *) clause)->opType == OP_EXPR);
-}
-
 /*
  * make_opclause
- *	  Creates a clause given its operator, left operand, and right
- *	  operand (pass NULL to create single-operand clause).
+ *	  Creates an operator clause given its operator info, left operand,
+ *	  and right operand (pass NULL to create single-operand clause).
  */
 Expr *
-make_opclause(Oper *op, Var *leftop, Var *rightop)
+make_opclause(Oid opno, Oid opresulttype, bool opretset,
+			  Expr *leftop, Expr *rightop)
 {
-	Expr	   *expr = makeNode(Expr);
+	OpExpr	   *expr = makeNode(OpExpr);
 
-	expr->typeOid = op->opresulttype;
-	expr->opType = OP_EXPR;
-	expr->oper = (Node *) op;
+	expr->opno = opno;
+	expr->opfuncid = InvalidOid;
+	expr->opresulttype = opresulttype;
+	expr->opretset = opretset;
 	if (rightop)
 		expr->args = makeList2(leftop, rightop);
 	else
 		expr->args = makeList1(leftop);
-	return expr;
+	return (Expr *) expr;
 }
 
 /*
@@ -163,8 +120,10 @@ make_opclause(Oper *op, Var *leftop, Var *rightop)
 Var *
 get_leftop(Expr *clause)
 {
-	if (clause->args != NULL)
-		return lfirst(clause->args);
+	OpExpr *expr = (OpExpr *) clause;
+
+	if (expr->args != NULL)
+		return lfirst(expr->args);
 	else
 		return NULL;
 }
@@ -178,124 +137,109 @@ get_leftop(Expr *clause)
 Var *
 get_rightop(Expr *clause)
 {
-	if (clause->args != NULL && lnext(clause->args) != NULL)
-		return lfirst(lnext(clause->args));
+	OpExpr *expr = (OpExpr *) clause;
+
+	if (expr->args != NULL && lnext(expr->args) != NULL)
+		return lfirst(lnext(expr->args));
 	else
 		return NULL;
 }
 
 /*****************************************************************************
- *		FUNC clause functions
+ *		FUNCTION clause functions
  *****************************************************************************/
 
-/*
- * is_funcclause
- *
- * Returns t iff the clause is a function clause: (func { expr }).
- */
-bool
-is_funcclause(Node *clause)
-{
-	return (clause != NULL &&
-			IsA(clause, Expr) &&
-			((Expr *) clause)->opType == FUNC_EXPR);
-}
-
 /*
  * make_funcclause
- *
- * Creates a function clause given the FUNC node and the functional
- * arguments.
+ *	  Creates a function clause given its function info and argument list.
  */
 Expr *
-make_funcclause(Func *func, List *funcargs)
+make_funcclause(Oid funcid, Oid funcresulttype, bool funcretset,
+				CoercionForm funcformat, List *funcargs)
 {
-	Expr	   *expr = makeNode(Expr);
+	FuncExpr   *expr = makeNode(FuncExpr);
 
-	expr->typeOid = func->funcresulttype;
-	expr->opType = FUNC_EXPR;
-	expr->oper = (Node *) func;
+	expr->funcid = funcid;
+	expr->funcresulttype = funcresulttype;
+	expr->funcretset = funcretset;
+	expr->funcformat = funcformat;
 	expr->args = funcargs;
-	return expr;
+	return (Expr *) expr;
 }
 
 /*****************************************************************************
- *		OR clause functions
+ *		NOT clause functions
  *****************************************************************************/
 
 /*
- * or_clause
+ * not_clause
  *
- * Returns t iff the clause is an 'or' clause: (OR { expr }).
+ * Returns t iff this is a 'not' clause: (NOT expr).
  */
 bool
-or_clause(Node *clause)
+not_clause(Node *clause)
 {
 	return (clause != NULL &&
-			IsA(clause, Expr) &&
-			((Expr *) clause)->opType == OR_EXPR);
+			IsA(clause, BoolExpr) &&
+			((BoolExpr *) clause)->boolop == NOT_EXPR);
 }
 
 /*
- * make_orclause
+ * make_notclause
  *
- * Creates an 'or' clause given a list of its subclauses.
+ * Create a 'not' clause given the expression to be negated.
  */
 Expr *
-make_orclause(List *orclauses)
+make_notclause(Expr *notclause)
 {
-	Expr	   *expr = makeNode(Expr);
+	BoolExpr   *expr = makeNode(BoolExpr);
 
-	expr->typeOid = BOOLOID;
-	expr->opType = OR_EXPR;
-	expr->oper = NULL;
-	expr->args = orclauses;
-	return expr;
+	expr->boolop = NOT_EXPR;
+	expr->args = makeList1(notclause);
+	return (Expr *) expr;
 }
 
-/*****************************************************************************
- *		NOT clause functions
- *****************************************************************************/
-
 /*
- * not_clause
+ * get_notclausearg
  *
- * Returns t iff this is a 'not' clause: (NOT expr).
+ * Retrieve the clause within a 'not' clause
  */
-bool
-not_clause(Node *clause)
+Expr *
+get_notclausearg(Expr *notclause)
 {
-	return (clause != NULL &&
-			IsA(clause, Expr) &&
-			((Expr *) clause)->opType == NOT_EXPR);
+	return lfirst(((BoolExpr *) notclause)->args);
 }
 
+/*****************************************************************************
+ *		OR clause functions
+ *****************************************************************************/
+
 /*
- * make_notclause
+ * or_clause
  *
- * Create a 'not' clause given the expression to be negated.
+ * Returns t iff the clause is an 'or' clause: (OR { expr }).
  */
-Expr *
-make_notclause(Expr *notclause)
+bool
+or_clause(Node *clause)
 {
-	Expr	   *expr = makeNode(Expr);
-
-	expr->typeOid = BOOLOID;
-	expr->opType = NOT_EXPR;
-	expr->oper = NULL;
-	expr->args = makeList1(notclause);
-	return expr;
+	return (clause != NULL &&
+			IsA(clause, BoolExpr) &&
+			((BoolExpr *) clause)->boolop == OR_EXPR);
 }
 
 /*
- * get_notclausearg
+ * make_orclause
  *
- * Retrieve the clause within a 'not' clause
+ * Creates an 'or' clause given a list of its subclauses.
  */
 Expr *
-get_notclausearg(Expr *notclause)
+make_orclause(List *orclauses)
 {
-	return lfirst(notclause->args);
+	BoolExpr   *expr = makeNode(BoolExpr);
+
+	expr->boolop = OR_EXPR;
+	expr->args = orclauses;
+	return (Expr *) expr;
 }
 
 /*****************************************************************************
@@ -312,25 +256,23 @@ bool
 and_clause(Node *clause)
 {
 	return (clause != NULL &&
-			IsA(clause, Expr) &&
-			((Expr *) clause)->opType == AND_EXPR);
+			IsA(clause, BoolExpr) &&
+			((BoolExpr *) clause)->boolop == AND_EXPR);
 }
 
 /*
  * make_andclause
  *
- * Create an 'and' clause given its arguments in a list.
+ * Creates an 'and' clause given a list of its subclauses.
  */
 Expr *
 make_andclause(List *andclauses)
 {
-	Expr	   *expr = makeNode(Expr);
+	BoolExpr   *expr = makeNode(BoolExpr);
 
-	expr->typeOid = BOOLOID;
-	expr->opType = AND_EXPR;
-	expr->oper = NULL;
+	expr->boolop = AND_EXPR;
 	expr->args = andclauses;
-	return expr;
+	return (Expr *) expr;
 }
 
 /*
@@ -382,7 +324,7 @@ make_ands_implicit(Expr *clause)
 	if (clause == NULL)
 		return NIL;				/* NULL -> NIL list == TRUE */
 	else if (and_clause((Node *) clause))
-		return clause->args;
+		return ((BoolExpr *) clause)->args;
 	else if (IsA(clause, Const) &&
 			 !((Const *) clause)->constisnull &&
 			 DatumGetBool(((Const *) clause)->constvalue))
@@ -476,7 +418,7 @@ pull_agg_clause_walker(Node *node, List **listptr)
 		 * Complain if the aggregate's argument contains any aggregates;
 		 * nested agg functions are semantically nonsensical.
 		 */
-		if (contain_agg_clause(((Aggref *) node)->target))
+		if (contain_agg_clause((Node *) ((Aggref *) node)->target))
 			elog(ERROR, "Aggregate function calls may not be nested");
 
 		/*
@@ -512,38 +454,41 @@ expression_returns_set_walker(Node *node, void *context)
 {
 	if (node == NULL)
 		return false;
-	if (IsA(node, Expr))
+	if (IsA(node, FuncExpr))
 	{
-		Expr	   *expr = (Expr *) node;
+		FuncExpr   *expr = (FuncExpr *) node;
 
-		switch (expr->opType)
-		{
-			case OP_EXPR:
-			case DISTINCT_EXPR:
-				if (((Oper *) expr->oper)->opretset)
-					return true;
-				/* else fall through to check args */
-				break;
-			case FUNC_EXPR:
-				if (((Func *) expr->oper)->funcretset)
-					return true;
-				/* else fall through to check args */
-				break;
-			case OR_EXPR:
-			case AND_EXPR:
-			case NOT_EXPR:
-				/* Booleans can't return a set, so no need to recurse */
-				return false;
-			case SUBPLAN_EXPR:
-				/* Subplans can't presently return sets either */
-				return false;
-		}
+		if (expr->funcretset)
+			return true;
+		/* else fall through to check args */
+	}
+	if (IsA(node, OpExpr))
+	{
+		OpExpr   *expr = (OpExpr *) node;
+
+		if (expr->opretset)
+			return true;
+		/* else fall through to check args */
+	}
+	if (IsA(node, DistinctExpr))
+	{
+		DistinctExpr   *expr = (DistinctExpr *) node;
+
+		if (expr->opretset)
+			return true;
+		/* else fall through to check args */
 	}
-	/* Avoid recursion for some other cases that can't return a set */
+
+	/* Avoid recursion for some cases that can't return a set */
+	if (IsA(node, BoolExpr))
+		return false;
 	if (IsA(node, Aggref))
 		return false;
 	if (IsA(node, SubLink))
 		return false;
+	if (IsA(node, SubPlanExpr))
+		return false;
+
 	return expression_tree_walker(node, expression_returns_set_walker,
 								  context);
 }
@@ -574,7 +519,8 @@ contain_subplans_walker(Node *node, void *context)
 {
 	if (node == NULL)
 		return false;
-	if (is_subplan(node) || IsA(node, SubLink))
+	if (IsA(node, SubPlanExpr) ||
+		IsA(node, SubLink))
 		return true;			/* abort the tree traversal and return
 								 * true */
 	return expression_tree_walker(node, contain_subplans_walker, context);
@@ -584,8 +530,8 @@ contain_subplans_walker(Node *node, void *context)
  * pull_subplans
  *	  Recursively pulls all subplans from an expression tree.
  *
- *	  Returns list of subplan nodes found.	Note the nodes themselves are not
- *	  copied, only referenced.
+ *	  Returns list of SubPlanExpr nodes found.  Note the nodes themselves
+ *	  are not copied, only referenced.
  */
 List *
 pull_subplans(Node *clause)
@@ -603,7 +549,7 @@ pull_subplans_walker(Node *node, List **listptr)
 		return false;
 	if (is_subplan(node))
 	{
-		*listptr = lappend(*listptr, ((Expr *) node)->oper);
+		*listptr = lappend(*listptr, node);
 		/* fall through to check args to subplan */
 	}
 	return expression_tree_walker(node, pull_subplans_walker,
@@ -710,7 +656,7 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
 		 */
 		List	   *t;
 
-		foreach(t, ((Expr *) node)->args)
+		foreach(t, ((SubPlanExpr *) node)->args)
 		{
 			Node	   *thisarg = lfirst(t);
 			Var		   *var;
@@ -789,24 +735,29 @@ contain_mutable_functions_walker(Node *node, void *context)
 {
 	if (node == NULL)
 		return false;
-	if (IsA(node, Expr))
+	if (IsA(node, FuncExpr))
 	{
-		Expr	   *expr = (Expr *) node;
+		FuncExpr   *expr = (FuncExpr *) node;
 
-		switch (expr->opType)
-		{
-			case OP_EXPR:
-			case DISTINCT_EXPR:
-				if (op_volatile(((Oper *) expr->oper)->opno) != PROVOLATILE_IMMUTABLE)
-					return true;
-				break;
-			case FUNC_EXPR:
-				if (func_volatile(((Func *) expr->oper)->funcid) != PROVOLATILE_IMMUTABLE)
-					return true;
-				break;
-			default:
-				break;
-		}
+		if (func_volatile(expr->funcid) != PROVOLATILE_IMMUTABLE)
+			return true;
+		/* else fall through to check args */
+	}
+	if (IsA(node, OpExpr))
+	{
+		OpExpr   *expr = (OpExpr *) node;
+
+		if (op_volatile(expr->opno) != PROVOLATILE_IMMUTABLE)
+			return true;
+		/* else fall through to check args */
+	}
+	if (IsA(node, DistinctExpr))
+	{
+		DistinctExpr   *expr = (DistinctExpr *) node;
+
+		if (op_volatile(expr->opno) != PROVOLATILE_IMMUTABLE)
+			return true;
+		/* else fall through to check args */
 	}
 	return expression_tree_walker(node, contain_mutable_functions_walker,
 								  context);
@@ -839,24 +790,29 @@ contain_volatile_functions_walker(Node *node, void *context)
 {
 	if (node == NULL)
 		return false;
-	if (IsA(node, Expr))
+	if (IsA(node, FuncExpr))
 	{
-		Expr	   *expr = (Expr *) node;
+		FuncExpr   *expr = (FuncExpr *) node;
 
-		switch (expr->opType)
-		{
-			case OP_EXPR:
-			case DISTINCT_EXPR:
-				if (op_volatile(((Oper *) expr->oper)->opno) == PROVOLATILE_VOLATILE)
-					return true;
-				break;
-			case FUNC_EXPR:
-				if (func_volatile(((Func *) expr->oper)->funcid) == PROVOLATILE_VOLATILE)
-					return true;
-				break;
-			default:
-				break;
-		}
+		if (func_volatile(expr->funcid) == PROVOLATILE_VOLATILE)
+			return true;
+		/* else fall through to check args */
+	}
+	if (IsA(node, OpExpr))
+	{
+		OpExpr   *expr = (OpExpr *) node;
+
+		if (op_volatile(expr->opno) == PROVOLATILE_VOLATILE)
+			return true;
+		/* else fall through to check args */
+	}
+	if (IsA(node, DistinctExpr))
+	{
+		DistinctExpr   *expr = (DistinctExpr *) node;
+
+		if (op_volatile(expr->opno) == PROVOLATILE_VOLATILE)
+			return true;
+		/* else fall through to check args */
 	}
 	return expression_tree_walker(node, contain_volatile_functions_walker,
 								  context);
@@ -876,7 +832,7 @@ contain_volatile_functions_walker(Node *node, void *context)
  *
  * XXX we do not examine sublinks/subplans to see if they contain uses of
  * nonstrict functions.	It's not real clear if that is correct or not...
- * for the current usage it does not matter, since inline_op_or_func()
+ * for the current usage it does not matter, since inline_function()
  * rejects cases with sublinks.
  */
 bool
@@ -890,23 +846,33 @@ contain_nonstrict_functions_walker(Node *node, void *context)
 {
 	if (node == NULL)
 		return false;
-	if (IsA(node, Expr))
+	if (IsA(node, FuncExpr))
+	{
+		FuncExpr   *expr = (FuncExpr *) node;
+
+		if (!func_strict(expr->funcid))
+			return true;
+		/* else fall through to check args */
+	}
+	if (IsA(node, OpExpr))
+	{
+		OpExpr   *expr = (OpExpr *) node;
+
+		if (!op_strict(expr->opno))
+			return true;
+		/* else fall through to check args */
+	}
+	if (IsA(node, DistinctExpr))
+	{
+		/* IS DISTINCT FROM is inherently non-strict */
+		return true;
+	}
+	if (IsA(node, BoolExpr))
 	{
-		Expr	   *expr = (Expr *) node;
+		BoolExpr   *expr = (BoolExpr *) node;
 
-		switch (expr->opType)
+		switch (expr->boolop)
 		{
-			case OP_EXPR:
-				if (!op_strict(((Oper *) expr->oper)->opno))
-					return true;
-				break;
-			case DISTINCT_EXPR:
-				/* IS DISTINCT FROM is inherently non-strict */
-				return true;
-			case FUNC_EXPR:
-				if (!func_strict(((Func *) expr->oper)->funcid))
-					return true;
-				break;
 			case OR_EXPR:
 			case AND_EXPR:
 				/* OR, AND are inherently non-strict */
@@ -1147,39 +1113,28 @@ NumRelids(Node *clause)
  * XXX the clause is destructively modified!
  */
 void
-CommuteClause(Expr *clause)
+CommuteClause(OpExpr *clause)
 {
 	Oid			opoid;
-	HeapTuple	optup;
-	Form_pg_operator commuTup;
-	Oper	   *commu;
 	Node	   *temp;
 
-	if (!is_opclause((Node *) clause) ||
+	if (!is_opclause(clause) ||
 		length(clause->args) != 2)
 		elog(ERROR, "CommuteClause: applied to non-binary-operator clause");
 
-	opoid = ((Oper *) clause->oper)->opno;
-
-	optup = SearchSysCache(OPEROID,
-						   ObjectIdGetDatum(get_commutator(opoid)),
-						   0, 0, 0);
-	if (!HeapTupleIsValid(optup))
-		elog(ERROR, "CommuteClause: no commutator for operator %u", opoid);
-
-	commuTup = (Form_pg_operator) GETSTRUCT(optup);
+	opoid = get_commutator(clause->opno);
 
-	commu = makeOper(HeapTupleGetOid(optup),
-					 commuTup->oprcode,
-					 commuTup->oprresult,
-					 ((Oper *) clause->oper)->opretset);
-
-	ReleaseSysCache(optup);
+	if (!OidIsValid(opoid))
+		elog(ERROR, "CommuteClause: no commutator for operator %u",
+			 clause->opno);
 
 	/*
-	 * re-form the clause in-place!
+	 * modify the clause in-place!
 	 */
-	clause->oper = (Node *) commu;
+	clause->opno = opoid;
+	clause->opfuncid = InvalidOid;
+	/* opresulttype and opretset are assumed not to change */
+
 	temp = lfirst(clause->args);
 	lfirst(clause->args) = lsecond(clause->args);
 	lsecond(clause->args) = temp;
@@ -1223,15 +1178,94 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
 {
 	if (node == NULL)
 		return NULL;
-	if (IsA(node, Expr))
+	if (IsA(node, FuncExpr))
 	{
-		Expr	   *expr = (Expr *) node;
+		FuncExpr   *expr = (FuncExpr *) node;
 		List	   *args;
-		Const	   *const_input;
-		Expr	   *newexpr;
+		Expr	   *simple;
+		FuncExpr   *newexpr;
+
+		/*
+		 * Reduce constants in the FuncExpr's arguments.  We know args is
+		 * either NIL or a List node, so we can call
+		 * expression_tree_mutator directly rather than recursing to self.
+		 */
+		args = (List *) expression_tree_mutator((Node *) expr->args,
+										  eval_const_expressions_mutator,
+												(void *) active_fns);
+		/*
+		 * Code for op/func reduction is pretty bulky, so split it out
+		 * as a separate function.
+		 */
+		simple = simplify_function(expr->funcid, args, true, active_fns);
+		if (simple)				/* successfully simplified it */
+			return (Node *) simple;
+		/*
+		 * The expression cannot be simplified any further, so build and
+		 * return a replacement FuncExpr node using the possibly-simplified
+		 * arguments.
+		 */
+		newexpr = makeNode(FuncExpr);
+		newexpr->funcid = expr->funcid;
+		newexpr->funcresulttype = expr->funcresulttype;
+		newexpr->funcretset = expr->funcretset;
+		newexpr->funcformat = expr->funcformat;
+		newexpr->args = args;
+		return (Node *) newexpr;
+	}
+	if (IsA(node, OpExpr))
+	{
+		OpExpr	   *expr = (OpExpr *) node;
+		List	   *args;
+		Expr	   *simple;
+		OpExpr	   *newexpr;
 
 		/*
-		 * Reduce constants in the Expr's arguments.  We know args is
+		 * Reduce constants in the OpExpr's arguments.  We know args is
+		 * either NIL or a List node, so we can call
+		 * expression_tree_mutator directly rather than recursing to self.
+		 */
+		args = (List *) expression_tree_mutator((Node *) expr->args,
+										  eval_const_expressions_mutator,
+												(void *) active_fns);
+		/*
+		 * Need to get OID of underlying function.  Okay to scribble on
+		 * input to this extent.
+		 */
+		set_opfuncid(expr);
+		/*
+		 * Code for op/func reduction is pretty bulky, so split it out
+		 * as a separate function.
+		 */
+		simple = simplify_function(expr->opfuncid, args, true, active_fns);
+		if (simple)				/* successfully simplified it */
+			return (Node *) simple;
+		/*
+		 * The expression cannot be simplified any further, so build and
+		 * return a replacement OpExpr node using the possibly-simplified
+		 * arguments.
+		 */
+		newexpr = makeNode(OpExpr);
+		newexpr->opno = expr->opno;
+		newexpr->opfuncid = expr->opfuncid;
+		newexpr->opresulttype = expr->opresulttype;
+		newexpr->opretset = expr->opretset;
+		newexpr->args = args;
+		return (Node *) newexpr;
+	}
+	if (IsA(node, DistinctExpr))
+	{
+		DistinctExpr *expr = (DistinctExpr *) node;
+		List	   *args;
+		List	   *arg;
+		bool		has_null_input = false;
+		bool		all_null_input = true;
+		bool		has_nonconst_input = false;
+		Expr	   *simple;
+		DistinctExpr *newexpr;
+
+		/*
+		 * Reduce constants in the DistinctExpr's arguments.  We know args is
 		 * either NIL or a List node, so we can call
 		 * expression_tree_mutator directly rather than recursing to self.
 		 */
@@ -1239,76 +1273,83 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
 										  eval_const_expressions_mutator,
 												(void *) active_fns);
 
-		switch (expr->opType)
+		/*
+		 * We must do our own check for NULLs because
+		 * DistinctExpr has different results for NULL input
+		 * than the underlying operator does.
+		 */
+		foreach(arg, args)
 		{
-			case OP_EXPR:
-			case FUNC_EXPR:
+			if (IsA(lfirst(arg), Const))
+			{
+				has_null_input |= ((Const *) lfirst(arg))->constisnull;
+				all_null_input &= ((Const *) lfirst(arg))->constisnull;
+			}
+			else
+				has_nonconst_input = true;
+		}
 
-				/*
-				 * Code for op/func case is pretty bulky, so split it out
-				 * as a separate function.
-				 */
-				newexpr = simplify_op_or_func(expr, args,
-											  true, active_fns);
-				if (newexpr)	/* successfully simplified it */
-					return (Node *) newexpr;
+		/* all constants? then can optimize this out */
+		if (!has_nonconst_input)
+		{
+			/* all nulls? then not distinct */
+			if (all_null_input)
+				return MAKEBOOLCONST(false, false);
 
-				/*
-				 * else fall out to build new Expr node with simplified
-				 * args
-				 */
-				break;
-			case DISTINCT_EXPR:
-				{
-					List	   *arg;
-					bool		has_null_input = false;
-					bool		all_null_input = true;
-					bool		has_nonconst_input = false;
+			/* one null? then distinct */
+			if (has_null_input)
+				return MAKEBOOLCONST(true, false);
 
-					/*
-					 * We must do our own check for NULLs because
-					 * DISTINCT_EXPR has different results for NULL input
-					 * than the underlying operator does.
-					 */
-					foreach(arg, args)
-					{
-						if (IsA(lfirst(arg), Const))
-						{
-							has_null_input |= ((Const *) lfirst(arg))->constisnull;
-							all_null_input &= ((Const *) lfirst(arg))->constisnull;
-						}
-						else
-							has_nonconst_input = true;
-					}
+			/* otherwise try to evaluate the '=' operator */
+			/* (NOT okay to try to inline it, though!) */
 
-					/* all constants? then can optimize this out */
-					if (!has_nonconst_input)
-					{
-						/* all nulls? then not distinct */
-						if (all_null_input)
-							return MAKEBOOLCONST(false, false);
-
-						/* one null? then distinct */
-						if (has_null_input)
-							return MAKEBOOLCONST(true, false);
-
-						/* otherwise try to evaluate the '=' operator */
-						/* (NOT okay to try to inline it, though!) */
-						newexpr = simplify_op_or_func(expr, args,
-													  false, active_fns);
-						if (newexpr)	/* successfully simplified it */
-							return (Node *) newexpr;
-					}
+			/*
+			 * Need to get OID of underlying function.  Okay to scribble on
+			 * input to this extent.
+			 */
+			set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
+			/*
+			 * Code for op/func reduction is pretty bulky, so split it out
+			 * as a separate function.
+			 */
+			simple = simplify_function(expr->opfuncid, args,
+									   false, active_fns);
+			if (simple)			/* successfully simplified it */
+				return (Node *) simple;
+		}
 
-					/*
-					 * else fall out to build new Expr node with simplified
-					 * args
-					 */
-					break;
-				}
+		/*
+		 * The expression cannot be simplified any further, so build and
+		 * return a replacement DistinctExpr node using the
+		 * possibly-simplified arguments.
+		 */
+		newexpr = makeNode(DistinctExpr);
+		newexpr->opno = expr->opno;
+		newexpr->opfuncid = expr->opfuncid;
+		newexpr->opresulttype = expr->opresulttype;
+		newexpr->opretset = expr->opretset;
+		newexpr->args = args;
+		return (Node *) newexpr;
+	}
+	if (IsA(node, BoolExpr))
+	{
+		BoolExpr   *expr = (BoolExpr *) node;
+		List	   *args;
+		Const	   *const_input;
+
+		/*
+		 * Reduce constants in the BoolExpr's arguments.  We know args is
+		 * either NIL or a List node, so we can call
+		 * expression_tree_mutator directly rather than recursing to self.
+		 */
+		args = (List *) expression_tree_mutator((Node *) expr->args,
+										  eval_const_expressions_mutator,
+												(void *) active_fns);
+
+		switch (expr->boolop)
+		{
 			case OR_EXPR:
 				{
-
 					/*----------
 					 * OR arguments are handled as follows:
 					 *	non constant: keep
@@ -1361,7 +1402,6 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
 				}
 			case AND_EXPR:
 				{
-
 					/*----------
 					 * AND arguments are handled as follows:
 					 *	non constant: keep
@@ -1414,47 +1454,34 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
 				}
 			case NOT_EXPR:
 				Assert(length(args) == 1);
-				if (!IsA(lfirst(args), Const))
-					break;
-				const_input = (Const *) lfirst(args);
-				/* NOT NULL => NULL */
-				if (const_input->constisnull)
-					return MAKEBOOLCONST(false, true);
-				/* otherwise pretty easy */
-				return MAKEBOOLCONST(!DatumGetBool(const_input->constvalue),
-									 false);
-			case SUBPLAN_EXPR:
-
-				/*
-				 * Return a SubPlan unchanged --- too late to do anything
-				 * with it.  The arglist simplification above was wasted
-				 * work (the list probably only contains Var nodes
-				 * anyway).
-				 *
-				 * XXX should we elog() here instead?  Probably this routine
-				 * should never be invoked after SubPlan creation.
-				 */
-				return (Node *) expr;
+				if (IsA(lfirst(args), Const))
+				{
+					const_input = (Const *) lfirst(args);
+					/* NOT NULL => NULL */
+					if (const_input->constisnull)
+						return MAKEBOOLCONST(false, true);
+					/* otherwise pretty easy */
+					return MAKEBOOLCONST(!DatumGetBool(const_input->constvalue),
+										 false);
+				}
+				/* Else we still need a NOT node */
+				return (Node *) make_notclause(lfirst(args));
 			default:
-				elog(ERROR, "eval_const_expressions: unexpected opType %d",
-					 (int) expr->opType);
+				elog(ERROR, "eval_const_expressions: unexpected boolop %d",
+					 (int) expr->boolop);
 				break;
 		}
-
+	}
+	if (IsA(node, SubPlanExpr))
+	{
 		/*
-		 * If we break out of the above switch on opType, then the
-		 * expression cannot be simplified any further, so build and
-		 * return a replacement Expr node using the possibly-simplified
-		 * arguments and the original oper node. Can't use make_clause()
-		 * here because we want to be sure the typeOid field is
-		 * preserved...
+		 * Return a SubPlanExpr unchanged --- too late to do anything
+		 * with it.
+		 *
+		 * XXX should we elog() here instead?  Probably this routine
+		 * should never be invoked after SubPlanExpr creation.
 		 */
-		newexpr = makeNode(Expr);
-		newexpr->typeOid = expr->typeOid;
-		newexpr->opType = expr->opType;
-		newexpr->oper = expr->oper;
-		newexpr->args = args;
-		return (Node *) newexpr;
+		return node;
 	}
 	if (IsA(node, RelabelType))
 	{
@@ -1466,14 +1493,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
 		RelabelType *relabel = (RelabelType *) node;
 		Node	   *arg;
 
-		arg = eval_const_expressions_mutator(relabel->arg, active_fns);
+		arg = eval_const_expressions_mutator((Node *) relabel->arg,
+											 active_fns);
 
 		/*
 		 * If we find stacked RelabelTypes (eg, from foo :: int :: oid) we
 		 * can discard all but the top one.
 		 */
 		while (arg && IsA(arg, RelabelType))
-			arg = ((RelabelType *) arg)->arg;
+			arg = (Node *) ((RelabelType *) arg)->arg;
 
 		if (arg && IsA(arg, Const))
 		{
@@ -1493,7 +1521,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
 		{
 			RelabelType *newrelabel = makeNode(RelabelType);
 
-			newrelabel->arg = arg;
+			newrelabel->arg = (Expr *) arg;
 			newrelabel->resulttype = relabel->resulttype;
 			newrelabel->resulttypmod = relabel->resulttypmod;
 			return (Node *) newrelabel;
@@ -1545,7 +1573,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
 			 * alternative, the CASE reduces to just this alternative.
 			 */
 			if (newargs == NIL)
-				return casewhen->result;
+				return (Node *) casewhen->result;
 
 			/*
 			 * Otherwise, add it to the list, and drop all the rest.
@@ -1555,7 +1583,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
 		}
 
 		/* Simplify the default result */
-		defresult = eval_const_expressions_mutator(caseexpr->defresult,
+		defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult,
 												   active_fns);
 
 		/*
@@ -1569,7 +1597,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
 		newcase->casetype = caseexpr->casetype;
 		newcase->arg = NULL;
 		newcase->args = newargs;
-		newcase->defresult = defresult;
+		newcase->defresult = (Expr *) defresult;
 		return (Node *) newcase;
 	}
 
@@ -1585,19 +1613,18 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
 }
 
 /*
- * Subroutine for eval_const_expressions: try to simplify an op or func
+ * Subroutine for eval_const_expressions: try to simplify a function call
+ * (which might originally have been an operator; we don't care)
  *
- * Inputs are the op or func Expr node, and the pre-simplified argument list;
+ * Inputs are the function OID and the pre-simplified argument list;
  * also a list of already-active inline function expansions.
  *
  * Returns a simplified expression if successful, or NULL if cannot
- * simplify the op/func.
+ * simplify the function call.
  */
 static Expr *
-simplify_op_or_func(Expr *expr, List *args, bool allow_inline,
-					List *active_fns)
+simplify_function(Oid funcid, List *args, bool allow_inline, List *active_fns)
 {
-	Oid			funcid;
 	HeapTuple	func_tuple;
 	Expr	   *newexpr;
 
@@ -1609,30 +1636,16 @@ simplify_op_or_func(Expr *expr, List *args, bool allow_inline,
 	 * to the function's pg_proc tuple, so fetch it just once to use in both
 	 * attempts.
 	 */
-	if (expr->opType == FUNC_EXPR)
-	{
-		Func	   *func = (Func *) expr->oper;
-
-		funcid = func->funcid;
-	}
-	else						/* OP_EXPR or DISTINCT_EXPR */
-	{
-		Oper	   *oper = (Oper *) expr->oper;
-
-		replace_opid(oper);		/* OK to scribble on input to this extent */
-		funcid = oper->opid;
-	}
-
 	func_tuple = SearchSysCache(PROCOID,
 								ObjectIdGetDatum(funcid),
 								0, 0, 0);
 	if (!HeapTupleIsValid(func_tuple))
 		elog(ERROR, "Function OID %u does not exist", funcid);
 
-	newexpr = evaluate_op_or_func(expr, args, func_tuple);
+	newexpr = evaluate_function(funcid, args, func_tuple);
 
 	if (!newexpr && allow_inline)
-		newexpr = inline_op_or_func(expr, args, func_tuple, active_fns);
+		newexpr = inline_function(funcid, args, func_tuple, active_fns);
 
 	ReleaseSysCache(func_tuple);
 
@@ -1640,17 +1653,17 @@ simplify_op_or_func(Expr *expr, List *args, bool allow_inline,
 }
 
 /*
- * evaluate_op_or_func: try to pre-evaluate an op or func
+ * evaluate_function: try to pre-evaluate a function call
  *
  * We can do this if the function is strict and has any constant-null inputs
  * (just return a null constant), or if the function is immutable and has all
  * constant inputs (call it and return the result as a Const node).
  *
  * Returns a simplified expression if successful, or NULL if cannot
- * simplify the op/func.
+ * simplify the function.
  */
 static Expr *
-evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple)
+evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
 {
 	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
 	Oid			result_typeid = funcform->prorettype;
@@ -1658,7 +1671,7 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple)
 	bool		resultTypByVal;
 	bool		has_nonconst_input = false;
 	bool		has_null_input = false;
-	Expr	   *newexpr;
+	FuncExpr   *newexpr;
 	ExprContext *econtext;
 	Datum		const_val;
 	bool		const_is_null;
@@ -1705,21 +1718,20 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple)
 	 * We use the executor's routine ExecEvalExpr() to avoid duplication of
 	 * code and ensure we get the same result as the executor would get.
 	 *
-	 * Build a new Expr node containing the already-simplified arguments.
-	 * The only other setup needed here is the replace_opid() that
-	 * simplify_op_or_func already did for the OP_EXPR/DISTINCT_EXPR case.
+	 * Build a new FuncExpr node containing the already-simplified arguments.
 	 */
-	newexpr = makeNode(Expr);
-	newexpr->typeOid = expr->typeOid;
-	newexpr->opType = expr->opType;
-	newexpr->oper = expr->oper;
+	newexpr = makeNode(FuncExpr);
+	newexpr->funcid = funcid;
+	newexpr->funcresulttype = result_typeid;
+	newexpr->funcretset = false;
+	newexpr->funcformat = COERCE_EXPLICIT_CALL;	/* doesn't matter */
 	newexpr->args = args;
 
 	/* Get info needed about result datatype */
 	get_typlenbyval(result_typeid, &resultTypLen, &resultTypByVal);
 
 	/*
-	 * It is OK to pass a dummy econtext because none of the
+	 * It is OK to use a dummy econtext because none of the
 	 * ExecEvalExpr() code used in this situation will use econtext.  That
 	 * might seem fortuitous, but it's not so unreasonable --- a constant
 	 * expression does not depend on context, by definition, n'est ce pas?
@@ -1745,7 +1757,7 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple)
 }
 
 /*
- * inline_op_or_func: try to expand inline an op or func
+ * inline_function: try to expand a function call inline
  *
  * If the function is a sufficiently simple SQL-language function
  * (just "SELECT expression"), then we can inline it and avoid the rather
@@ -1763,14 +1775,13 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple)
  * functions by inlining them.
  *
  * Returns a simplified expression if successful, or NULL if cannot
- * simplify the op/func.
+ * simplify the function.
  */
 static Expr *
-inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple,
-				  List *active_fns)
+inline_function(Oid funcid, List *args, HeapTuple func_tuple,
+				List *active_fns)
 {
 	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
-	Oid			funcid = HeapTupleGetOid(func_tuple);
 	Oid			result_typeid = funcform->prorettype;
 	char		result_typtype;
 	char	   *src;
@@ -1816,7 +1827,7 @@ inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple,
 	 * stuff that parsing might create.
 	 */
 	mycxt = AllocSetContextCreate(CurrentMemoryContext,
-								  "inline_op_or_func",
+								  "inline_function",
 								  ALLOCSET_DEFAULT_MINSIZE,
 								  ALLOCSET_DEFAULT_INITSIZE,
 								  ALLOCSET_DEFAULT_MAXSIZE);
@@ -1828,7 +1839,7 @@ inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple,
 						  Anum_pg_proc_prosrc,
 						  &isNull);
 	if (isNull)
-		elog(ERROR, "inline_op_or_func: null prosrc for procedure %u",
+		elog(ERROR, "inline_function: null prosrc for procedure %u",
 			 funcid);
 	src = DatumGetCString(DirectFunctionCall1(textout, tmp));
 
@@ -1877,7 +1888,7 @@ inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple,
 		length(querytree->targetList) != 1)
 		goto fail;
 
-	newexpr = ((TargetEntry *) lfirst(querytree->targetList))->expr;
+	newexpr = (Node *) ((TargetEntry *) lfirst(querytree->targetList))->expr;
 
 	/*
 	 * Additional validity checks on the expression.  It mustn't return a
@@ -2065,17 +2076,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 SubPlan nodes by recursing
- * normally into the "lefthand" arguments (which belong 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 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:
  *
  *		if (IsA(node, Query))
  *		{
@@ -2115,29 +2126,12 @@ expression_tree_walker(Node *node,
 		return false;
 	switch (nodeTag(node))
 	{
-		case T_Const:
 		case T_Var:
+		case T_Const:
 		case T_Param:
 		case T_RangeTblRef:
 			/* primitive node types with no subnodes */
 			break;
-		case T_Expr:
-			{
-				Expr	   *expr = (Expr *) node;
-
-				if (expr->opType == SUBPLAN_EXPR)
-				{
-					/* recurse to the SubLink node (skipping SubPlan!) */
-					if (walker((Node *) ((SubPlan *) expr->oper)->sublink,
-							   context))
-						return true;
-				}
-				/* for all Expr node types, examine args list */
-				if (expression_tree_walker((Node *) expr->args,
-										   walker, context))
-					return true;
-			}
-			break;
 		case T_Aggref:
 			return walker(((Aggref *) node)->target, context);
 		case T_ArrayRef:
@@ -2158,41 +2152,41 @@ expression_tree_walker(Node *node,
 					return true;
 			}
 			break;
-		case T_FieldSelect:
-			return walker(((FieldSelect *) node)->arg, context);
-		case T_RelabelType:
-			return walker(((RelabelType *) node)->arg, context);
-		case T_CaseExpr:
+		case T_FuncExpr:
 			{
-				CaseExpr   *caseexpr = (CaseExpr *) node;
+				FuncExpr   *expr = (FuncExpr *) node;
 
-				/* we assume walker doesn't care about CaseWhens, either */
-				foreach(temp, caseexpr->args)
-				{
-					CaseWhen   *when = (CaseWhen *) lfirst(temp);
+				if (expression_tree_walker((Node *) expr->args,
+										   walker, context))
+					return true;
+			}
+			break;
+		case T_OpExpr:
+			{
+				OpExpr	   *expr = (OpExpr *) node;
 
-					Assert(IsA(when, CaseWhen));
-					if (walker(when->expr, context))
-						return true;
-					if (walker(when->result, context))
-						return true;
-				}
-				/* caseexpr->arg should be null, but we'll check it anyway */
-				if (walker(caseexpr->arg, context))
+				if (expression_tree_walker((Node *) expr->args,
+										   walker, context))
 					return true;
-				if (walker(caseexpr->defresult, context))
+			}
+			break;
+		case T_DistinctExpr:
+			{
+				DistinctExpr *expr = (DistinctExpr *) node;
+
+				if (expression_tree_walker((Node *) expr->args,
+										   walker, context))
 					return true;
 			}
 			break;
-		case T_NullTest:
-			return walker(((NullTest *) node)->arg, context);
-		case T_BooleanTest:
-			return walker(((BooleanTest *) node)->arg, context);
-		case T_ConstraintTest:
-			if (walker(((ConstraintTest *) node)->arg, context))
-				return true;
-			return walker(((ConstraintTest *) node)->check_expr, context);
-		case T_ConstraintTestValue:
+		case T_BoolExpr:
+			{
+				BoolExpr   *expr = (BoolExpr *) node;
+
+				if (expression_tree_walker((Node *) expr->args,
+										   walker, context))
+					return true;
+			}
 			break;
 		case T_SubLink:
 			{
@@ -2202,7 +2196,7 @@ expression_tree_walker(Node *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 Oper nodes in the
+				 * the lefthand list (the incomplete OpExpr nodes in the
 				 * oper list are deemed uninteresting, perhaps even
 				 * confusing).
 				 */
@@ -2224,6 +2218,57 @@ expression_tree_walker(Node *node,
 				return walker(sublink->subselect, context);
 			}
 			break;
+		case T_SubPlanExpr:
+			{
+				SubPlanExpr *expr = (SubPlanExpr *) node;
+
+				/* recurse to the SubLink node, but not into the Plan */
+				if (walker((Node *) expr->sublink, context))
+					return true;
+				/* also examine args list */
+				if (expression_tree_walker((Node *) expr->args,
+										   walker, context))
+					return true;
+			}
+			break;
+		case T_FieldSelect:
+			return walker(((FieldSelect *) node)->arg, context);
+		case T_RelabelType:
+			return walker(((RelabelType *) node)->arg, context);
+		case T_CaseExpr:
+			{
+				CaseExpr   *caseexpr = (CaseExpr *) node;
+
+				/* we assume walker doesn't care about CaseWhens, either */
+				foreach(temp, caseexpr->args)
+				{
+					CaseWhen   *when = (CaseWhen *) lfirst(temp);
+
+					Assert(IsA(when, CaseWhen));
+					if (walker(when->expr, context))
+						return true;
+					if (walker(when->result, context))
+						return true;
+				}
+				/* caseexpr->arg should be null, but we'll check it anyway */
+				if (walker(caseexpr->arg, context))
+					return true;
+				if (walker(caseexpr->defresult, context))
+					return true;
+			}
+			break;
+		case T_NullTest:
+			return walker(((NullTest *) node)->arg, context);
+		case T_BooleanTest:
+			return walker(((BooleanTest *) node)->arg, context);
+		case T_ConstraintTest:
+			if (walker(((ConstraintTest *) node)->arg, context))
+				return true;
+			return walker(((ConstraintTest *) node)->check_expr, context);
+		case T_ConstraintTestValue:
+			break;
+		case T_TargetEntry:
+			return walker(((TargetEntry *) node)->expr, context);
 		case T_Query:
 			/* Do nothing with a sub-Query, per discussion above */
 			break;
@@ -2234,8 +2279,6 @@ expression_tree_walker(Node *node,
 					return true;
 			}
 			break;
-		case T_TargetEntry:
-			return walker(((TargetEntry *) node)->expr, context);
 		case T_FromExpr:
 			{
 				FromExpr   *from = (FromExpr *) node;
@@ -2387,14 +2430,14 @@ 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 SUBPLAN_EXPR node by recursing into
- * the args and slink->oper lists (which belong to the outer plan), but it
+ * 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
  * 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
  * and doing the right thing.
  *
- * Bare SubLink nodes (without a SUBPLAN_EXPR) are handled by recursing into
+ * 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
@@ -2428,61 +2471,19 @@ expression_tree_mutator(Node *node,
 		return NULL;
 	switch (nodeTag(node))
 	{
-		case T_Const:
 		case T_Var:
+		case T_Const:
 		case T_Param:
 		case T_RangeTblRef:
 			/* primitive node types with no subnodes */
 			return (Node *) copyObject(node);
-		case T_Expr:
-			{
-				Expr	   *expr = (Expr *) node;
-				Expr	   *newnode;
-
-				FLATCOPY(newnode, expr, Expr);
-
-				if (expr->opType == SUBPLAN_EXPR)
-				{
-					SubLink    *oldsublink = ((SubPlan *) expr->oper)->sublink;
-					SubPlan    *newsubplan;
-
-					/* flat-copy the oper node, which is a SubPlan */
-					CHECKFLATCOPY(newsubplan, expr->oper, SubPlan);
-					newnode->oper = (Node *) newsubplan;
-					/* likewise its SubLink node */
-					CHECKFLATCOPY(newsubplan->sublink, oldsublink, SubLink);
-
-					/*
-					 * transform args list (params to be passed to
-					 * subplan)
-					 */
-					MUTATE(newnode->args, expr->args, List *);
-					/* transform sublink's oper list as well */
-					MUTATE(newsubplan->sublink->oper, oldsublink->oper, List *);
-
-					/*
-					 * but not the subplan itself, which is referenced
-					 * as-is
-					 */
-				}
-				else
-				{
-					/*
-					 * for other Expr node types, just transform args
-					 * list, linking to original oper node (OK?)
-					 */
-					MUTATE(newnode->args, expr->args, List *);
-				}
-				return (Node *) newnode;
-			}
-			break;
 		case T_Aggref:
 			{
 				Aggref	   *aggref = (Aggref *) node;
 				Aggref	   *newnode;
 
 				FLATCOPY(newnode, aggref, Aggref);
-				MUTATE(newnode->target, aggref->target, Node *);
+				MUTATE(newnode->target, aggref->target, Expr *);
 				return (Node *) newnode;
 			}
 			break;
@@ -2497,9 +2498,81 @@ expression_tree_mutator(Node *node,
 				MUTATE(newnode->reflowerindexpr, arrayref->reflowerindexpr,
 					   List *);
 				MUTATE(newnode->refexpr, arrayref->refexpr,
-					   Node *);
+					   Expr *);
 				MUTATE(newnode->refassgnexpr, arrayref->refassgnexpr,
-					   Node *);
+					   Expr *);
+				return (Node *) newnode;
+			}
+			break;
+		case T_FuncExpr:
+			{
+				FuncExpr   *expr = (FuncExpr *) node;
+				FuncExpr   *newnode;
+
+				FLATCOPY(newnode, expr, FuncExpr);
+				MUTATE(newnode->args, expr->args, List *);
+				return (Node *) newnode;
+			}
+			break;
+		case T_OpExpr:
+			{
+				OpExpr	   *expr = (OpExpr *) node;
+				OpExpr	   *newnode;
+
+				FLATCOPY(newnode, expr, OpExpr);
+				MUTATE(newnode->args, expr->args, List *);
+				return (Node *) newnode;
+			}
+			break;
+		case T_DistinctExpr:
+			{
+				DistinctExpr   *expr = (DistinctExpr *) node;
+				DistinctExpr   *newnode;
+
+				FLATCOPY(newnode, expr, DistinctExpr);
+				MUTATE(newnode->args, expr->args, List *);
+				return (Node *) newnode;
+			}
+			break;
+		case T_BoolExpr:
+			{
+				BoolExpr   *expr = (BoolExpr *) node;
+				BoolExpr   *newnode;
+
+				FLATCOPY(newnode, expr, BoolExpr);
+				MUTATE(newnode->args, expr->args, List *);
+				return (Node *) newnode;
+			}
+			break;
+		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.
+				 */
+				SubLink    *sublink = (SubLink *) node;
+				SubLink    *newnode;
+
+				FLATCOPY(newnode, sublink, SubLink);
+				MUTATE(newnode->lefthand, sublink->lefthand, List *);
+				return (Node *) newnode;
+			}
+			break;
+		case T_SubPlanExpr:
+			{
+				SubPlanExpr   *expr = (SubPlanExpr *) node;
+				SubLink		  *oldsublink = expr->sublink;
+				SubPlanExpr   *newnode;
+
+				FLATCOPY(newnode, expr, SubPlanExpr);
+				/* flat-copy the SubLink node */
+				CHECKFLATCOPY(newnode->sublink, oldsublink, SubLink);
+				/* 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 */
 				return (Node *) newnode;
 			}
 			break;
@@ -2509,7 +2582,7 @@ expression_tree_mutator(Node *node,
 				FieldSelect *newnode;
 
 				FLATCOPY(newnode, fselect, FieldSelect);
-				MUTATE(newnode->arg, fselect->arg, Node *);
+				MUTATE(newnode->arg, fselect->arg, Expr *);
 				return (Node *) newnode;
 			}
 			break;
@@ -2519,7 +2592,7 @@ expression_tree_mutator(Node *node,
 				RelabelType *newnode;
 
 				FLATCOPY(newnode, relabel, RelabelType);
-				MUTATE(newnode->arg, relabel->arg, Node *);
+				MUTATE(newnode->arg, relabel->arg, Expr *);
 				return (Node *) newnode;
 			}
 			break;
@@ -2531,8 +2604,8 @@ expression_tree_mutator(Node *node,
 				FLATCOPY(newnode, caseexpr, CaseExpr);
 				MUTATE(newnode->args, caseexpr->args, List *);
 				/* caseexpr->arg should be null, but we'll check it anyway */
-				MUTATE(newnode->arg, caseexpr->arg, Node *);
-				MUTATE(newnode->defresult, caseexpr->defresult, Node *);
+				MUTATE(newnode->arg, caseexpr->arg, Expr *);
+				MUTATE(newnode->defresult, caseexpr->defresult, Expr *);
 				return (Node *) newnode;
 			}
 			break;
@@ -2542,8 +2615,8 @@ expression_tree_mutator(Node *node,
 				CaseWhen   *newnode;
 
 				FLATCOPY(newnode, casewhen, CaseWhen);
-				MUTATE(newnode->expr, casewhen->expr, Node *);
-				MUTATE(newnode->result, casewhen->result, Node *);
+				MUTATE(newnode->expr, casewhen->expr, Expr *);
+				MUTATE(newnode->result, casewhen->result, Expr *);
 				return (Node *) newnode;
 			}
 			break;
@@ -2553,7 +2626,7 @@ expression_tree_mutator(Node *node,
 				NullTest   *newnode;
 
 				FLATCOPY(newnode, ntest, NullTest);
-				MUTATE(newnode->arg, ntest->arg, Node *);
+				MUTATE(newnode->arg, ntest->arg, Expr *);
 				return (Node *) newnode;
 			}
 			break;
@@ -2563,7 +2636,7 @@ expression_tree_mutator(Node *node,
 				BooleanTest *newnode;
 
 				FLATCOPY(newnode, btest, BooleanTest);
-				MUTATE(newnode->arg, btest->arg, Node *);
+				MUTATE(newnode->arg, btest->arg, Expr *);
 				return (Node *) newnode;
 			}
 			break;
@@ -2573,8 +2646,8 @@ expression_tree_mutator(Node *node,
 				ConstraintTest *newnode;
 
 				FLATCOPY(newnode, ctest, ConstraintTest);
-				MUTATE(newnode->arg, ctest->arg, Node *);
-				MUTATE(newnode->check_expr, ctest->check_expr, Node *);
+				MUTATE(newnode->arg, ctest->arg, Expr *);
+				MUTATE(newnode->check_expr, ctest->check_expr, Expr *);
 				return (Node *) newnode;
 			}
 			break;
@@ -2587,18 +2660,17 @@ expression_tree_mutator(Node *node,
 				return (Node *) newnode;
 			}
 			break;
-		case T_SubLink:
+		case T_TargetEntry:
 			{
 				/*
-				 * A "bare" SubLink (note we will not come here if we
-				 * found a SUBPLAN_EXPR node above it).  Transform the
-				 * lefthand side, but not the oper list nor the subquery.
+				 * We mutate the expression, but not the resdom, by
+				 * default.
 				 */
-				SubLink    *sublink = (SubLink *) node;
-				SubLink    *newnode;
+				TargetEntry *targetentry = (TargetEntry *) node;
+				TargetEntry *newnode;
 
-				FLATCOPY(newnode, sublink, SubLink);
-				MUTATE(newnode->lefthand, sublink->lefthand, List *);
+				FLATCOPY(newnode, targetentry, TargetEntry);
+				MUTATE(newnode->expr, targetentry->expr, Expr *);
 				return (Node *) newnode;
 			}
 			break;
@@ -2622,20 +2694,6 @@ expression_tree_mutator(Node *node,
 				return (Node *) resultlist;
 			}
 			break;
-		case T_TargetEntry:
-			{
-				/*
-				 * We mutate the expression, but not the resdom, by
-				 * default.
-				 */
-				TargetEntry *targetentry = (TargetEntry *) node;
-				TargetEntry *newnode;
-
-				FLATCOPY(newnode, targetentry, TargetEntry);
-				MUTATE(newnode->expr, targetentry->expr, Node *);
-				return (Node *) newnode;
-			}
-			break;
 		case T_FromExpr:
 			{
 				FromExpr   *from = (FromExpr *) node;
diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c
index fa8c89862f4d0b3d1376e4816c0feb1da9ebdff0..0d268b8e40cb66750be062131f96edb62471827b 100644
--- a/src/backend/optimizer/util/tlist.c
+++ b/src/backend/optimizer/util/tlist.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.52 2002/06/20 20:29:31 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.53 2002/12/12 15:49:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -110,7 +110,7 @@ create_tl_element(Var *var, int resdomno)
 									  var->vartypmod,
 									  NULL,
 									  false),
-						   (Node *) var);
+						   (Expr *) var);
 }
 
 /*****************************************************************************
@@ -253,5 +253,5 @@ get_sortgroupclause_expr(SortClause *sortClause, List *targetList)
 {
 	TargetEntry *tle = get_sortgroupclause_tle(sortClause, targetList);
 
-	return tle->expr;
+	return (Node *) tle->expr;
 }
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index 23b824dbcb019d239ee32ba79c3b44198645220c..8d22aa26b9144147956423135e9a41271c679c3d 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.40 2002/09/11 14:48:54 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.41 2002/12/12 15:49:33 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
- * SubPlan, we only need to look at the parameters passed to the subplan.
+ * SubPlanExpr, we only need to look at the parameters passed to the subplan.
  */
 List *
 pull_varnos(Node *node)
@@ -111,12 +111,12 @@ 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.
 		 */
-		Expr	   *expr = (Expr *) node;
+		SubPlanExpr *subplan = (SubPlanExpr *) node;
 
-		if (pull_varnos_walker((Node *) ((SubPlan *) expr->oper)->sublink->oper,
+		if (pull_varnos_walker((Node *) subplan->sublink->oper,
 							   context))
 			return true;
-		if (pull_varnos_walker((Node *) expr->args,
+		if (pull_varnos_walker((Node *) subplan->args,
 							   context))
 			return true;
 		return false;
@@ -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
- * SubPlan, we only need to look at the parameters passed to the subplan.
+ * SubPlanExpr, 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,12 +194,12 @@ 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.
 		 */
-		Expr	   *expr = (Expr *) node;
+		SubPlanExpr *subplan = (SubPlanExpr *) node;
 
-		if (contain_var_reference_walker((Node *) ((SubPlan *) expr->oper)->sublink->oper,
+		if (contain_var_reference_walker((Node *) subplan->sublink->oper,
 										 context))
 			return true;
-		if (contain_var_reference_walker((Node *) expr->args,
+		if (contain_var_reference_walker((Node *) subplan->args,
 										 context))
 			return true;
 		return false;
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 18144f7b94136c904258afdf9e31e3ce8529b696..56f0fdd955a4f79ecca798a55624d36ead4f5569 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.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/parser/analyze.c,v 1.254 2002/11/15 02:50:07 momjian Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.255 2002/12/12 15:49:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -479,14 +479,14 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
 		{
 			TargetEntry *tle = (TargetEntry *) lfirst(tl);
 			Resdom	   *resnode = tle->resdom;
-			Node	   *expr;
+			Expr	   *expr;
 
 			if (resnode->resjunk)
 				continue;
 			if (tle->expr && IsA(tle->expr, Const))
 				expr = tle->expr;
 			else
-				expr = (Node *) makeVar(rtr->rtindex,
+				expr = (Expr *) makeVar(rtr->rtindex,
 										resnode->resno,
 										resnode->restype,
 										resnode->restypmod,
@@ -1807,14 +1807,14 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 		Resdom	   *leftResdom = ((TargetEntry *) lfirst(lefttl))->resdom;
 		char	   *colName = pstrdup(leftResdom->resname);
 		Resdom	   *resdom;
-		Node	   *expr;
+		Expr	   *expr;
 
 		resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
 							colType,
 							-1,
 							colName,
 							false);
-		expr = (Node *) makeVar(1,
+		expr = (Expr *) makeVar(1,
 								leftResdom->resno,
 								colType,
 								-1,
@@ -2424,7 +2424,7 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
 					 format_type_be(given_type_id),
 					 format_type_be(expected_type_id));
 
-			fix_opids(expr);
+			fix_opfuncids(expr);
 
 			lfirst(l) = expr;
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index b3edb3b5505e43461390a5c18181f141ae0179e5..53e1a5999fed52e5a032f11057b35c2460331c29 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.386 2002/12/06 05:00:22 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.387 2002/12/12 15:49:36 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -5755,70 +5755,70 @@ a_expr:		c_expr									{ $$ = $1; }
 			| a_expr ISNULL
 				{
 					NullTest *n = makeNode(NullTest);
-					n->arg = $1;
+					n->arg = (Expr *) $1;
 					n->nulltesttype = IS_NULL;
 					$$ = (Node *)n;
 				}
 			| a_expr IS NULL_P
 				{
 					NullTest *n = makeNode(NullTest);
-					n->arg = $1;
+					n->arg = (Expr *) $1;
 					n->nulltesttype = IS_NULL;
 					$$ = (Node *)n;
 				}
 			| a_expr NOTNULL
 				{
 					NullTest *n = makeNode(NullTest);
-					n->arg = $1;
+					n->arg = (Expr *) $1;
 					n->nulltesttype = IS_NOT_NULL;
 					$$ = (Node *)n;
 				}
 			| a_expr IS NOT NULL_P
 				{
 					NullTest *n = makeNode(NullTest);
-					n->arg = $1;
+					n->arg = (Expr *) $1;
 					n->nulltesttype = IS_NOT_NULL;
 					$$ = (Node *)n;
 				}
 			| a_expr IS TRUE_P
 				{
 					BooleanTest *b = makeNode(BooleanTest);
-					b->arg = $1;
+					b->arg = (Expr *) $1;
 					b->booltesttype = IS_TRUE;
 					$$ = (Node *)b;
 				}
 			| a_expr IS NOT TRUE_P
 				{
 					BooleanTest *b = makeNode(BooleanTest);
-					b->arg = $1;
+					b->arg = (Expr *) $1;
 					b->booltesttype = IS_NOT_TRUE;
 					$$ = (Node *)b;
 				}
 			| a_expr IS FALSE_P
 				{
 					BooleanTest *b = makeNode(BooleanTest);
-					b->arg = $1;
+					b->arg = (Expr *) $1;
 					b->booltesttype = IS_FALSE;
 					$$ = (Node *)b;
 				}
 			| a_expr IS NOT FALSE_P
 				{
 					BooleanTest *b = makeNode(BooleanTest);
-					b->arg = $1;
+					b->arg = (Expr *) $1;
 					b->booltesttype = IS_NOT_FALSE;
 					$$ = (Node *)b;
 				}
 			| a_expr IS UNKNOWN
 				{
 					BooleanTest *b = makeNode(BooleanTest);
-					b->arg = $1;
+					b->arg = (Expr *) $1;
 					b->booltesttype = IS_UNKNOWN;
 					$$ = (Node *)b;
 				}
 			| a_expr IS NOT UNKNOWN
 				{
 					BooleanTest *b = makeNode(BooleanTest);
-					b->arg = $1;
+					b->arg = (Expr *) $1;
 					b->booltesttype = IS_NOT_UNKNOWN;
 					$$ = (Node *)b;
 				}
@@ -6640,9 +6640,9 @@ in_expr:	select_with_parens
 case_expr:	CASE case_arg when_clause_list case_default END_TRANS
 				{
 					CaseExpr *c = makeNode(CaseExpr);
-					c->arg = $2;
+					c->arg = (Expr *) $2;
 					c->args = $3;
-					c->defresult = $4;
+					c->defresult = (Expr *) $4;
 					$$ = (Node *)c;
 				}
 			| NULLIF '(' a_expr ',' a_expr ')'
@@ -6650,10 +6650,10 @@ case_expr:	CASE case_arg when_clause_list case_default END_TRANS
 					CaseExpr *c = makeNode(CaseExpr);
 					CaseWhen *w = makeNode(CaseWhen);
 
-					w->expr = (Node *) makeSimpleA_Expr(OP, "=", $3, $5);
+					w->expr = (Expr *) makeSimpleA_Expr(OP, "=", $3, $5);
 					/* w->result is left NULL */
 					c->args = makeList1(w);
-					c->defresult = $3;
+					c->defresult = (Expr *) $3;
 					$$ = (Node *)c;
 				}
 			| COALESCE '(' expr_list ')'
@@ -6666,7 +6666,7 @@ case_expr:	CASE case_arg when_clause_list case_default END_TRANS
 						NullTest *n = makeNode(NullTest);
 						n->arg = lfirst(l);
 						n->nulltesttype = IS_NOT_NULL;
-						w->expr = (Node *) n;
+						w->expr = (Expr *) n;
 						w->result = lfirst(l);
 						c->args = lappend(c->args, w);
 					}
@@ -6684,8 +6684,8 @@ when_clause:
 			WHEN a_expr THEN a_expr
 				{
 					CaseWhen *w = makeNode(CaseWhen);
-					w->expr = $2;
-					w->result = $4;
+					w->expr = (Expr *) $2;
+					w->result = (Expr *) $4;
 					$$ = (Node *)w;
 				}
 		;
@@ -7594,20 +7594,17 @@ static Node *
 makeRowNullTest(NullTestType test, List *args)
 {
 	Node *expr = NULL;
-	Node *arg;
 	NullTest *n;
 
 	if (lnext(args) != NIL)
 		expr = makeRowNullTest(test, lnext(args));
 
-	arg = lfirst(args);
-
 	n = makeNode(NullTest);
-	n->arg = arg;
+	n->arg = (Expr *) lfirst(args);
 	n->nulltesttype = test;
 
 	if (expr == NULL)
-		expr = (Node *)n;
+		expr = (Node *) n;
 	else if (test == IS_NOT_NULL)
 		expr = (Node *) makeA_Expr(OR, NIL, expr, (Node *)n);
 	else
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index ca398b4e3b31d4f50b4db0cd87e5ed409c7d19e0..6f05ee329cd1127ffd06f5760452ff92f291f358 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.100 2002/11/29 21:39:11 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.101 2002/12/12 15:49:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -502,17 +502,6 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
 			elog(ERROR, "cannot use aggregate function in FROM function expression");
 	}
 
-	/*
-	 * Insist we have a bare function call (explain.c is the only place
-	 * that depends on this, I think).	If this fails, it's probably
-	 * because transformExpr interpreted the function notation as a type
-	 * coercion.
-	 */
-	if (!funcexpr ||
-		!IsA(funcexpr, Expr) ||
-		((Expr *) funcexpr)->opType != FUNC_EXPR)
-		elog(ERROR, "Coercion function not allowed in FROM clause");
-
 	/*
 	 * OK, build an RTE for the function.
 	 */
@@ -876,7 +865,7 @@ buildMergedJoinVar(JoinType jointype, Var *l_colvar, Var *r_colvar)
 							 outcoltype,
 							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
 	else if (l_colvar->vartypmod != outcoltypmod)
-		l_node = (Node *) makeRelabelType((Node *) l_colvar,
+		l_node = (Node *) makeRelabelType((Expr *) l_colvar,
 										  outcoltype, outcoltypmod,
 										  COERCE_IMPLICIT_CAST);
 	else
@@ -887,7 +876,7 @@ buildMergedJoinVar(JoinType jointype, Var *l_colvar, Var *r_colvar)
 							 outcoltype,
 							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
 	else if (r_colvar->vartypmod != outcoltypmod)
-		r_node = (Node *) makeRelabelType((Node *) r_colvar,
+		r_node = (Node *) makeRelabelType((Expr *) r_colvar,
 										  outcoltype, outcoltypmod,
 										  COERCE_IMPLICIT_CAST);
 	else
@@ -928,13 +917,13 @@ buildMergedJoinVar(JoinType jointype, Var *l_colvar, Var *r_colvar)
 				CaseWhen   *w = makeNode(CaseWhen);
 				NullTest   *n = makeNode(NullTest);
 
-				n->arg = l_node;
+				n->arg = (Expr *) l_node;
 				n->nulltesttype = IS_NOT_NULL;
-				w->expr = (Node *) n;
-				w->result = l_node;
+				w->expr = (Expr *) n;
+				w->result = (Expr *) l_node;
 				c->casetype = outcoltype;
 				c->args = makeList1(w);
-				c->defresult = r_node;
+				c->defresult = (Expr *) r_node;
 				res_node = (Node *) c;
 				break;
 			}
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 6d3524c5d6c148406bdc8bef0cd573121b33c649..3856939d404a87d83ded1857a4c37120fec36587 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.89 2002/11/30 18:28:49 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.90 2002/12/12 15:49:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,7 +88,8 @@ coerce_to_target_type(Node *expr, Oid exprtype,
 							   ccontext, cformat);
 			/* Need a RelabelType if no typmod coercion is performed */
 			if (targettypmod < 0)
-				expr = (Node *) makeRelabelType(expr, targettype, -1,
+				expr = (Node *) makeRelabelType((Expr *) expr,
+												targettype, -1,
 												cformat);
 		}
 		else
@@ -190,7 +191,8 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
 											 cformat);
 			/* We might now need a RelabelType. */
 			if (exprType(result) != targetTypeId)
-				result = (Node *) makeRelabelType(result, targetTypeId, -1,
+				result = (Node *) makeRelabelType((Expr *) result,
+												  targetTypeId, -1,
 												  cformat);
 		}
 
@@ -227,7 +229,8 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
 			{
 				result = coerce_type_constraints(result, targetTypeId,
 												 cformat);
-				result = (Node *) makeRelabelType(result, targetTypeId, -1,
+				result = (Node *) makeRelabelType((Expr *) result,
+												  targetTypeId, -1,
 												  cformat);
 			}
 
@@ -266,7 +269,8 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
 			 * typmod, which is likely but not certain (wrong if target is
 			 * a domain, in any case).
 			 */
-			result = (Node *) makeRelabelType(result, targetTypeId, -1,
+			result = (Node *) makeRelabelType((Expr *) result,
+											  targetTypeId, -1,
 											  cformat);
 		}
 	}
@@ -277,7 +281,8 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
 		 * except relabel the type.  This is binary compatibility for
 		 * complex types.
 		 */
-		result = (Node *) makeRelabelType(node, targetTypeId, -1,
+		result = (Node *) makeRelabelType((Expr *) node,
+										  targetTypeId, -1,
 										  cformat);
 	}
 	else
@@ -449,7 +454,7 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
 				elog(ERROR, "coerce_type_constraints: domain %s constraint %s has NULL conbin",
 					 NameStr(typTup->typname), NameStr(c->conname));
 
-			r->arg = arg;
+			r->arg = (Expr *) arg;
 			r->testtype = CONSTR_TEST_CHECK;
 			r->name = NameStr(c->conname);
 			r->domname = NameStr(typTup->typname);
@@ -492,7 +497,7 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
 	{
 		ConstraintTest *r = makeNode(ConstraintTest);
 
-		r->arg = arg;
+		r->arg = (Expr *) arg;
 		r->testtype = CONSTR_TEST_NOTNULL;
 		r->name = "NOT NULL";
 		r->domname = notNull;
@@ -1140,21 +1145,14 @@ find_typmod_coercion_function(Oid typeId, int *nargs)
 static Node *
 build_func_call(Oid funcid, Oid rettype, List *args, CoercionForm fformat)
 {
-	Func	   *funcnode;
-	Expr	   *expr;
-
-	funcnode = makeNode(Func);
-	funcnode->funcid = funcid;
-	funcnode->funcresulttype = rettype;
-	funcnode->funcretset = false;		/* only possible case here */
-	funcnode->funcformat = fformat;
-	funcnode->func_fcache = NULL;
-
-	expr = makeNode(Expr);
-	expr->typeOid = rettype;
-	expr->opType = FUNC_EXPR;
-	expr->oper = (Node *) funcnode;
-	expr->args = args;
-
-	return (Node *) expr;
+	FuncExpr   *funcexpr;
+
+	funcexpr = makeNode(FuncExpr);
+	funcexpr->funcid = funcid;
+	funcexpr->funcresulttype = rettype;
+	funcexpr->funcretset = false;		/* only possible case here */
+	funcexpr->funcformat = fformat;
+	funcexpr->args = args;
+
+	return (Node *) funcexpr;
 }
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 41e669428597176b3052ab53ab79f1e2f7de372a..7dcbf59a4e397a77ee7773a61c71352476892208 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.135 2002/12/06 05:00:26 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.136 2002/12/12 15:49:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -199,9 +199,9 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 								n->nulltesttype = IS_NULL;
 
 								if (exprIsNullConstant(a->lexpr))
-									n->arg = a->rexpr;
+									n->arg = (Expr *) a->rexpr;
 								else
-									n->arg = a->lexpr;
+									n->arg = (Expr *) a->lexpr;
 
 								result = transformExpr(pstate,
 													   (Node *) n, domVal);
@@ -225,15 +225,13 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 															  a->lexpr, domVal);
 							Node	   *rexpr = transformExpr(pstate,
 															  a->rexpr, domVal);
-							Expr	   *expr = makeNode(Expr);
 
 							lexpr = coerce_to_boolean(lexpr, "AND");
 							rexpr = coerce_to_boolean(rexpr, "AND");
 
-							expr->typeOid = BOOLOID;
-							expr->opType = AND_EXPR;
-							expr->args = makeList2(lexpr, rexpr);
-							result = (Node *) expr;
+							result = (Node *) makeBoolExpr(AND_EXPR,
+														   makeList2(lexpr,
+																	 rexpr));
 						}
 						break;
 					case OR:
@@ -242,29 +240,24 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 															  a->lexpr, domVal);
 							Node	   *rexpr = transformExpr(pstate,
 															  a->rexpr, domVal);
-							Expr	   *expr = makeNode(Expr);
 
 							lexpr = coerce_to_boolean(lexpr, "OR");
 							rexpr = coerce_to_boolean(rexpr, "OR");
 
-							expr->typeOid = BOOLOID;
-							expr->opType = OR_EXPR;
-							expr->args = makeList2(lexpr, rexpr);
-							result = (Node *) expr;
+							result = (Node *) makeBoolExpr(OR_EXPR,
+														   makeList2(lexpr,
+																	 rexpr));
 						}
 						break;
 					case NOT:
 						{
 							Node	   *rexpr = transformExpr(pstate,
 															  a->rexpr, domVal);
-							Expr	   *expr = makeNode(Expr);
 
 							rexpr = coerce_to_boolean(rexpr, "NOT");
 
-							expr->typeOid = BOOLOID;
-							expr->opType = NOT_EXPR;
-							expr->args = makeList1(rexpr);
-							result = (Node *) expr;
+							result = (Node *) makeBoolExpr(NOT_EXPR,
+														   makeList1(rexpr));
 						}
 						break;
 					case DISTINCT:
@@ -277,9 +270,12 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 							result = (Node *) make_op(a->name,
 													  lexpr,
 													  rexpr);
-							if (((Expr *) result)->typeOid != BOOLOID)
+							if (((OpExpr *) result)->opresulttype != BOOLOID)
 								elog(ERROR, "IS DISTINCT FROM requires = operator to yield boolean");
-							((Expr *) result)->opType = DISTINCT_EXPR;
+							/*
+							 * We rely on DistinctExpr and OpExpr being same struct
+							 */
+							NodeSetTag(result, T_DistinctExpr);
 						}
 						break;
 					case OF:
@@ -433,7 +429,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 						Node	   *lexpr;
 						Operator	optup;
 						Form_pg_operator opform;
-						Oper	   *newop;
+						OpExpr	   *newop;
 
 						right_list = lnext(right_list);
 						if (tent->resdom->resjunk)
@@ -451,7 +447,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 						 */
 						optup = oper(op,
 									 exprType(lexpr),
-									 exprType(tent->expr),
+									 exprType((Node *) tent->expr),
 									 false);
 						opform = (Form_pg_operator) GETSTRUCT(optup);
 
@@ -466,11 +462,15 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 								 " to be used with quantified predicate subquery",
 								 opname);
 
-						newop = makeOper(oprid(optup),	/* opno */
-										 InvalidOid,	/* opid */
-										 opform->oprresult,
-										 false);
+						newop = makeNode(OpExpr);
+						newop->opno = oprid(optup);
+						newop->opfuncid = InvalidOid;
+						newop->opresulttype = opform->oprresult;
+						newop->opretset = false;
+						newop->args = NIL; /* for now */
+
 						sublink->oper = lappend(sublink->oper, newop);
+
 						ReleaseSysCache(optup);
 					}
 					if (left_list != NIL)
@@ -499,22 +499,24 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 
 					Assert(IsA(w, CaseWhen));
 
-					warg = w->expr;
+					warg = (Node *) w->expr;
 					if (c->arg != NULL)
 					{
 						/* shorthand form was specified, so expand... */
 						warg = (Node *) makeSimpleA_Expr(OP, "=",
-														 c->arg, warg);
+														 (Node *) c->arg,
+														 warg);
 					}
-					neww->expr = transformExpr(pstate, warg, domVal);
+					neww->expr = (Expr *) transformExpr(pstate, warg, domVal);
 
-					neww->expr = coerce_to_boolean(neww->expr, "CASE/WHEN");
+					neww->expr = (Expr *) coerce_to_boolean((Node *) neww->expr,
+															"CASE/WHEN");
 
 					/*
 					 * result is NULL for NULLIF() construct - thomas
 					 * 1998-11-11
 					 */
-					warg = w->result;
+					warg = (Node *) w->result;
 					if (warg == NULL)
 					{
 						A_Const    *n = makeNode(A_Const);
@@ -522,10 +524,10 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 						n->val.type = T_Null;
 						warg = (Node *) n;
 					}
-					neww->result = transformExpr(pstate, warg, domVal);
+					neww->result = (Expr *) transformExpr(pstate, warg, domVal);
 
 					newargs = lappend(newargs, neww);
-					typeids = lappendi(typeids, exprType(neww->result));
+					typeids = lappendi(typeids, exprType((Node *) neww->result));
 				}
 
 				newc->args = newargs;
@@ -538,7 +540,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 				newc->arg = NULL;
 
 				/* transform the default clause */
-				defresult = c->defresult;
+				defresult = (Node *) c->defresult;
 				if (defresult == NULL)
 				{
 					A_Const    *n = makeNode(A_Const);
@@ -546,7 +548,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 					n->val.type = T_Null;
 					defresult = (Node *) n;
 				}
-				newc->defresult = transformExpr(pstate, defresult, domVal);
+				newc->defresult = (Expr *) transformExpr(pstate, defresult, domVal);
 
 				/*
 				 * Note: default result is considered the most significant
@@ -554,24 +556,26 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 				 * code worked before, but it seems a little bogus to me
 				 * --- tgl
 				 */
-				typeids = lconsi(exprType(newc->defresult), typeids);
+				typeids = lconsi(exprType((Node *) newc->defresult), typeids);
 
 				ptype = select_common_type(typeids, "CASE");
 				newc->casetype = ptype;
 
 				/* Convert default result clause, if necessary */
-				newc->defresult = coerce_to_common_type(newc->defresult,
-														ptype,
-														"CASE/ELSE");
+				newc->defresult = (Expr *)
+					coerce_to_common_type((Node *) newc->defresult,
+										  ptype,
+										  "CASE/ELSE");
 
 				/* Convert when-clause results, if necessary */
 				foreach(args, newc->args)
 				{
 					CaseWhen   *w = (CaseWhen *) lfirst(args);
 
-					w->result = coerce_to_common_type(w->result,
-													  ptype,
-													  "CASE/WHEN");
+					w->result = (Expr *)
+						coerce_to_common_type((Node *) w->result,
+											  ptype,
+											  "CASE/WHEN");
 				}
 
 				result = (Node *) newc;
@@ -582,7 +586,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 			{
 				NullTest   *n = (NullTest *) expr;
 
-				n->arg = transformExpr(pstate, n->arg, domVal);
+				n->arg = (Expr *) transformExpr(pstate, (Node *) n->arg, domVal);
 				/* the argument can be any type, so don't coerce it */
 				result = expr;
 				break;
@@ -619,9 +623,9 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
 						clausename = NULL;		/* keep compiler quiet */
 				}
 
-				b->arg = transformExpr(pstate, b->arg, domVal);
+				b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg, domVal);
 
-				b->arg = coerce_to_boolean(b->arg, clausename);
+				b->arg = (Expr *) coerce_to_boolean((Node *) b->arg, clausename);
 
 				result = expr;
 				break;
@@ -885,36 +889,39 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
 Oid
 exprType(Node *expr)
 {
-	Oid			type = (Oid) InvalidOid;
+	Oid			type;
 
 	if (!expr)
-		return type;
+		return InvalidOid;
 
 	switch (nodeTag(expr))
 	{
 		case T_Var:
 			type = ((Var *) expr)->vartype;
 			break;
-		case T_Expr:
-			type = ((Expr *) expr)->typeOid;
-			break;
 		case T_Const:
 			type = ((Const *) expr)->consttype;
 			break;
-		case T_ArrayRef:
-			type = ((ArrayRef *) expr)->refrestype;
+		case T_Param:
+			type = ((Param *) expr)->paramtype;
 			break;
 		case T_Aggref:
 			type = ((Aggref *) expr)->aggtype;
 			break;
-		case T_Param:
-			type = ((Param *) expr)->paramtype;
+		case T_ArrayRef:
+			type = ((ArrayRef *) expr)->refrestype;
 			break;
-		case T_FieldSelect:
-			type = ((FieldSelect *) expr)->resulttype;
+		case T_FuncExpr:
+			type = ((FuncExpr *) expr)->funcresulttype;
 			break;
-		case T_RelabelType:
-			type = ((RelabelType *) expr)->resulttype;
+		case T_OpExpr:
+			type = ((OpExpr *) expr)->opresulttype;
+			break;
+		case T_DistinctExpr:
+			type = ((DistinctExpr *) expr)->opresulttype;
+			break;
+		case T_BoolExpr:
+			type = BOOLOID;
 			break;
 		case T_SubLink:
 			{
@@ -938,11 +945,17 @@ exprType(Node *expr)
 				}
 			}
 			break;
+		case T_FieldSelect:
+			type = ((FieldSelect *) expr)->resulttype;
+			break;
+		case T_RelabelType:
+			type = ((RelabelType *) expr)->resulttype;
+			break;
 		case T_CaseExpr:
 			type = ((CaseExpr *) expr)->casetype;
 			break;
 		case T_CaseWhen:
-			type = exprType(((CaseWhen *) expr)->result);
+			type = exprType((Node *) ((CaseWhen *) expr)->result);
 			break;
 		case T_NullTest:
 			type = BOOLOID;
@@ -951,7 +964,7 @@ exprType(Node *expr)
 			type = BOOLOID;
 			break;
 		case T_ConstraintTest:
-			type = exprType(((ConstraintTest *) expr)->arg);
+			type = exprType((Node *) ((ConstraintTest *) expr)->arg);
 			break;
 		case T_ConstraintTestValue:
 			type = ((ConstraintTestValue *) expr)->typeId;
@@ -959,6 +972,7 @@ exprType(Node *expr)
 		default:
 			elog(ERROR, "exprType: Do not know how to get type for %d node",
 				 nodeTag(expr));
+			type = InvalidOid;	/* keep compiler quiet */
 			break;
 	}
 	return type;
@@ -995,7 +1009,7 @@ exprTypmod(Node *expr)
 				}
 			}
 			break;
-		case T_Expr:
+		case T_FuncExpr:
 			{
 				int32		coercedTypmod;
 
@@ -1021,9 +1035,9 @@ exprTypmod(Node *expr)
 
 				if (!cexpr->defresult)
 					return -1;
-				if (exprType(cexpr->defresult) != casetype)
+				if (exprType((Node *) cexpr->defresult) != casetype)
 					return -1;
-				typmod = exprTypmod(cexpr->defresult);
+				typmod = exprTypmod((Node *) cexpr->defresult);
 				if (typmod < 0)
 					return -1;	/* no point in trying harder */
 				foreach(arg, cexpr->args)
@@ -1031,16 +1045,16 @@ exprTypmod(Node *expr)
 					CaseWhen   *w = (CaseWhen *) lfirst(arg);
 
 					Assert(IsA(w, CaseWhen));
-					if (exprType(w->result) != casetype)
+					if (exprType((Node *) w->result) != casetype)
 						return -1;
-					if (exprTypmod(w->result) != typmod)
+					if (exprTypmod((Node *) w->result) != typmod)
 						return -1;
 				}
 				return typmod;
 			}
 			break;
 		case T_ConstraintTest:
-			return exprTypmod(((ConstraintTest *) expr)->arg);
+			return exprTypmod((Node *) ((ConstraintTest *) expr)->arg);
 
 		default:
 			break;
@@ -1059,7 +1073,7 @@ exprTypmod(Node *expr)
 bool
 exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
 {
-	Func	   *func;
+	FuncExpr   *func;
 	int			nargs;
 	Const	   *second_arg;
 
@@ -1067,12 +1081,9 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
 		*coercedTypmod = -1;	/* default result on failure */
 
 	/* Is it a function-call at all? */
-	if (expr == NULL ||
-		!IsA(expr, Expr) ||
-		((Expr *) expr)->opType != FUNC_EXPR)
+	if (expr == NULL || !IsA(expr, FuncExpr))
 		return false;
-	func = (Func *) (((Expr *) expr)->oper);
-	Assert(IsA(func, Func));
+	func = (FuncExpr *) expr;
 
 	/*
 	 * If it didn't come from a coercion context, reject.
@@ -1086,11 +1097,11 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
 	 * argument being an int4 constant, it can't have been created from a
 	 * length coercion (it must be a type coercion, instead).
 	 */
-	nargs = length(((Expr *) expr)->args);
+	nargs = length(func->args);
 	if (nargs < 2 || nargs > 3)
 		return false;
 
-	second_arg = (Const *) lsecond(((Expr *) expr)->args);
+	second_arg = (Const *) lsecond(func->args);
 	if (!IsA(second_arg, Const) ||
 		second_arg->consttype != INT4OID ||
 		second_arg->constisnull)
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 46d1bb0755c1e934e1a743cc6810ab28b8c5a682..4a2eb27d7ccc9dac1cc7c7d6957edf56f86cd4a7 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.142 2002/11/13 00:39:47 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.143 2002/12/12 15:49:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -315,21 +315,15 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 	/* build the appropriate output structure */
 	if (fdresult == FUNCDETAIL_NORMAL)
 	{
-		Expr	   *expr = makeNode(Expr);
-		Func	   *funcnode = makeNode(Func);
+		FuncExpr   *funcexpr = makeNode(FuncExpr);
 
-		funcnode->funcid = funcid;
-		funcnode->funcresulttype = rettype;
-		funcnode->funcretset = retset;
-		funcnode->funcformat = COERCE_EXPLICIT_CALL;
-		funcnode->func_fcache = NULL;
+		funcexpr->funcid = funcid;
+		funcexpr->funcresulttype = rettype;
+		funcexpr->funcretset = retset;
+		funcexpr->funcformat = COERCE_EXPLICIT_CALL;
+		funcexpr->args = fargs;
 
-		expr->typeOid = rettype;
-		expr->opType = FUNC_EXPR;
-		expr->oper = (Node *) funcnode;
-		expr->args = fargs;
-
-		retval = (Node *) expr;
+		retval = (Node *) funcexpr;
 	}
 	else
 	{
@@ -1182,7 +1176,7 @@ setup_field_select(Node *input, char *attname, Oid relid)
 		elog(ERROR, "Relation \"%s\" has no column \"%s\"",
 			 get_rel_name(relid), attname);
 
-	fselect->arg = input;
+	fselect->arg = (Expr *) input;
 	fselect->fieldnum = attno;
 	fselect->resulttype = get_atttype(relid, attno);
 	fselect->resulttypmod = get_atttypmod(relid, attno);
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 088aaafb0b32c8cee87716977ec3ecab76d979eb..a246344c7bd6a6c2a15efe956f7f139f89f07884 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.74 2002/11/25 21:29:41 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.75 2002/12/12 15:49:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -89,10 +89,9 @@ make_op(List *opname, Node *ltree, Node *rtree)
 				rtypeId;
 	Operator	tup;
 	Form_pg_operator opform;
-	Oper	   *newop;
 	Node	   *left,
 			   *right;
-	Expr	   *result;
+	OpExpr	   *result;
 
 	ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree);
 	rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree);
@@ -124,15 +123,11 @@ make_op(List *opname, Node *ltree, Node *rtree)
 		right = make_operand(rtree, rtypeId, opform->oprright);
 	}
 
-	newop = makeOper(oprid(tup),	/* opno */
-					 InvalidOid,	/* opid */
-					 opform->oprresult, /* opresulttype */
-					 get_func_retset(opform->oprcode)); /* opretset */
-
-	result = makeNode(Expr);
-	result->typeOid = opform->oprresult;
-	result->opType = OP_EXPR;
-	result->oper = (Node *) newop;
+	result = makeNode(OpExpr);
+	result->opno = oprid(tup);
+	result->opfuncid = InvalidOid;
+	result->opresulttype = opform->oprresult;
+	result->opretset = get_func_retset(opform->oprcode);
 
 	if (!left)
 		result->args = makeList1(right);
@@ -143,7 +138,7 @@ make_op(List *opname, Node *ltree, Node *rtree)
 
 	ReleaseSysCache(tup);
 
-	return result;
+	return (Expr *) result;
 }	/* make_op() */
 
 
@@ -343,8 +338,8 @@ transformArraySubscripts(ParseState *pstate,
 	aref->refelemalign = type_struct_element->typalign;
 	aref->refupperindexpr = upperIndexpr;
 	aref->reflowerindexpr = lowerIndexpr;
-	aref->refexpr = arrayBase;
-	aref->refassgnexpr = assignFrom;
+	aref->refexpr = (Expr *) arrayBase;
+	aref->refassgnexpr = (Expr *) assignFrom;
 
 	ReleaseSysCache(type_tuple_array);
 	ReleaseSysCache(type_tuple_element);
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 65c386a937c9c19f4309f289cafbdfb97b2232a4..4ae3bf23153229616db8ae6e7debafe33508ae32 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.79 2002/09/04 20:31:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.80 2002/12/12 15:49:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1452,7 +1452,7 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte)
 								exprTypmod(varnode),
 								label,
 								false);
-		te->expr = varnode;
+		te->expr = (Expr *) varnode;
 		te_list = lappend(te_list, te);
 
 		names = lnext(names);
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 1a2da6da1eb354fe1723a90e20951056314b4961..5e4e23db920686f1106eecf0229aa6034c134198 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.92 2002/11/15 02:50:09 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.93 2002/12/12 15:49:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -79,7 +79,7 @@ transformTargetEntry(ParseState *pstate,
 						 colname,
 						 resjunk);
 
-	return makeTargetEntry(resnode, expr);
+	return makeTargetEntry(resnode, (Expr *) expr);
 }
 
 
@@ -225,7 +225,7 @@ updateTargetListEntry(ParseState *pstate,
 					  int attrno,
 					  List *indirection)
 {
-	Oid			type_id = exprType(tle->expr);	/* type of value provided */
+	Oid			type_id = exprType((Node *) tle->expr);	/* type of value provided */
 	Oid			attrtype;		/* type of target column */
 	int32		attrtypmod;
 	Resdom	   *resnode = tle->resdom;
@@ -277,8 +277,8 @@ updateTargetListEntry(ParseState *pstate,
 										attrtypmod,
 										indirection,
 										pstate->p_is_insert,
-										tle->expr);
-		tle->expr = (Node *) aref;
+										(Node *) tle->expr);
+		tle->expr = (Expr *) aref;
 	}
 	else
 	{
@@ -289,10 +289,11 @@ updateTargetListEntry(ParseState *pstate,
 		 */
 		if (type_id != InvalidOid)
 		{
-			tle->expr = coerce_to_target_type(tle->expr, type_id,
-											  attrtype, attrtypmod,
-											  COERCION_ASSIGNMENT,
-											  COERCE_IMPLICIT_CAST);
+			tle->expr = (Expr *)
+				coerce_to_target_type((Node *) tle->expr, type_id,
+									  attrtype, attrtypmod,
+									  COERCION_ASSIGNMENT,
+									  COERCE_IMPLICIT_CAST);
 			if (tle->expr == NULL)
 				elog(ERROR, "column \"%s\" is of type %s"
 					 " but expression is of type %s"
@@ -501,7 +502,7 @@ FigureColnameInternal(Node *node, char **name)
 			}
 			break;
 		case T_CaseExpr:
-			strength = FigureColnameInternal(((CaseExpr *) node)->defresult,
+			strength = FigureColnameInternal((Node *) ((CaseExpr *) node)->defresult,
 											 name);
 			if (strength <= 1)
 			{
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index bb58db8e8a5584deaf07dc47a51105e8ad0cbb63..d0badcc154f960f75c15db6cae898fc7d776a7be 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.113 2002/10/20 00:58:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.114 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -304,7 +304,7 @@ rewriteTargetList(Query *parsetree, Relation target_relation)
 													 att_tup->atttypmod,
 									  pstrdup(NameStr(att_tup->attname)),
 													 false),
-										  new_expr);
+										  (Expr *) new_expr);
 		}
 
 		if (new_tle)
@@ -389,10 +389,10 @@ process_matched_tle(TargetEntry *src_tle,
 	 * Prior TLE could be a nest of ArrayRefs if we do this more than
 	 * once.
 	 */
-	priorbottom = ((ArrayRef *) prior_tle->expr)->refexpr;
+	priorbottom = (Node *) ((ArrayRef *) prior_tle->expr)->refexpr;
 	while (priorbottom != NULL && IsA(priorbottom, ArrayRef) &&
 		   ((ArrayRef *) priorbottom)->refassgnexpr != NULL)
-		priorbottom = ((ArrayRef *) priorbottom)->refexpr;
+		priorbottom = (Node *) ((ArrayRef *) priorbottom)->refexpr;
 	if (!equal(priorbottom, ((ArrayRef *) src_tle->expr)->refexpr))
 		elog(ERROR, "Multiple assignments to same attribute \"%s\"",
 			 resdom->resname);
@@ -404,7 +404,7 @@ process_matched_tle(TargetEntry *src_tle,
 	memcpy(newexpr, src_tle->expr, sizeof(ArrayRef));
 	newexpr->refexpr = prior_tle->expr;
 
-	return makeTargetEntry(resdom, (Node *) newexpr);
+	return makeTargetEntry(resdom, (Expr *) newexpr);
 }
 
 
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index 94a940648c002bae6b628f03664b767652f506b0..22e7eee306c50f395602c6fb4de187345307596b 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.67 2002/10/20 00:58:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.68 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -706,7 +706,7 @@ AddInvertedQual(Query *parsetree, Node *qual)
 
 	/* Need not copy input qual, because AddQual will... */
 	invqual = makeNode(BooleanTest);
-	invqual->arg = qual;
+	invqual->arg = (Expr *) qual;
 	invqual->booltesttype = IS_NOT_TRUE;
 
 	AddQual(parsetree, (Node *) invqual);
@@ -724,7 +724,7 @@ FindMatchingNew(List *tlist, int attno)
 		TargetEntry *tle = lfirst(i);
 
 		if (tle->resdom->resno == attno)
-			return tle->expr;
+			return (Node *) tle->expr;
 	}
 	return NULL;
 }
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index b8189e8cc11018a0d0872a60fc19cd16af07c5aa..104f93a355c216e4daea2f6bf629fb5880c41027 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -17,7 +17,7 @@
  *
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.45 2002/12/05 04:04:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.46 2002/12/12 15:49:40 tgl Exp $
  *
  * ----------
  */
@@ -35,6 +35,7 @@
 #include "catalog/pg_operator.h"
 #include "commands/trigger.h"
 #include "executor/spi_priv.h"
+#include "optimizer/planmain.h"
 #include "parser/parse_oper.h"
 #include "utils/lsyscache.h"
 #include "miscadmin.h"
@@ -2747,6 +2748,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
 								nth(defval[j].adnum - 1,
 									spi_plan->targetlist);
 							spi_qptle->expr = stringToNode(defval[j].adbin);
+							fix_opfuncids((Node *) spi_qptle->expr);
 
 							break;
 						}
@@ -3037,6 +3039,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
 									nth(defval[j].adnum - 1,
 										spi_plan->targetlist);
 								spi_qptle->expr = stringToNode(defval[j].adbin);
+								fix_opfuncids((Node *) spi_qptle->expr);
 
 								break;
 							}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index c5a0f0d75d853fa8d70399c8c317acfc090e4535..92f69a32a829ecd6bde51148ab6dff96846de3ea 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.127 2002/11/26 03:01:58 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.128 2002/12/12 15:49:40 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -149,13 +149,13 @@ static RangeTblEntry *find_rte_by_refname(const char *refname,
 					deparse_context *context);
 static void get_rule_expr(Node *node, deparse_context *context,
 						  bool showimplicit);
-static void get_oper_expr(Expr *expr, deparse_context *context);
-static void get_func_expr(Expr *expr, deparse_context *context,
+static void get_oper_expr(OpExpr *expr, deparse_context *context);
+static void get_func_expr(FuncExpr *expr, deparse_context *context,
 						  bool showimplicit);
 static void get_agg_expr(Aggref *aggref, deparse_context *context);
 static Node *strip_type_coercion(Node *expr, Oid resultType);
 static void get_const_expr(Const *constval, deparse_context *context);
-static void get_sublink_expr(Node *node, deparse_context *context);
+static void get_sublink_expr(SubLink *sublink, deparse_context *context);
 static void get_from_clause(Query *query, deparse_context *context);
 static void get_from_clause_item(Node *jtnode, Query *query,
 					 deparse_context *context);
@@ -1434,7 +1434,7 @@ get_basic_select_query(Query *query, deparse_context *context,
 		sep = ", ";
 		colno++;
 
-		get_rule_expr(tle->expr, context, true);
+		get_rule_expr((Node *) tle->expr, context, true);
 
 		/*
 		 * Figure out what the result column should be called.	In the
@@ -1565,7 +1565,7 @@ get_rule_sortgroupclause(SortClause *srt, List *tlist, bool force_colno,
 	Node	   *expr;
 
 	tle = get_sortgroupclause_tle(srt, tlist);
-	expr = tle->expr;
+	expr = (Node *) tle->expr;
 
 	/*
 	 * Use column-number form if requested by caller or if expression is a
@@ -1647,7 +1647,7 @@ get_insert_query_def(Query *query, deparse_context *context)
 
 			appendStringInfo(buf, sep);
 			sep = ", ";
-			get_rule_expr(tle->expr, context, false);
+			get_rule_expr((Node *) tle->expr, context, false);
 		}
 		appendStringInfoChar(buf, ')');
 	}
@@ -1697,7 +1697,7 @@ get_update_query_def(Query *query, deparse_context *context)
 		if (!tleIsArrayAssign(tle))
 			appendStringInfo(buf, "%s = ",
 							 quote_identifier(tle->resdom->resname));
-		get_rule_expr(tle->expr, context, false);
+		get_rule_expr((Node *) tle->expr, context, false);
 	}
 
 	/* Add the FROM clause if needed */
@@ -1924,10 +1924,6 @@ get_rule_expr(Node *node, deparse_context *context,
 	 */
 	switch (nodeTag(node))
 	{
-		case T_Const:
-			get_const_expr((Const *) node, context);
-			break;
-
 		case T_Var:
 			{
 				Var		   *var = (Var *) node;
@@ -1958,82 +1954,26 @@ get_rule_expr(Node *node, deparse_context *context,
 			}
 			break;
 
-		case T_Expr:
+		case T_Const:
+			get_const_expr((Const *) node, context);
+			break;
+
+		case T_Param:
 			{
-				Expr	   *expr = (Expr *) node;
-				List	   *args = expr->args;
+				Param	   *param = (Param *) node;
 
-				/*
-				 * Expr nodes have to be handled a bit detailed
-				 */
-				switch (expr->opType)
+				switch (param->paramkind)
 				{
-					case OP_EXPR:
-						get_oper_expr(expr, context);
-						break;
-
-					case DISTINCT_EXPR:
-						appendStringInfoChar(buf, '(');
-						Assert(length(args) == 2);
-						{
-							/* binary operator */
-							Node	   *arg1 = (Node *) lfirst(args);
-							Node	   *arg2 = (Node *) lsecond(args);
-
-							get_rule_expr(arg1, context, true);
-							appendStringInfo(buf, " IS DISTINCT FROM ");
-							get_rule_expr(arg2, context, true);
-						}
-						appendStringInfoChar(buf, ')');
-						break;
-
-					case FUNC_EXPR:
-						get_func_expr(expr, context, showimplicit);
-						break;
-
-					case OR_EXPR:
-						appendStringInfoChar(buf, '(');
-						get_rule_expr((Node *) lfirst(args), context, false);
-						while ((args = lnext(args)) != NIL)
-						{
-							appendStringInfo(buf, " OR ");
-							get_rule_expr((Node *) lfirst(args), context,
-										  false);
-						}
-						appendStringInfoChar(buf, ')');
-						break;
-
-					case AND_EXPR:
-						appendStringInfoChar(buf, '(');
-						get_rule_expr((Node *) lfirst(args), context, false);
-						while ((args = lnext(args)) != NIL)
-						{
-							appendStringInfo(buf, " AND ");
-							get_rule_expr((Node *) lfirst(args), context,
-										  false);
-						}
-						appendStringInfoChar(buf, ')');
-						break;
-
-					case NOT_EXPR:
-						appendStringInfo(buf, "(NOT ");
-						get_rule_expr((Node *) lfirst(args), context, false);
-						appendStringInfoChar(buf, ')');
+					case PARAM_NAMED:
+						appendStringInfo(buf, "$%s", param->paramname);
 						break;
-
-					case SUBPLAN_EXPR:
-
-						/*
-						 * We cannot see an already-planned subplan in
-						 * rule deparsing, only while EXPLAINing a query
-						 * plan. For now, just punt.
-						 */
-						appendStringInfo(buf, "(subplan)");
+					case PARAM_NUM:
+					case PARAM_EXEC:
+						appendStringInfo(buf, "$%d", param->paramid);
 						break;
-
 					default:
-						elog(ERROR, "get_rule_expr: expr opType %d not supported",
-							 expr->opType);
+						appendStringInfo(buf, "(param)");
+						break;
 				}
 			}
 			break;
@@ -2058,7 +1998,7 @@ get_rule_expr(Node *node, deparse_context *context,
 				 */
 				if (aref->refassgnexpr)
 					context->varprefix = false;
-				get_rule_expr(aref->refexpr, context, showimplicit);
+				get_rule_expr((Node *) aref->refexpr, context, showimplicit);
 				context->varprefix = savevarprefix;
 				lowlist = aref->reflowerindexpr;
 				foreach(uplist, aref->refupperindexpr)
@@ -2077,15 +2017,103 @@ get_rule_expr(Node *node, deparse_context *context,
 				if (aref->refassgnexpr)
 				{
 					appendStringInfo(buf, " = ");
-					get_rule_expr(aref->refassgnexpr, context, showimplicit);
+					get_rule_expr((Node *) aref->refassgnexpr, context,
+								  showimplicit);
+				}
+			}
+			break;
+
+		case T_FuncExpr:
+			get_func_expr((FuncExpr *) node, context, showimplicit);
+			break;
+
+		case T_OpExpr:
+			get_oper_expr((OpExpr *) node, context);
+			break;
+
+		case T_DistinctExpr:
+			{
+				DistinctExpr *expr = (DistinctExpr *) node;
+				List	   *args = expr->args;
+
+				Assert(length(args) == 2);
+				{
+					/* binary operator */
+					Node	   *arg1 = (Node *) lfirst(args);
+					Node	   *arg2 = (Node *) lsecond(args);
+
+					appendStringInfoChar(buf, '(');
+					get_rule_expr(arg1, context, true);
+					appendStringInfo(buf, " IS DISTINCT FROM ");
+					get_rule_expr(arg2, context, true);
+					appendStringInfoChar(buf, ')');
 				}
 			}
 			break;
 
+		case T_BoolExpr:
+			{
+				BoolExpr   *expr = (BoolExpr *) node;
+				List	   *args = expr->args;
+
+				switch (expr->boolop)
+				{
+					case AND_EXPR:
+						appendStringInfoChar(buf, '(');
+						get_rule_expr((Node *) lfirst(args), context, false);
+						while ((args = lnext(args)) != NIL)
+						{
+							appendStringInfo(buf, " AND ");
+							get_rule_expr((Node *) lfirst(args), context,
+										  false);
+						}
+						appendStringInfoChar(buf, ')');
+						break;
+
+					case OR_EXPR:
+						appendStringInfoChar(buf, '(');
+						get_rule_expr((Node *) lfirst(args), context, false);
+						while ((args = lnext(args)) != NIL)
+						{
+							appendStringInfo(buf, " OR ");
+							get_rule_expr((Node *) lfirst(args), context,
+										  false);
+						}
+						appendStringInfoChar(buf, ')');
+						break;
+
+					case NOT_EXPR:
+						appendStringInfo(buf, "(NOT ");
+						get_rule_expr((Node *) lfirst(args), context, false);
+						appendStringInfoChar(buf, ')');
+						break;
+
+					default:
+						elog(ERROR, "get_rule_expr: unknown boolop %d",
+							 (int) expr->boolop);
+				}
+			}
+			break;
+
+		case T_SubLink:
+			get_sublink_expr((SubLink *) node, context);
+			break;
+
+		case T_SubPlanExpr:
+			{
+				/*
+				 * We cannot see an already-planned subplan in
+				 * rule deparsing, only while EXPLAINing a query
+				 * plan. For now, just punt.
+				 */
+				appendStringInfo(buf, "(subplan)");
+			}
+			break;
+
 		case T_FieldSelect:
 			{
 				FieldSelect *fselect = (FieldSelect *) node;
-				Oid			argType = exprType(fselect->arg);
+				Oid			argType = exprType((Node *) fselect->arg);
 				Oid			typrelid;
 				char	   *fieldname;
 
@@ -2103,7 +2131,7 @@ get_rule_expr(Node *node, deparse_context *context,
 				 * are *not* simple.  So, always use parenthesized syntax.
 				 */
 				appendStringInfoChar(buf, '(');
-				get_rule_expr(fselect->arg, context, true);
+				get_rule_expr((Node *) fselect->arg, context, true);
 				appendStringInfo(buf, ").%s", quote_identifier(fieldname));
 			}
 			break;
@@ -2111,7 +2139,7 @@ get_rule_expr(Node *node, deparse_context *context,
 		case T_RelabelType:
 			{
 				RelabelType *relabel = (RelabelType *) node;
-				Node   *arg = relabel->arg;
+				Node   *arg = (Node *) relabel->arg;
 
 				if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
 					!showimplicit)
@@ -2149,12 +2177,12 @@ get_rule_expr(Node *node, deparse_context *context,
 					CaseWhen   *when = (CaseWhen *) lfirst(temp);
 
 					appendStringInfo(buf, " WHEN ");
-					get_rule_expr(when->expr, context, false);
+					get_rule_expr((Node *) when->expr, context, false);
 					appendStringInfo(buf, " THEN ");
-					get_rule_expr(when->result, context, true);
+					get_rule_expr((Node *) when->result, context, true);
 				}
 				appendStringInfo(buf, " ELSE ");
-				get_rule_expr(caseexpr->defresult, context, true);
+				get_rule_expr((Node *) caseexpr->defresult, context, true);
 				appendStringInfo(buf, " END");
 			}
 			break;
@@ -2164,7 +2192,7 @@ get_rule_expr(Node *node, deparse_context *context,
 				NullTest   *ntest = (NullTest *) node;
 
 				appendStringInfo(buf, "(");
-				get_rule_expr(ntest->arg, context, true);
+				get_rule_expr((Node *) ntest->arg, context, true);
 				switch (ntest->nulltesttype)
 				{
 					case IS_NULL:
@@ -2185,7 +2213,7 @@ get_rule_expr(Node *node, deparse_context *context,
 				BooleanTest *btest = (BooleanTest *) node;
 
 				appendStringInfo(buf, "(");
-				get_rule_expr(btest->arg, context, false);
+				get_rule_expr((Node *) btest->arg, context, false);
 				switch (btest->booltesttype)
 				{
 					case IS_TRUE:
@@ -2221,38 +2249,12 @@ get_rule_expr(Node *node, deparse_context *context,
 				 * We assume that the operations of the constraint node
 				 * need not be explicitly represented in the output.
 				 */
-				get_rule_expr(ctest->arg, context, showimplicit);
+				get_rule_expr((Node *) ctest->arg, context, showimplicit);
 			}
 			break;
 
 		case T_ConstraintTestValue:
-			{
-				appendStringInfo(buf, "VALUE");
-			}
-			break;
-
-		case T_SubLink:
-			get_sublink_expr(node, context);
-			break;
-
-		case T_Param:
-			{
-				Param	   *param = (Param *) node;
-
-				switch (param->paramkind)
-				{
-					case PARAM_NAMED:
-						appendStringInfo(buf, "$%s", param->paramname);
-						break;
-					case PARAM_NUM:
-					case PARAM_EXEC:
-						appendStringInfo(buf, "$%d", param->paramid);
-						break;
-					default:
-						appendStringInfo(buf, "(param)");
-						break;
-				}
-			}
+			appendStringInfo(buf, "VALUE");
 			break;
 
 		default:
@@ -2263,13 +2265,13 @@ get_rule_expr(Node *node, deparse_context *context,
 
 
 /*
- * get_oper_expr			- Parse back an Oper node
+ * get_oper_expr			- Parse back an OpExpr node
  */
 static void
-get_oper_expr(Expr *expr, deparse_context *context)
+get_oper_expr(OpExpr *expr, deparse_context *context)
 {
 	StringInfo	buf = context->buf;
-	Oid			opno = ((Oper *) expr->oper)->opno;
+	Oid			opno = expr->opno;
 	List	   *args = expr->args;
 
 	appendStringInfoChar(buf, '(');
@@ -2324,15 +2326,14 @@ get_oper_expr(Expr *expr, deparse_context *context)
 }
 
 /*
- * get_func_expr			- Parse back a Func node
+ * get_func_expr			- Parse back a FuncExpr node
  */
 static void
-get_func_expr(Expr *expr, deparse_context *context,
+get_func_expr(FuncExpr *expr, deparse_context *context,
 			  bool showimplicit)
 {
 	StringInfo	buf = context->buf;
-	Func	   *func = (Func *) (expr->oper);
-	Oid			funcoid = func->funcid;
+	Oid			funcoid = expr->funcid;
 	Oid			argtypes[FUNC_MAX_ARGS];
 	int			nargs;
 	List	   *l;
@@ -2342,7 +2343,7 @@ get_func_expr(Expr *expr, deparse_context *context,
 	 * If the function call came from an implicit coercion, then just show
 	 * the first argument --- unless caller wants to see implicit coercions.
 	 */
-	if (func->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
+	if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
 	{
 		get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
 		return;
@@ -2352,11 +2353,11 @@ get_func_expr(Expr *expr, deparse_context *context,
 	 * If the function call came from a cast, then show
 	 * the first argument plus an explicit cast operation.
 	 */
-	if (func->funcformat == COERCE_EXPLICIT_CAST ||
-		func->funcformat == COERCE_IMPLICIT_CAST)
+	if (expr->funcformat == COERCE_EXPLICIT_CAST ||
+		expr->funcformat == COERCE_IMPLICIT_CAST)
 	{
 		Node	   *arg = lfirst(expr->args);
-		Oid			rettype = expr->typeOid;
+		Oid			rettype = expr->funcresulttype;
 		int32		coercedTypmod;
 
 		/* Get the typmod if this is a length-coercion function */
@@ -2410,7 +2411,7 @@ static void
 get_agg_expr(Aggref *aggref, deparse_context *context)
 {
 	StringInfo	buf = context->buf;
-	Oid			argtype = exprType(aggref->target);
+	Oid			argtype = exprType((Node *) aggref->target);
 
 	appendStringInfo(buf, "%s(%s",
 				   generate_function_name(aggref->aggfnoid, 1, &argtype),
@@ -2418,7 +2419,7 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
 	if (aggref->aggstar)
 		appendStringInfo(buf, "*");
 	else
-		get_rule_expr(aggref->target, context, true);
+		get_rule_expr((Node *) aggref->target, context, true);
 	appendStringInfoChar(buf, ')');
 }
 
@@ -2442,14 +2443,12 @@ strip_type_coercion(Node *expr, Oid resultType)
 
 	if (IsA(expr, RelabelType) &&
 		((RelabelType *) expr)->resulttypmod == -1)
-		return ((RelabelType *) expr)->arg;
+		return (Node *) ((RelabelType *) expr)->arg;
 
-	if (IsA(expr, Expr) &&
-		((Expr *) expr)->opType == FUNC_EXPR)
+	if (IsA(expr, FuncExpr))
 	{
-		Func	   *func = (Func *) (((Expr *) expr)->oper);
+		FuncExpr   *func = (FuncExpr *) expr;
 
-		Assert(IsA(func, Func));
 		if (func->funcformat != COERCE_EXPLICIT_CAST &&
 			func->funcformat != COERCE_IMPLICIT_CAST)
 			return expr;		/* don't absorb into upper coercion */
@@ -2457,7 +2456,7 @@ strip_type_coercion(Node *expr, Oid resultType)
 		if (exprIsLengthCoercion(expr, NULL))
 			return expr;
 
-		return (Node *) lfirst(((Expr *) expr)->args);
+		return (Node *) lfirst(func->args);
 	}
 
 	return expr;
@@ -2609,14 +2608,13 @@ get_const_expr(Const *constval, deparse_context *context)
  * ----------
  */
 static void
-get_sublink_expr(Node *node, deparse_context *context)
+get_sublink_expr(SubLink *sublink, deparse_context *context)
 {
 	StringInfo	buf = context->buf;
-	SubLink    *sublink = (SubLink *) node;
 	Query	   *query = (Query *) (sublink->subselect);
 	List	   *l;
 	char	   *sep;
-	Oper	   *oper;
+	OpExpr	   *oper;
 	bool		need_paren;
 
 	appendStringInfoChar(buf, '(');
@@ -2657,17 +2655,17 @@ get_sublink_expr(Node *node, deparse_context *context)
 			break;
 
 		case ANY_SUBLINK:
-			oper = (Oper *) lfirst(sublink->oper);
+			oper = (OpExpr *) lfirst(sublink->oper);
 			appendStringInfo(buf, "%s ANY ", get_opname(oper->opno));
 			break;
 
 		case ALL_SUBLINK:
-			oper = (Oper *) lfirst(sublink->oper);
+			oper = (OpExpr *) lfirst(sublink->oper);
 			appendStringInfo(buf, "%s ALL ", get_opname(oper->opno));
 			break;
 
 		case MULTIEXPR_SUBLINK:
-			oper = (Oper *) lfirst(sublink->oper);
+			oper = (OpExpr *) lfirst(sublink->oper);
 			appendStringInfo(buf, "%s ", get_opname(oper->opno));
 			break;
 
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 827b000d229bf92097af0a2ff97793264bc20005..c378f8b50e38461247e782edb9b859408c915cdd 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.122 2002/11/25 21:29:42 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.123 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1025,7 +1025,7 @@ booltestsel(Query *root, BoolTestType booltesttype, Node *arg, int varRelid)
 	 * can't hurt)
 	 */
 	if (IsA(arg, RelabelType))
-		arg = ((RelabelType *) arg)->arg;
+		arg = (Node *) ((RelabelType *) arg)->arg;
 
 	if (IsA(arg, Var) &&(varRelid == 0 || varRelid == ((Var *) arg)->varno))
 		var = (Var *) arg;
@@ -1246,7 +1246,7 @@ nulltestsel(Query *root, NullTestType nulltesttype, Node *arg, int varRelid)
 	 * Ignore any binary-compatible relabeling
 	 */
 	if (IsA(arg, RelabelType))
-		arg = ((RelabelType *) arg)->arg;
+		arg = (Node *) ((RelabelType *) arg)->arg;
 
 	if (IsA(arg, Var) &&
 		(varRelid == 0 || varRelid == ((Var *) arg)->varno))
@@ -1753,14 +1753,15 @@ mergejoinscansel(Query *root, Node *clause,
 	/* Deconstruct the merge clause */
 	if (!is_opclause(clause))
 		return;					/* shouldn't happen */
-	opno = ((Oper *) ((Expr *) clause)->oper)->opno;
+	opno = ((OpExpr *) clause)->opno;
 	left = get_leftop((Expr *) clause);
 	right = get_rightop((Expr *) clause);
 	if (!right)
 		return;					/* shouldn't happen */
 
 	/* Can't do anything if inputs are not Vars */
-	if (!IsA(left, Var) ||!IsA(right, Var))
+	if (!IsA(left, Var) ||
+		!IsA(right, Var))
 		return;
 
 	/* Verify mergejoinability and get left and right "<" operators */
@@ -2842,9 +2843,9 @@ get_restriction_var(List *args,
 	/* Ignore any binary-compatible relabeling */
 
 	if (IsA(left, RelabelType))
-		left = ((RelabelType *) left)->arg;
+		left = (Node *) ((RelabelType *) left)->arg;
 	if (IsA(right, RelabelType))
-		right = ((RelabelType *) right)->arg;
+		right = (Node *) ((RelabelType *) right)->arg;
 
 	/* Look for the var */
 
@@ -2895,9 +2896,9 @@ get_join_vars(List *args, Var **var1, Var **var2)
 
 	/* Ignore any binary-compatible relabeling */
 	if (IsA(left, RelabelType))
-		left = ((RelabelType *) left)->arg;
+		left = (Node *) ((RelabelType *) left)->arg;
 	if (IsA(right, RelabelType))
-		right = ((RelabelType *) right)->arg;
+		right = (Node *) ((RelabelType *) right)->arg;
 
 	if (IsA(left, Var))
 		*var1 = (Var *) left;
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 8cb41a9290b80fe485ad08d046daabc34f9b9250..fa3131873300e5f530cf0a44e8ebeacebac84da9 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.168 2002/12/06 05:20:24 momjian Exp $
+ * $Id: catversion.h,v 1.169 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200212061
+#define CATALOG_VERSION_NO	200212101
 
 #endif
diff --git a/src/include/executor/nodeSubplan.h b/src/include/executor/nodeSubplan.h
index c573cf900dfc6561040fb16c6b51ed427d7e6a16..e025c9de696167107259d7816af5c3fd18aec649 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.12 2002/12/05 15:50:38 tgl Exp $
+ * $Id: nodeSubplan.h,v 1.13 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,7 +16,7 @@
 
 #include "nodes/execnodes.h"
 
-extern SubPlanState *ExecInitSubPlan(SubPlan *node, EState *estate);
+extern SubPlanState *ExecInitSubPlan(SubPlanExpr *node, EState *estate);
 extern Datum ExecSubPlan(SubPlanState *node, List *pvar, ExprContext *econtext,
 			bool *isNull);
 extern void ExecEndSubPlan(SubPlanState *node);
diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h
index 68f0dcda49a215e41fcdc08309ca66ba0f651663..d1f4ebfc4002c8404e99ffd5ff8b2c285133d50b 100644
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.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: makefuncs.h,v 1.42 2002/11/25 21:29:42 tgl Exp $
+ * $Id: makefuncs.h,v 1.43 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,18 +22,13 @@ extern A_Expr *makeA_Expr(int oper, List *name, Node *lexpr, Node *rexpr);
 extern A_Expr *makeSimpleA_Expr(int oper, const char *name,
 				 Node *lexpr, Node *rexpr);
 
-extern Oper *makeOper(Oid opno,
-		 Oid opid,
-		 Oid opresulttype,
-		 bool opretset);
-
 extern Var *makeVar(Index varno,
 		AttrNumber varattno,
 		Oid vartype,
 		int32 vartypmod,
 		Index varlevelsup);
 
-extern TargetEntry *makeTargetEntry(Resdom *resdom, Node *expr);
+extern TargetEntry *makeTargetEntry(Resdom *resdom, Expr *expr);
 
 extern Resdom *makeResdom(AttrNumber resno,
 		   Oid restype,
@@ -49,9 +44,11 @@ extern Const *makeConst(Oid consttype,
 
 extern Const *makeNullConst(Oid consttype);
 
+extern Expr *makeBoolExpr(BoolExprType boolop, List *args);
+
 extern Alias *makeAlias(const char *aliasname, List *colnames);
 
-extern RelabelType *makeRelabelType(Node *arg, Oid rtype, int32 rtypmod,
+extern RelabelType *makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod,
 									CoercionForm rformat);
 
 extern RangeVar *makeRangeVar(char *schemaname, char *relname);
diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h
index 7db0525bad8875f6451f660c871f33f356db392b..99e1a62542c965a453b9c0406ee0614795b3051e 100644
--- a/src/include/nodes/nodeFuncs.h
+++ b/src/include/nodes/nodeFuncs.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: nodeFuncs.h,v 1.17 2002/06/20 20:29:51 momjian Exp $
+ * $Id: nodeFuncs.h,v 1.18 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern bool single_node(Node *node);
 extern bool var_is_outer(Var *var);
 extern bool var_is_rel(Var *var);
-extern Oper *replace_opid(Oper *oper);
+extern void set_opfuncid(OpExpr *opexpr);
 
 #endif   /* NODEFUNCS_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 2f3e71407aaadb82dfd5035527a3224a40a10b9e..aacdf60dd9ad396373fc8ca4507f01106541dcd8 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.129 2002/12/06 05:00:31 momjian Exp $
+ * $Id: nodes.h,v 1.130 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -62,7 +62,6 @@ typedef enum NodeTag
 	T_Hash,
 	T_SetOp,
 	T_Limit,
-	T_SubPlan,
 
 	/*
 	 * TAGS FOR PLAN STATE NODES (execnodes.h)
@@ -96,21 +95,32 @@ typedef enum NodeTag
 	 * TAGS FOR PRIMITIVE NODES (primnodes.h)
 	 */
 	T_Resdom = 300,
-	T_Fjoin,
+	T_Alias,
+	T_RangeVar,
 	T_Expr,
 	T_Var,
-	T_Oper,
 	T_Const,
 	T_Param,
 	T_Aggref,
+	T_ArrayRef,
+	T_FuncExpr,
+	T_OpExpr,
+	T_DistinctExpr,
+	T_BoolExpr,
 	T_SubLink,
-	T_Func,
+	T_SubPlanExpr,
 	T_FieldSelect,
-	T_ArrayRef,
 	T_RelabelType,
+	T_CaseExpr,
+	T_CaseWhen,
+	T_NullTest,
+	T_BooleanTest,
+	T_ConstraintTest,
+	T_ConstraintTestValue,
+	T_TargetEntry,
 	T_RangeTblRef,
-	T_FromExpr,
 	T_JoinExpr,
+	T_FromExpr,
 
 	/*
 	 * TAGS FOR PLANNER NODES (relation.h)
@@ -183,7 +193,6 @@ typedef enum NodeTag
 	T_ViewStmt,
 	T_LoadStmt,
 	T_CreateDomainStmt,
-	T_DomainConstraintValue,
 	T_CreatedbStmt,
 	T_DropdbStmt,
 	T_VacuumStmt,
@@ -228,30 +237,22 @@ typedef enum NodeTag
 	T_ResTarget,
 	T_TypeCast,
 	T_SortGroupBy,
-	T_Alias,
-	T_RangeVar,
 	T_RangeSubselect,
 	T_RangeFunction,
 	T_TypeName,
-	T_IndexElem,
 	T_ColumnDef,
+	T_IndexElem,
 	T_Constraint,
 	T_DefElem,
-	T_TargetEntry,
 	T_RangeTblEntry,
 	T_SortClause,
 	T_GroupClause,
-	T_NullTest,
-	T_BooleanTest,
-	T_ConstraintTest,
-	T_ConstraintTestValue,
-	T_CaseExpr,
-	T_CaseWhen,
 	T_FkConstraint,
 	T_PrivGrantee,
 	T_FuncWithArgs,
 	T_PrivTarget,
 	T_InsertDefault,
+	T_DomainConstraintValue,
 	T_CreateOpClassItem,
 	T_CompositeTypeStmt,
 
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 5201e1bb0e7287055b2f3c2af55ef90db81f1a2f..f2d92431b71e993121713004b70f1bdd99fb3591 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.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: parsenodes.h,v 1.221 2002/12/06 05:00:32 momjian Exp $
+ * $Id: parsenodes.h,v 1.222 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,7 +34,7 @@ typedef enum QuerySource
 
 /*
  * Query -
- *	  all statments are turned into a Query tree (via transformStmt)
+ *	  all statements are turned into a Query tree (via transformStmt)
  *	  for further processing by the optimizer
  *	  utility statements (i.e. non-optimizable statements)
  *	  have the *utilityStmt field set.
@@ -201,145 +201,6 @@ typedef struct TypeCast
 	TypeName   *typename;		/* the target type */
 } TypeCast;
 
-/*
- * CaseExpr - a CASE expression
- */
-typedef struct CaseExpr
-{
-	NodeTag		type;
-	Oid			casetype;
-	Node	   *arg;			/* implicit equality comparison argument */
-	List	   *args;			/* the arguments (list of WHEN clauses) */
-	Node	   *defresult;		/* the default result (ELSE clause) */
-} CaseExpr;
-
-/*
- * CaseWhen - an argument to a CASE expression
- */
-typedef struct CaseWhen
-{
-	NodeTag		type;
-	Node	   *expr;			/* comparison expression */
-	Node	   *result;			/* substitution result */
-} CaseWhen;
-
-/* ----------------
- * NullTest
- *
- * NullTest represents the operation of testing a value for NULLness.
- * Currently, we only support scalar input values, but eventually a
- * row-constructor input should be supported.
- * The appropriate test is performed and returned as a boolean Datum.
- * ----------------
- */
-
-typedef enum NullTestType
-{
-	IS_NULL, IS_NOT_NULL
-} NullTestType;
-
-typedef struct NullTest
-{
-	NodeTag		type;
-	Node	   *arg;			/* input expression */
-	NullTestType nulltesttype;	/* IS NULL, IS NOT NULL */
-} NullTest;
-
-/*
- * BooleanTest
- *
- * BooleanTest represents the operation of determining whether a boolean
- * is TRUE, FALSE, or UNKNOWN (ie, NULL).  All six meaningful combinations
- * are supported.  Note that a NULL input does *not* cause a NULL result.
- * The appropriate test is performed and returned as a boolean Datum.
- */
-
-typedef enum BoolTestType
-{
-	IS_TRUE, IS_NOT_TRUE, IS_FALSE, IS_NOT_FALSE, IS_UNKNOWN, IS_NOT_UNKNOWN
-} BoolTestType;
-
-typedef struct BooleanTest
-{
-	NodeTag		type;
-	Node	   *arg;			/* input expression */
-	BoolTestType booltesttype;	/* test type */
-} BooleanTest;
-
-/*
- * ConstraintTest
- *
- * ConstraintTest represents the operation of testing a value to see whether
- * it meets a constraint.  If so, the input value is returned as the result;
- * if not, an error is raised.
- */
-
-typedef enum ConstraintTestType
-{
-	CONSTR_TEST_NOTNULL,
-	CONSTR_TEST_CHECK
-} ConstraintTestType;
-
-typedef struct ConstraintTest
-{
-	NodeTag		type;
-	Node	   *arg;			/* input expression */
-	ConstraintTestType testtype;	/* test type */
-	char	   *name;			/* name of constraint (for error msgs) */
-	char	   *domname; 		/* name of domain (for error messages) */
-	Node	   *check_expr;		/* for CHECK test, a boolean expression */
-} ConstraintTest;
-
-/*
- * Placeholder node for the value to be processed by a domains
- * check constraint.
- */
-typedef struct DomainConstraintValue
-{
-	NodeTag		type;
-} DomainConstraintValue;
-
-typedef struct ConstraintTestValue
-{
-	NodeTag		type;
-	Oid			typeId;
-	int32		typeMod;
-} ConstraintTestValue;
-
-/*
- * ColumnDef - column definition (used in various creates)
- *
- * If the column has a default value, we may have the value expression
- * in either "raw" form (an untransformed parse tree) or "cooked" form
- * (the nodeToString representation of an executable expression tree),
- * depending on how this ColumnDef node was created (by parsing, or by
- * inheritance from an existing relation).	We should never have both
- * in the same node!
- *
- * The constraints list may contain a CONSTR_DEFAULT item in a raw
- * parsetree produced by gram.y, but transformCreateStmt will remove
- * the item and set raw_default instead.  CONSTR_DEFAULT items
- * should not appear in any subsequent processing.
- *
- * The "support" field, if not null, denotes a supporting relation that
- * should be linked by an internal dependency to the column.  Currently
- * this is only used to link a SERIAL column's sequence to the column.
- */
-typedef struct ColumnDef
-{
-	NodeTag		type;
-	char	   *colname;		/* name of column */
-	TypeName   *typename;		/* type of column */
-	int			inhcount;		/* number of times column is inherited */
-	bool		is_local;		/* column has local (non-inherited) def'n */
-	bool		is_not_null;	/* NOT NULL constraint specified? */
-	Node	   *raw_default;	/* default value (untransformed parse
-								 * tree) */
-	char	   *cooked_default; /* nodeToString representation */
-	List	   *constraints;	/* other constraints on column */
-	RangeVar   *support;		/* supporting relation, if any */
-} ColumnDef;
-
 /*
  * FuncCall - a function or aggregate invocation
  *
@@ -414,6 +275,15 @@ typedef struct InsertDefault
 	NodeTag		type;
 } InsertDefault;
 
+/*
+ * Empty node used as raw-parse-tree representation of VALUE keyword
+ * for domain check constraints.
+ */
+typedef struct DomainConstraintValue
+{
+	NodeTag		type;
+} DomainConstraintValue;
+
 /*
  * SortGroupBy - for ORDER BY clause
  */
@@ -446,6 +316,40 @@ typedef struct RangeFunction
 								 * assignment of RECORD TupleDesc */
 } RangeFunction;
 
+/*
+ * ColumnDef - column definition (used in various creates)
+ *
+ * If the column has a default value, we may have the value expression
+ * in either "raw" form (an untransformed parse tree) or "cooked" form
+ * (the nodeToString representation of an executable expression tree),
+ * depending on how this ColumnDef node was created (by parsing, or by
+ * inheritance from an existing relation).	We should never have both
+ * in the same node!
+ *
+ * The constraints list may contain a CONSTR_DEFAULT item in a raw
+ * parsetree produced by gram.y, but transformCreateStmt will remove
+ * the item and set raw_default instead.  CONSTR_DEFAULT items
+ * should not appear in any subsequent processing.
+ *
+ * The "support" field, if not null, denotes a supporting relation that
+ * should be linked by an internal dependency to the column.  Currently
+ * this is only used to link a SERIAL column's sequence to the column.
+ */
+typedef struct ColumnDef
+{
+	NodeTag		type;
+	char	   *colname;		/* name of column */
+	TypeName   *typename;		/* type of column */
+	int			inhcount;		/* number of times column is inherited */
+	bool		is_local;		/* column has local (non-inherited) def'n */
+	bool		is_not_null;	/* NOT NULL constraint specified? */
+	Node	   *raw_default;	/* default value (untransformed parse
+								 * tree) */
+	char	   *cooked_default; /* nodeToString representation */
+	List	   *constraints;	/* other constraints on column */
+	RangeVar   *support;		/* supporting relation, if any */
+} ColumnDef;
+
 /*
  * IndexElem - index parameters (used in CREATE INDEX)
  *
@@ -479,21 +383,6 @@ typedef struct DefElem
  *	Nodes for a Query tree
  ****************************************************************************/
 
-/*
- * TargetEntry -
- *	   a target  entry (used in the transformed target list)
- *
- * one of resdom or fjoin is not NULL. a target list is
- *		((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...)
- */
-typedef struct TargetEntry
-{
-	NodeTag		type;
-	Resdom	   *resdom;			/* fjoin overload this to be a list?? */
-	Fjoin	   *fjoin;
-	Node	   *expr;
-} TargetEntry;
-
 /*--------------------
  * RangeTblEntry -
  *	  A range table is a List of RangeTblEntry nodes.
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 097f8d93b1334bcb117ece115e0f358b172fb058..67a4d48782f1c072f2964ef74307cfefaadc36c5 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.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: plannodes.h,v 1.62 2002/12/05 15:50:39 tgl Exp $
+ * $Id: plannodes.h,v 1.63 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -375,31 +375,4 @@ typedef struct Limit
 	Node	   *limitCount;		/* COUNT parameter, or NULL if none */
 } Limit;
 
-/* ---------------------
- *		SubPlan node
- *
- * XXX Perhaps does not belong in this file?  It's not really a Plan node.
- * Should we make it inherit from Plan anyway?
- * ---------------------
- */
-typedef struct SubPlan
-{
-	NodeTag		type;
-	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 */
-	/* 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 corr. Vars from parent plan */
-	SubLink    *sublink;		/* SubLink node from parser; holds info
-								 * about what to do with subselect's
-								 * results */
-
-	struct SubPlanState *pstate; /* XXX TEMPORARY HACK */
-} SubPlan;
-
 #endif   /* PLANNODES_H */
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 11e74a8d92b83b4205ca34975b12af4866cf3e4d..ec0ad4235c96fb0a9d30d6dfee30a09859c27479 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.71 2002/11/30 21:25:06 tgl Exp $
+ * $Id: primnodes.h,v 1.72 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -67,31 +67,6 @@ typedef struct Resdom
 								 * from final target list */
 } Resdom;
 
-/*
- * Fjoin
- */
-typedef struct Fjoin
-{
-	NodeTag		type;
-	bool		fj_initialized; /* true if the Fjoin has already been
-								 * initialized for the current target list
-								 * evaluation */
-	int			fj_nNodes;		/* The number of Iter nodes returning sets
-								 * that the node will flatten */
-	List	   *fj_innerNode;	/* exactly one Iter node.  We eval every
-								 * node in the outerList once then eval
-								 * the inner node to completion pair the
-								 * outerList result vector with each inner
-								 * result to form the full result.	When
-								 * the inner has been exhausted, we get
-								 * the next outer result vector and reset
-								 * the inner. */
-	DatumPtr	fj_results;		/* The complete (flattened) result vector */
-	BoolPtr		fj_alwaysDone;	/* a null vector to indicate sets with a
-								 * cardinality of 0, we treat them as the
-								 * set {NULL}. */
-} Fjoin;
-
 
 /*
  * Alias -
@@ -140,96 +115,20 @@ typedef struct RangeVar
  */
 
 /*
- * CoercionContext - distinguishes the allowed set of type casts
+ * Expr - generic superclass for executable-expression nodes
  *
- * NB: ordering of the alternatives is significant; later (larger) values
- * allow more casts than earlier ones.
+ * All node types that are used in executable expression trees should derive
+ * from Expr (that is, have Expr as their first field).  Since Expr only
+ * contains NodeTag, this is a formality, but it is an easy form of
+ * documentation.  See also the ExprState node types in execnodes.h.
  */
-typedef enum CoercionContext
-{
-	COERCION_IMPLICIT,			/* coercion in context of expression */
-	COERCION_ASSIGNMENT,		/* coercion in context of assignment */
-	COERCION_EXPLICIT			/* explicit cast operation */
-} CoercionContext;
-
-/*
- * CoercionForm - information showing how to display a function-call node
- */
-typedef enum CoercionForm
-{
-	COERCE_EXPLICIT_CALL,		/* display as a function call */
-	COERCE_EXPLICIT_CAST,		/* display as an explicit cast */
-	COERCE_IMPLICIT_CAST,		/* implicit cast, so hide it */
-	COERCE_DONTCARE				/* special case for pathkeys */
-} CoercionForm;
-
-/*
- * Expr
- *
- * Note: DISTINCT_EXPR implements the "x IS DISTINCT FROM y" construct.
- * This is similar to an OP_EXPR, except for its handling of NULL inputs.
- * The oper field is always an Oper node for the "=" operator for x and y.
- * (We use "=", not the more obvious "<>", because more datatypes have "="
- * than "<>".  This means the executor must invert the operator result.)
- */
-typedef enum OpType
-{
-	OP_EXPR, DISTINCT_EXPR, FUNC_EXPR,
-	OR_EXPR, AND_EXPR, NOT_EXPR, SUBPLAN_EXPR
-} OpType;
-
 typedef struct Expr
 {
 	NodeTag		type;
-	Oid			typeOid;		/* oid of the type of this expression */
-	OpType		opType;			/* kind of expression */
-	Node	   *oper;			/* operator node if needed (Oper, Func, or
-								 * SubPlan) */
-	List	   *args;			/* arguments to this expression */
 } Expr;
 
 /*
- * Oper - Expr subnode for an OP_EXPR (or DISTINCT_EXPR)
- *
- * NOTE: in the good old days 'opno' used to be both (or either, or
- * neither) the pg_operator oid, and/or the pg_proc oid depending
- * on the postgres module in question (parser->pg_operator,
- * executor->pg_proc, planner->both), the mood of the programmer,
- * and the phase of the moon (rumors that it was also depending on the day
- * of the week are probably false). To make things even more postgres-like
- * (i.e. a mess) some comments were referring to 'opno' using the name
- * 'opid'. Anyway, now we have two separate fields, and of course that
- * immediately removes all bugs from the code...		[ sp :-) ].
- *
- * Note also that opid is not necessarily filled in immediately on creation
- * of the node.  The planner makes sure it is valid before passing the node
- * tree to the executor, but during parsing/planning opid is typically 0.
- */
-typedef struct Oper
-{
-	NodeTag		type;
-	Oid			opno;			/* PG_OPERATOR OID of the operator */
-	Oid			opid;			/* PG_PROC OID of underlying function */
-	Oid			opresulttype;	/* PG_TYPE OID of result value */
-	bool		opretset;		/* true if operator returns set */
-	FunctionCachePtr op_fcache; /* runtime state, else NULL */
-} Oper;
-
-/*
- * Func - Expr subnode for a FUNC_EXPR
- */
-typedef struct Func
-{
-	NodeTag		type;
-	Oid			funcid;			/* PG_PROC OID of the function */
-	Oid			funcresulttype; /* PG_TYPE OID of result value */
-	bool		funcretset;		/* true if function returns set */
-	CoercionForm funcformat;	/* how to display this function call */
-	FunctionCachePtr func_fcache;		/* runtime state, or NULL */
-} Func;
-
-/*
- * Var
+ * Var - expression node representing a variable (ie, a table column)
  *
  * Note: during parsing/planning, varnoold/varoattno are always just copies
  * of varno/varattno.  At the tail end of planning, Var nodes appearing in
@@ -248,7 +147,7 @@ typedef struct Func
 
 typedef struct Var
 {
-	NodeTag		type;
+	Expr		xpr;
 	Index		varno;			/* index of this var's relation in the
 								 * range table (could also be INNER or
 								 * OUTER) */
@@ -272,7 +171,7 @@ typedef struct Var
  */
 typedef struct Const
 {
-	NodeTag		type;
+	Expr		xpr;
 	Oid			consttype;		/* PG_TYPE OID of the constant's datatype */
 	int			constlen;		/* typlen of the constant's datatype */
 	Datum		constvalue;		/* the constant's value */
@@ -300,12 +199,11 @@ typedef struct Const
  *
  *		PARAM_EXEC:	 The parameter is an internal executor parameter.
  *				It has a number contained in the `paramid' field.
- *
  * ----------------
  */
 typedef struct Param
 {
-	NodeTag		type;
+	Expr		xpr;
 	int			paramkind;		/* kind of parameter. See above */
 	AttrNumber	paramid;		/* numeric ID for parameter ("$1") */
 	char	   *paramname;		/* name for parameter ("$.foo") */
@@ -317,15 +215,156 @@ typedef struct Param
  */
 typedef struct Aggref
 {
-	NodeTag		type;
+	Expr		xpr;
 	Oid			aggfnoid;		/* pg_proc Oid of the aggregate */
 	Oid			aggtype;		/* type Oid of result of the aggregate */
-	Node	   *target;			/* expression we are aggregating on */
+	Expr	   *target;			/* expression we are aggregating on */
 	bool		aggstar;		/* TRUE if argument was really '*' */
 	bool		aggdistinct;	/* TRUE if it's agg(DISTINCT ...) */
+
+	/* XXX this should move to AggrefExprState: */
 	int			aggno;			/* workspace for executor (see nodeAgg.c) */
 } Aggref;
 
+/* ----------------
+ *	ArrayRef: describes an array subscripting operation
+ *
+ * An ArrayRef can describe fetching a single element from an array,
+ * fetching a subarray (array slice), storing a single element into
+ * an array, or storing a slice.  The "store" cases work with an
+ * initial array value and a source value that is inserted into the
+ * appropriate part of the array; the result of the operation is an
+ * entire new modified array value.
+ *
+ * If reflowerindexpr = NIL, then we are fetching or storing a single array
+ * element at the subscripts given by refupperindexpr.	Otherwise we are
+ * fetching or storing an array slice, that is a rectangular subarray
+ * with lower and upper bounds given by the index expressions.
+ * reflowerindexpr must be the same length as refupperindexpr when it
+ * is not NIL.
+ *
+ * Note: array types can be fixed-length (refattrlength > 0), but only
+ * when the element type is itself fixed-length.  Otherwise they are
+ * varlena structures and have refattrlength = -1.	In any case,
+ * an array type is never pass-by-value.
+ *
+ * Note: refrestype is NOT the element type, but the array type,
+ * when doing subarray fetch or either type of store.  It might be a good
+ * idea to include a refelemtype field as well.
+ * ----------------
+ */
+typedef struct ArrayRef
+{
+	Expr		xpr;
+	Oid			refrestype;		/* type of the result of the ArrayRef
+								 * operation */
+	int			refattrlength;	/* typlen of array type */
+	int			refelemlength;	/* typlen of the array element type */
+	bool		refelembyval;	/* is the element type pass-by-value? */
+	char		refelemalign;	/* typalign of the element type */
+	List	   *refupperindexpr;/* expressions that evaluate to upper
+								 * array indexes */
+	List	   *reflowerindexpr;/* expressions that evaluate to lower
+								 * array indexes */
+	Expr	   *refexpr;		/* the expression that evaluates to an
+								 * array value */
+	Expr	   *refassgnexpr;	/* expression for the source value, or
+								 * NULL if fetch */
+} ArrayRef;
+
+/*
+ * CoercionContext - distinguishes the allowed set of type casts
+ *
+ * NB: ordering of the alternatives is significant; later (larger) values
+ * allow more casts than earlier ones.
+ */
+typedef enum CoercionContext
+{
+	COERCION_IMPLICIT,			/* coercion in context of expression */
+	COERCION_ASSIGNMENT,		/* coercion in context of assignment */
+	COERCION_EXPLICIT			/* explicit cast operation */
+} CoercionContext;
+
+/*
+ * CoercionForm - information showing how to display a function-call node
+ */
+typedef enum CoercionForm
+{
+	COERCE_EXPLICIT_CALL,		/* display as a function call */
+	COERCE_EXPLICIT_CAST,		/* display as an explicit cast */
+	COERCE_IMPLICIT_CAST,		/* implicit cast, so hide it */
+	COERCE_DONTCARE				/* special case for pathkeys */
+} CoercionForm;
+
+/*
+ * FuncExpr - expression node for a function call
+ */
+typedef struct FuncExpr
+{
+	Expr		xpr;
+	Oid			funcid;			/* PG_PROC OID of the function */
+	Oid			funcresulttype; /* PG_TYPE OID of result value */
+	bool		funcretset;		/* true if function returns set */
+	CoercionForm funcformat;	/* how to display this function call */
+	List	   *args;			/* arguments to the function */
+
+	FunctionCachePtr func_fcache;		/* XXX runtime state, or NULL */
+} FuncExpr;
+
+/*
+ * OpExpr - expression node for an operator invocation
+ *
+ * Semantically, this is essentially the same as a function call.
+ *
+ * Note that opfuncid is not necessarily filled in immediately on creation
+ * of the node.  The planner makes sure it is valid before passing the node
+ * tree to the executor, but during parsing/planning opfuncid is typically 0.
+ */
+typedef struct OpExpr
+{
+	Expr		xpr;
+	Oid			opno;			/* PG_OPERATOR OID of the operator */
+	Oid			opfuncid;		/* PG_PROC OID of underlying function */
+	Oid			opresulttype;	/* PG_TYPE OID of result value */
+	bool		opretset;		/* true if operator returns set */
+	List	   *args;			/* arguments to the operator (1 or 2) */
+
+	FunctionCachePtr op_fcache; /* XXX runtime state, else NULL */
+} OpExpr;
+
+/*
+ * DistinctExpr - expression node for "x IS DISTINCT FROM y"
+ *
+ * Except for the nodetag, this is represented identically to an OpExpr
+ * referencing the "=" operator for x and y.
+ * We use "=", not the more obvious "<>", because more datatypes have "="
+ * than "<>".  This means the executor must invert the operator result.
+ * Note that the operator function won't be called at all if either input
+ * is NULL, since then the result can be determined directly.
+ */
+typedef OpExpr DistinctExpr;
+
+/*
+ * BoolExpr - expression node for the basic Boolean operators AND, OR, NOT
+ *
+ * Notice the arguments are given as a List.  For NOT, of course the list
+ * must always have exactly one element.  For AND and OR, the executor can
+ * handle any number of arguments.  The parser treats AND and OR as binary
+ * and so it only produces two-element lists, but the optimizer will flatten
+ * trees of AND and OR nodes to produce longer lists when possible.
+ */
+typedef enum BoolExprType
+{
+	AND_EXPR, OR_EXPR, NOT_EXPR
+} BoolExprType;
+
+typedef struct BoolExpr
+{
+	Expr		xpr;
+	BoolExprType boolop;
+	List	   *args;			/* arguments to this expression */
+} BoolExpr;
+
 /* ----------------
  * SubLink
  *
@@ -348,19 +387,23 @@ typedef struct Aggref
  * depending on the "useor" flag.  ALL and ANY combine the per-row results
  * 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
+ * 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 Oper nodes, one per lefthand
+ *	  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 actual Expr trees for
- *	  these operators yet.	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 Expr
+ *	  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.
@@ -370,7 +413,7 @@ typedef struct Aggref
  * 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 SubPlan nodes.
+ * found in SubLinks that are children of SubPlanExpr nodes.
  *
  * In EXISTS and EXPR SubLinks, both lefthand and oper are unused and are
  * always NIL.	useor is not significant either for these sublink types.
@@ -384,62 +427,45 @@ typedef enum SubLinkType
 
 typedef struct SubLink
 {
-	NodeTag		type;
+	Expr		xpr;
 	SubLinkType subLinkType;	/* EXISTS, ALL, ANY, MULTIEXPR, EXPR */
 	bool		useor;			/* TRUE to combine column results with
 								 * "OR" not "AND" */
 	List	   *lefthand;		/* list of outer-query expressions on the
 								 * left */
-	List	   *oper;			/* list of Oper nodes for combining
-								 * operators */
+	List	   *oper;			/* list of OpExpr nodes for combining
+								 * operators, or final list of executable
+								 * expressions */
 	Node	   *subselect;		/* subselect as Query* or parsetree */
 } SubLink;
 
-/* ----------------
- *	ArrayRef: describes an array subscripting operation
- *
- * An ArrayRef can describe fetching a single element from an array,
- * fetching a subarray (array slice), storing a single element into
- * an array, or storing a slice.  The "store" cases work with an
- * initial array value and a source value that is inserted into the
- * appropriate part of the array; the result of the operation is an
- * entire new modified array value.
- *
- * If reflowerindexpr = NIL, then we are fetching or storing a single array
- * element at the subscripts given by refupperindexpr.	Otherwise we are
- * fetching or storing an array slice, that is a rectangular subarray
- * with lower and upper bounds given by the index expressions.
- * reflowerindexpr must be the same length as refupperindexpr when it
- * is not NIL.
- *
- * Note: array types can be fixed-length (refattrlength > 0), but only
- * when the element type is itself fixed-length.  Otherwise they are
- * varlena structures and have refattrlength = -1.	In any case,
- * an array type is never pass-by-value.
+/*
+ * SubPlanExpr - executable expression node for a subplan (sub-SELECT)
  *
- * Note: refrestype is NOT the element type, but the array type,
- * when doing subarray fetch or either type of store.  It might be a good
- * idea to include a refelemtype field as well.
- * ----------------
+ * The planner replaces SubLink nodes in expression trees with SubPlanExpr
+ * nodes after it has finished planning the subquery.  See notes above.
  */
-typedef struct ArrayRef
+typedef struct SubPlanExpr
 {
-	NodeTag		type;
-	Oid			refrestype;		/* type of the result of the ArrayRef
-								 * operation */
-	int			refattrlength;	/* typlen of array type */
-	int			refelemlength;	/* typlen of the array element type */
-	bool		refelembyval;	/* is the element type pass-by-value? */
-	char		refelemalign;	/* typalign of the element type */
-	List	   *refupperindexpr;/* expressions that evaluate to upper
-								 * array indexes */
-	List	   *reflowerindexpr;/* expressions that evaluate to lower
-								 * array indexes */
-	Node	   *refexpr;		/* the expression that evaluates to an
-								 * array value */
-	Node	   *refassgnexpr;	/* expression for the source value, or
-								 * NULL if fetch */
-} ArrayRef;
+	Expr		xpr;
+	Oid			typeOid;		/* PG_TYPE OID of the expression result */
+	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 */
+	/* 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 */
+
+	struct SubPlanState *pstate; /* XXX TEMPORARY HACK */
+} SubPlanExpr;
 
 /* ----------------
  * FieldSelect
@@ -453,8 +479,8 @@ typedef struct ArrayRef
 
 typedef struct FieldSelect
 {
-	NodeTag		type;
-	Node	   *arg;			/* input expression */
+	Expr		xpr;
+	Expr	   *arg;			/* input expression */
 	AttrNumber	fieldnum;		/* attribute number of field to extract */
 	Oid			resulttype;		/* type of the field (result type of this
 								 * node) */
@@ -476,13 +502,134 @@ typedef struct FieldSelect
 
 typedef struct RelabelType
 {
-	NodeTag		type;
-	Node	   *arg;			/* input expression */
+	Expr		xpr;
+	Expr	   *arg;			/* input expression */
 	Oid			resulttype;		/* output type of coercion expression */
 	int32		resulttypmod;	/* output typmod (usually -1) */
 	CoercionForm relabelformat;	/* how to display this node */
 } RelabelType;
 
+/*
+ * CaseExpr - a CASE expression
+ */
+typedef struct CaseExpr
+{
+	Expr		xpr;
+	Oid			casetype;		/* type of expression result */
+	Expr	   *arg;			/* implicit equality comparison argument */
+	List	   *args;			/* the arguments (list of WHEN clauses) */
+	Expr	   *defresult;		/* the default result (ELSE clause) */
+} CaseExpr;
+
+/*
+ * CaseWhen - an argument to a CASE expression
+ */
+typedef struct CaseWhen
+{
+	Expr		xpr;
+	Expr	   *expr;			/* condition expression */
+	Expr	   *result;			/* substitution result */
+} CaseWhen;
+
+/* ----------------
+ * NullTest
+ *
+ * NullTest represents the operation of testing a value for NULLness.
+ * Currently, we only support scalar input values, but eventually a
+ * row-constructor input should be supported.
+ * The appropriate test is performed and returned as a boolean Datum.
+ * ----------------
+ */
+
+typedef enum NullTestType
+{
+	IS_NULL, IS_NOT_NULL
+} NullTestType;
+
+typedef struct NullTest
+{
+	Expr		xpr;
+	Expr	   *arg;			/* input expression */
+	NullTestType nulltesttype;	/* IS NULL, IS NOT NULL */
+} NullTest;
+
+/*
+ * BooleanTest
+ *
+ * BooleanTest represents the operation of determining whether a boolean
+ * is TRUE, FALSE, or UNKNOWN (ie, NULL).  All six meaningful combinations
+ * are supported.  Note that a NULL input does *not* cause a NULL result.
+ * The appropriate test is performed and returned as a boolean Datum.
+ */
+
+typedef enum BoolTestType
+{
+	IS_TRUE, IS_NOT_TRUE, IS_FALSE, IS_NOT_FALSE, IS_UNKNOWN, IS_NOT_UNKNOWN
+} BoolTestType;
+
+typedef struct BooleanTest
+{
+	Expr		xpr;
+	Expr	   *arg;			/* input expression */
+	BoolTestType booltesttype;	/* test type */
+} BooleanTest;
+
+/*
+ * ConstraintTest
+ *
+ * ConstraintTest represents the operation of testing a value to see whether
+ * it meets a constraint.  If so, the input value is returned as the result;
+ * if not, an error is raised.
+ */
+
+typedef enum ConstraintTestType
+{
+	CONSTR_TEST_NOTNULL,
+	CONSTR_TEST_CHECK
+} ConstraintTestType;
+
+typedef struct ConstraintTest
+{
+	Expr		xpr;
+	Expr	   *arg;			/* input expression */
+	ConstraintTestType testtype;	/* test type */
+	char	   *name;			/* name of constraint (for error msgs) */
+	char	   *domname; 		/* name of domain (for error messages) */
+	Expr	   *check_expr;		/* for CHECK test, a boolean expression */
+} ConstraintTest;
+
+/*
+ * Placeholder node for the value to be processed by a domains
+ * check constraint.  This is effectively like a Param; could we use
+ * a Param node instead?
+ */
+typedef struct ConstraintTestValue
+{
+	Expr		xpr;
+	Oid			typeId;
+	int32		typeMod;
+} ConstraintTestValue;
+
+
+/*
+ * TargetEntry -
+ *	   a target entry (used in query target lists)
+ *
+ * Strictly speaking, a TargetEntry isn't an expression node (since it can't
+ * be evaluated by ExecEvalExpr).  But we treat it as one anyway, since in
+ * very many places it's convenient to process a whole query targetlist as a
+ * single expression tree.
+ *
+ * The separation between TargetEntry and Resdom is historical.  One of these
+ * days, Resdom should probably get folded into TargetEntry.
+ */
+typedef struct TargetEntry
+{
+	Expr		xpr;
+	Resdom	   *resdom;			/* descriptor for targetlist item */
+	Expr	   *expr;			/* expression to evaluate */
+} TargetEntry;
+
 
 /* ----------------------------------------------------------------
  *					node types for join trees
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 333ca0b695b497572943cccdc2e8cc3c14237273..6da47683e6e23f21e44c7875776693b4a9ece905 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.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: relation.h,v 1.73 2002/12/05 15:50:39 tgl Exp $
+ * $Id: relation.h,v 1.74 2002/12/12 15:49:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -295,7 +295,7 @@ typedef struct PathKeyItem
 
 	/*
 	 * key typically points to a Var node, ie a relation attribute, but it
-	 * can also point to a Func clause representing the value indexed by a
+	 * can also point to a FuncExpr clause representing the value indexed by a
 	 * functional index.  Someday we might allow arbitrary expressions as
 	 * path keys, so don't assume more than you must.
 	 */
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index da0fe4c5102e5b6aa64d4443a8a1549e0851b640..8da7a8688efb9667179f3a72a25d59f64801f723 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.56 2002/12/01 21:05:14 tgl Exp $
+ * $Id: clauses.h,v 1.57 2002/12/12 15:49:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,23 +16,28 @@
 
 #include "nodes/relation.h"
 
-extern Expr *make_clause(int type, Node *oper, List *args);
 
-extern bool is_opclause(Node *clause);
-extern Expr *make_opclause(Oper *op, Var *leftop, Var *rightop);
+
+#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))
+
+
+extern Expr *make_opclause(Oid opno, Oid opresulttype, bool opretset,
+						   Expr *leftop, Expr *rightop);
 extern Var *get_leftop(Expr *clause);
 extern Var *get_rightop(Expr *clause);
 
-extern bool is_funcclause(Node *clause);
-extern Expr *make_funcclause(Func *func, List *funcargs);
-
-extern bool or_clause(Node *clause);
-extern Expr *make_orclause(List *orclauses);
+extern Expr *make_funcclause(Oid funcid, Oid funcresulttype, bool funcretset,
+							 CoercionForm funcformat, List *funcargs);
 
 extern bool not_clause(Node *clause);
 extern Expr *make_notclause(Expr *notclause);
 extern Expr *get_notclausearg(Expr *notclause);
 
+extern bool or_clause(Node *clause);
+extern Expr *make_orclause(List *orclauses);
+
 extern bool and_clause(Node *clause);
 extern Expr *make_andclause(List *andclauses);
 extern Node *make_and_qual(Node *qual1, Node *qual2);
@@ -60,7 +65,7 @@ extern bool has_distinct_on_clause(Query *query);
 
 extern void clause_get_relids_vars(Node *clause, Relids *relids, List **vars);
 extern int	NumRelids(Node *clause);
-extern void CommuteClause(Expr *clause);
+extern void CommuteClause(OpExpr *clause);
 
 extern Node *eval_const_expressions(Node *node);
 
@@ -78,8 +83,4 @@ extern bool query_tree_walker(Query *query, bool (*walker) (),
 extern void query_tree_mutator(Query *query, Node *(*mutator) (),
 							   void *context, int flags);
 
-#define is_subplan(clause)	((clause) != NULL && \
-							 IsA(clause, Expr) && \
-							 ((Expr *) (clause))->opType == SUBPLAN_EXPR)
-
 #endif   /* CLAUSES_H */
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index b03ce0453e6dd0c765cafdf3740b571730633b26..06f585f722007b011fcf65651a1ace7c211bd2cc 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: paths.h,v 1.61 2002/11/24 21:52:15 tgl Exp $
+ * $Id: paths.h,v 1.62 2002/12/12 15:49:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,8 +42,6 @@ extern void debug_print_rel(Query *root, RelOptInfo *rel);
 extern void create_index_paths(Query *root, RelOptInfo *rel);
 extern Path *best_inner_indexscan(Query *root, RelOptInfo *rel,
 								  Relids outer_relids, JoinType jointype);
-extern Oid indexable_operator(Expr *clause, Oid opclass,
-				   bool indexkey_on_left);
 extern List *extract_or_indexqual_conditions(RelOptInfo *rel,
 								IndexOptInfo *index,
 								Expr *orsubclause);
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index ecd7bca604246765eb75a0c0d60a288483adb882..134adad9b604c99f35225bf6042a7cebd9036f78 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.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: planmain.h,v 1.63 2002/11/21 00:42:19 tgl Exp $
+ * $Id: planmain.h,v 1.64 2002/12/12 15:49:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -68,6 +68,6 @@ extern void set_plan_references(Plan *plan, List *rtable);
 extern List *join_references(List *clauses, List *rtable,
 				List *outer_tlist, List *inner_tlist,
 				Index acceptable_rel);
-extern void fix_opids(Node *node);
+extern void fix_opfuncids(Node *node);
 
 #endif   /* PLANMAIN_H */
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 007a3ffbe7955060583d5d9d3c3a6f9a89b58dfd..23d457263e82d85978e5948e557c6d8cc56a114e 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3,7 +3,7 @@
  *			  procedural language
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.72 2002/12/05 15:50:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.73 2002/12/12 15:49:42 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -3499,44 +3499,130 @@ exec_cast_value(Datum value, Oid valtype,
 static bool
 exec_simple_check_node(Node *node)
 {
+	if (node == NULL)
+		return TRUE;
+
 	switch (nodeTag(node))
 	{
-		case T_Expr:
+		case T_Const:
+			return TRUE;
+
+		case T_Param:
+			return TRUE;
+
+		case T_ArrayRef:
 			{
-				Expr	   *expr = (Expr *) node;
-				List	   *l;
+				ArrayRef   *expr = (ArrayRef *) node;
 
-				switch (expr->opType)
-				{
-					case OP_EXPR:
-					case DISTINCT_EXPR:
-					case FUNC_EXPR:
-					case OR_EXPR:
-					case AND_EXPR:
-					case NOT_EXPR:
-						break;
+				if (!exec_simple_check_node((Node *) expr->refupperindexpr))
+					return FALSE;
+				if (!exec_simple_check_node((Node *) expr->reflowerindexpr))
+					return FALSE;
+				if (!exec_simple_check_node((Node *) expr->refexpr))
+					return FALSE;
+				if (!exec_simple_check_node((Node *) expr->refassgnexpr))
+					return FALSE;
 
-					default:
-						return FALSE;
-				}
+				return TRUE;
+			}
 
-				foreach(l, expr->args)
-				{
-					if (!exec_simple_check_node(lfirst(l)))
-						return FALSE;
-				}
+		case T_FuncExpr:
+			{
+				FuncExpr   *expr = (FuncExpr *) node;
+
+				if (expr->funcretset)
+					return FALSE;
+				if (!exec_simple_check_node((Node *) expr->args))
+					return FALSE;
 
 				return TRUE;
 			}
 
-		case T_Param:
-			return TRUE;
+		case T_OpExpr:
+			{
+				OpExpr	   *expr = (OpExpr *) node;
 
-		case T_Const:
-			return TRUE;
+				if (expr->opretset)
+					return FALSE;
+				if (!exec_simple_check_node((Node *) expr->args))
+					return FALSE;
+
+				return TRUE;
+			}
+
+		case T_DistinctExpr:
+			{
+				DistinctExpr *expr = (DistinctExpr *) node;
+
+				if (expr->opretset)
+					return FALSE;
+				if (!exec_simple_check_node((Node *) expr->args))
+					return FALSE;
+
+				return TRUE;
+			}
+
+		case T_BoolExpr:
+			{
+				BoolExpr   *expr = (BoolExpr *) node;
+
+				if (!exec_simple_check_node((Node *) expr->args))
+					return FALSE;
+
+				return TRUE;
+			}
+
+		case T_FieldSelect:
+			return exec_simple_check_node((Node *) ((FieldSelect *) node)->arg);
 
 		case T_RelabelType:
-			return exec_simple_check_node(((RelabelType *) node)->arg);
+			return exec_simple_check_node((Node *) ((RelabelType *) node)->arg);
+
+		case T_CaseExpr:
+			{
+				CaseExpr   *expr = (CaseExpr *) node;
+
+				if (!exec_simple_check_node((Node *) expr->arg))
+					return FALSE;
+				if (!exec_simple_check_node((Node *) expr->args))
+					return FALSE;
+				if (!exec_simple_check_node((Node *) expr->defresult))
+					return FALSE;
+
+				return TRUE;
+			}
+
+		case T_CaseWhen:
+			{
+				CaseWhen   *when = (CaseWhen *) node;
+
+				if (!exec_simple_check_node((Node *) when->expr))
+					return FALSE;
+				if (!exec_simple_check_node((Node *) when->result))
+					return FALSE;
+
+				return TRUE;
+			}
+
+		case T_NullTest:
+			return exec_simple_check_node((Node *) ((NullTest *) node)->arg);
+
+		case T_BooleanTest:
+			return exec_simple_check_node((Node *) ((BooleanTest *) node)->arg);
+
+		case T_List:
+			{
+				List	   *expr = (List *) node;
+				List	   *l;
+
+				foreach(l, expr)
+				{
+					if (!exec_simple_check_node(lfirst(l)))
+						return FALSE;
+				}
+
+				return TRUE;
+			}
 
 		default:
 			return FALSE;
@@ -3596,18 +3682,17 @@ exec_simple_check_plan(PLpgSQL_expr * expr)
 	tle = (TargetEntry *) lfirst(plan->targetlist);
 
 	/*
-	 * 5. Check that all the nodes in the expression are one of Expr,
-	 * Param or Const.
+	 * 5. Check that all the nodes in the expression are non-scary.
 	 */
-	if (!exec_simple_check_node(tle->expr))
+	if (!exec_simple_check_node((Node *) tle->expr))
 		return;
 
 	/*
 	 * Yes - this is a simple expression. Remember the expression and the
 	 * return type
 	 */
-	expr->plan_simple_expr = tle->expr;
-	expr->plan_simple_type = exprType(tle->expr);
+	expr->plan_simple_expr = (Node *) tle->expr;
+	expr->plan_simple_type = exprType((Node *) tle->expr);
 }
 
 /*