diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index e4e83d654ac52252fd070c587cbcb34a660155f1..4bd0eb2ff31c39bdb222b0bf87d4c8799204cf07 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -94,8 +94,25 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
 			Const	   *con = lsecond(expr->args);
 			bool		isnull;
 
+			/*
+			 * The righthand side of the expression should be either a Const
+			 * or a function call taking a Const as arg (the function would
+			 * be a run-time type coercion inserted by the parser to get to
+			 * the input type needed by the operator).  Find the Const node
+			 * and insert the actual righthand side value into it.
+			 */
+			if (! IsA(con, Const))
+			{
+				Assert(IsA(con, Expr));
+				con = lfirst(((Expr *) con)->args);
+				Assert(IsA(con, Const));
+			}
 			con->constvalue = heap_getattr(tup, i, tdesc, &(con->constisnull));
-			result = ExecEvalExpr((Node *) expr, econtext, &isnull, (bool *) NULL);
+			/*
+			 * Now we can eval the expression.
+			 */
+			result = ExecEvalExpr((Node *) expr, econtext, &isnull,
+								  (bool *) NULL);
 			if (isnull)
 			{
 				if (subLinkType == EXPR_SUBLINK)
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index c275b7adc457a819af76ee383bbeeda6e00f3ac1..7e5d2be749eabecce6b9e8b84f52891cead33957 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -6,18 +6,24 @@
  * Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.23 1999/08/22 20:14:49 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.24 1999/08/25 23:21:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "catalog/pg_operator.h"
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/planner.h"
 #include "optimizer/subselect.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_node.h"
+#include "parser/parse_oper.h"
+#include "utils/lsyscache.h"
+
 
 int			PlannerQueryLevel;	/* level of current query */
 List	   *PlannerInitPlan;	/* init subplans for current query */
@@ -46,7 +52,7 @@ int			PlannerPlanId;		/* to assign unique ID to subquery plans */
  * is set from the absolute level value given by varlevel.
  */
 static int
-_new_param(Var *var, int varlevel)
+new_param(Var *var, int varlevel)
 {
 	Var		   *paramVar = (Var *) copyObject(var);
 
@@ -62,7 +68,7 @@ _new_param(Var *var, int varlevel)
  * which is expected to have varlevelsup > 0 (ie, it is not local).
  */
 static Param *
-_replace_var(Var *var)
+replace_var(Var *var)
 {
 	List	   *ppv;
 	Param	   *retval;
@@ -98,7 +104,7 @@ _replace_var(Var *var)
 	if (! ppv)
 	{
 		/* Nope, so make a new one */
-		i = _new_param(var, varlevel);
+		i = new_param(var, varlevel);
 	}
 
 	retval = makeNode(Param);
@@ -109,8 +115,11 @@ _replace_var(Var *var)
 	return retval;
 }
 
+/*
+ * Convert a bare SubLink (as created by the parser) into a SubPlan.
+ */
 static Node *
-_make_subplan(SubLink *slink)
+make_subplan(SubLink *slink)
 {
 	SubPlan    *node = makeNode(SubPlan);
 	Plan	   *plan;
@@ -126,7 +135,7 @@ _make_subplan(SubLink *slink)
 
 	/*
 	 * Assign subPlan, extParam and locParam to plan nodes. At the moment,
-	 * SS_finalize_plan doesn't handle initPlan-s and so we assigne them
+	 * SS_finalize_plan doesn't handle initPlan-s and so we assign them
 	 * to the topmost plan node and take care about its extParam too.
 	 */
 	(void) SS_finalize_plan(plan);
@@ -169,31 +178,58 @@ _make_subplan(SubLink *slink)
 	 */
 	if (node->parParam == NULL && slink->subLinkType == EXPR_SUBLINK)
 	{
+		List	   *newoper = NIL;
 		int			i = 0;
 
-		/* transform right side of all sublink Oper-s into Param */
+		/*
+		 * Convert oper list of Opers into a list of Exprs, using
+		 * lefthand arguments and Params representing inside results.
+		 */
 		foreach(lst, slink->oper)
 		{
-			List	   *rside = lnext(((Expr *) lfirst(lst))->args);
+			Oper	   *oper = (Oper *) lfirst(lst);
+			Node	   *lefthand = nth(i, slink->lefthand);
 			TargetEntry *te = nth(i, plan->targetlist);
+			/* need a var node just to pass to new_param()... */
 			Var		   *var = makeVar(0, 0, te->resdom->restype,
 									  te->resdom->restypmod, 0);
 			Param	   *prm = makeNode(Param);
+			Operator	tup;
+			Form_pg_operator opform;
+			Node	   *left,
+					   *right;
 
 			prm->paramkind = PARAM_EXEC;
-			prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);
+			prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
 			prm->paramtype = var->vartype;
-			lfirst(rside) = prm;
+
+			Assert(IsA(oper, Oper));
+			tup = get_operator_tuple(oper->opno);
+			Assert(HeapTupleIsValid(tup));
+			opform = (Form_pg_operator) GETSTRUCT(tup);
+			/* Note: we use make_operand in case runtime type conversion
+			 * function calls must be inserted for this operator!
+			 */
+			left = make_operand("", lefthand,
+								exprType(lefthand), opform->oprleft);
+			right = make_operand("", (Node *) prm,
+								 prm->paramtype, opform->oprright);
+			newoper = lappend(newoper,
+							  make_opclause(oper,
+											(Var *) left,
+											(Var *) right));
 			node->setParam = lappendi(node->setParam, prm->paramid);
 			pfree(var);
 			i++;
 		}
+		slink->oper = newoper;
+		slink->lefthand = NIL;
 		PlannerInitPlan = lappend(PlannerInitPlan, node);
 		if (i > 1)
-			result = (Node *) ((slink->useor) ? make_orclause(slink->oper) :
-							   make_andclause(slink->oper));
+			result = (Node *) ((slink->useor) ? make_orclause(newoper) :
+							   make_andclause(newoper));
 		else
-			result = (Node *) lfirst(slink->oper);
+			result = (Node *) lfirst(newoper);
 	}
 	else if (node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK)
 	{
@@ -201,7 +237,7 @@ _make_subplan(SubLink *slink)
 		Param	   *prm = makeNode(Param);
 
 		prm->paramkind = PARAM_EXEC;
-		prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);
+		prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
 		prm->paramtype = var->vartype;
 		node->setParam = lappendi(node->setParam, prm->paramid);
 		pfree(var);
@@ -213,16 +249,15 @@ _make_subplan(SubLink *slink)
 		/* make expression of SUBPLAN type */
 		Expr	   *expr = makeNode(Expr);
 		List	   *args = NIL;
+		List	   *newoper = NIL;
 		int			i = 0;
 
-		expr->typeOid = BOOLOID;
+		expr->typeOid = BOOLOID; /* bogus, but we don't really care */
 		expr->opType = SUBPLAN_EXPR;
 		expr->oper = (Node *) node;
 
 		/*
-		 * Make expr->args from parParam. Left sides of sublink Oper-s are
-		 * handled by optimizer directly... Also, transform right side of
-		 * sublink Oper-s into Const.
+		 * Make expr->args from parParam.
 		 */
 		foreach(lst, node->parParam)
 		{
@@ -236,23 +271,55 @@ _make_subplan(SubLink *slink)
 			var->varlevelsup = 0;
 			args = lappend(args, var);
 		}
+		expr->args = args;
+		/*
+		 * Convert oper list of Opers into a list of Exprs, using
+		 * lefthand arguments and Consts representing inside results.
+		 */
 		foreach(lst, slink->oper)
 		{
-			List	   *rside = lnext(((Expr *) lfirst(lst))->args);
+			Oper	   *oper = (Oper *) lfirst(lst);
+			Node	   *lefthand = nth(i, slink->lefthand);
 			TargetEntry *te = nth(i, plan->targetlist);
-			Const	   *con = makeConst(te->resdom->restype,
-										0, 0, true, 0, 0, 0);
-
-			lfirst(rside) = con;
+			Const	   *con;
+			Operator	tup;
+			Form_pg_operator opform;
+			Node	   *left,
+					   *right;
+
+			/*
+			 * XXX really ought to fill in constlen and constbyval correctly,
+			 * but right now ExecEvalExpr won't look at them...
+			 */
+			con = makeConst(te->resdom->restype, 0, 0, true, 0, 0, 0);
+
+			Assert(IsA(oper, Oper));
+			tup = get_operator_tuple(oper->opno);
+			Assert(HeapTupleIsValid(tup));
+			opform = (Form_pg_operator) GETSTRUCT(tup);
+			/* Note: we use make_operand in case runtime type conversion
+			 * function calls must be inserted for this operator!
+			 */
+			left = make_operand("", lefthand,
+								exprType(lefthand), opform->oprleft);
+			right = make_operand("", (Node *) con,
+								 con->consttype, opform->oprright);
+			newoper = lappend(newoper,
+							  make_opclause(oper,
+											(Var *) left,
+											(Var *) right));
 			i++;
 		}
-		expr->args = args;
+		slink->oper = newoper;
+		slink->lefthand = NIL;
 		result = (Node *) expr;
 	}
 
 	return result;
 }
 
+/* this oughta be merged with LispUnioni */
+
 static List *
 set_unioni(List *l1, List *l2)
 {
@@ -264,6 +331,11 @@ set_unioni(List *l1, List *l2)
 	return nconc(l1, set_differencei(l2, l1));
 }
 
+/*
+ * finalize_primnode: build lists of subplans and params appearing
+ * in the given expression tree.
+ */
+
 typedef struct finalize_primnode_results {
 	List	*subplans;			/* List of subplans found in expr */
 	List	*paramids;			/* List of PARAM_EXEC paramids found */
@@ -315,165 +387,83 @@ finalize_primnode_walker(Node *node,
 				! intMember(paramid, results->paramids))
 				results->paramids = lconsi(paramid, results->paramids);
 		}
-		/* XXX We do NOT allow expression_tree_walker to examine the args
-		 * passed to the subplan.  Is that correct???  It's what the
-		 * old code did, but it seems mighty bogus...  tgl 7/14/99
-		 */
-		return false;			/* don't recurse into subplan args */
+		/* fall through to recurse into subplan args */
 	}
 	return expression_tree_walker(node, finalize_primnode_walker,
 								  (void *) results);
 }
 
-/* Replace correlation vars (uplevel vars) with Params. */
-
-/* XXX should replace this with use of a generalized tree rebuilder,
- * designed along the same lines as expression_tree_walker.
- * Not done yet.
+/*
+ * Replace correlation vars (uplevel vars) with Params.
  */
+
+static Node *replace_correlation_vars_mutator(Node *node, void *context);
+
 Node *
 SS_replace_correlation_vars(Node *expr)
 {
-	if (expr == NULL)
-		return NULL;
-	if (IsA(expr, Var))
-	{
-		if (((Var *) expr)->varlevelsup > 0)
-			expr = (Node *) _replace_var((Var *) expr);
-	}
-	else if (single_node(expr))
-		return expr;
-	else if (IsA(expr, List))
-	{
-		List	   *le;
-
-		foreach(le, (List *) expr)
-			lfirst(le) = SS_replace_correlation_vars((Node *) lfirst(le));
-	}
-	else if (IsA(expr, Expr))
-	{
-		/* XXX do we need to do anything special with subplans? */
-		((Expr *) expr)->args = (List *)
-			SS_replace_correlation_vars((Node *) ((Expr *) expr)->args);
-	}
-	else if (IsA(expr, Aggref))
-		((Aggref *) expr)->target = SS_replace_correlation_vars(((Aggref *) expr)->target);
-	else if (IsA(expr, Iter))
-		((Iter *) expr)->iterexpr = SS_replace_correlation_vars(((Iter *) expr)->iterexpr);
-	else if (IsA(expr, ArrayRef))
-	{
-		((ArrayRef *) expr)->refupperindexpr = (List *)
-			SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->refupperindexpr);
-		((ArrayRef *) expr)->reflowerindexpr = (List *)
-			SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->reflowerindexpr);
-		((ArrayRef *) expr)->refexpr = SS_replace_correlation_vars(((ArrayRef *) expr)->refexpr);
-		((ArrayRef *) expr)->refassgnexpr = SS_replace_correlation_vars(((ArrayRef *) expr)->refassgnexpr);
-	}
-	else if (IsA(expr, CaseExpr))
-	{
-		CaseExpr   *caseexpr = (CaseExpr *) expr;
-		List	   *le;
+	/* No setup needed for tree walk, so away we go */
+	return replace_correlation_vars_mutator(expr, NULL);
+}
 
-		foreach(le, caseexpr->args)
-		{
-			CaseWhen   *when = (CaseWhen *) lfirst(le);
-			Assert(IsA(when, CaseWhen));
-			when->expr = SS_replace_correlation_vars(when->expr);
-			when->result = SS_replace_correlation_vars(when->result);
-		}
-		/* caseexpr->arg should be null, but we'll check it anyway */
-		caseexpr->arg = SS_replace_correlation_vars(caseexpr->arg);
-		caseexpr->defresult = SS_replace_correlation_vars(caseexpr->defresult);
-	}
-	else if (IsA(expr, TargetEntry))
-		((TargetEntry *) expr)->expr = SS_replace_correlation_vars(((TargetEntry *) expr)->expr);
-	else if (IsA(expr, SubLink))
+static Node *
+replace_correlation_vars_mutator(Node *node, void *context)
+{
+	if (node == NULL)
+		return NULL;
+	if (IsA(node, Var))
 	{
-		List	   *le;
-
-		foreach(le, ((SubLink *) expr)->oper)	/* left sides only */
-		{
-			List	   *oparg = ((Expr *) lfirst(le))->args;
-
-			lfirst(oparg) = (List *)
-				SS_replace_correlation_vars((Node *) lfirst(oparg));
-		}
-		((SubLink *) expr)->lefthand = (List *)
-			SS_replace_correlation_vars((Node *) ((SubLink *) expr)->lefthand);
+		if (((Var *) node)->varlevelsup > 0)
+			return (Node *) replace_var((Var *) node);
 	}
-	else
-		elog(ERROR, "SS_replace_correlation_vars: can't handle node %d",
-			 nodeTag(expr));
-
-	return expr;
+	return expression_tree_mutator(node,
+								   replace_correlation_vars_mutator,
+								   context);
 }
 
-/* Replace sublinks by subplans in the given expression */
-
-/* XXX should replace this with use of a generalized tree rebuilder,
- * designed along the same lines as expression_tree_walker.
- * Not done yet.
+/*
+ * Expand SubLinks to SubPlans in the given expression.
  */
+
+static Node *process_sublinks_mutator(Node *node, void *context);
+
 Node *
 SS_process_sublinks(Node *expr)
 {
-	if (expr == NULL)
+	/* No setup needed for tree walk, so away we go */
+    return process_sublinks_mutator(expr, NULL);
+}
+
+static Node *
+process_sublinks_mutator(Node *node, void *context)
+{
+	if (node == NULL)
 		return NULL;
-	if (IsA(expr, SubLink))
-	{
-		expr = _make_subplan((SubLink *) expr);
-	}
-	else if (single_node(expr))
-		return expr;
-	else if (IsA(expr, List))
+	if (IsA(node, SubLink))
 	{
-		List	   *le;
+		SubLink	   *sublink = (SubLink *) node;
 
-		foreach(le, (List *) expr)
-			lfirst(le) = SS_process_sublinks((Node *) lfirst(le));
-	}
-	else if (IsA(expr, Expr))
-	{
-		/* We should never see a subplan node here, since this is the
-		 * routine that makes 'em in the first place.  No need to check.
+		/* First, scan the lefthand-side expressions.
+		 * This is a tad klugy since we modify the input SubLink node,
+		 * but that should be OK (make_subplan does it too!)
 		 */
-		((Expr *) expr)->args = (List *)
-			SS_process_sublinks((Node *) ((Expr *) expr)->args);
-	}
-	else if (IsA(expr, Aggref))
-		((Aggref *) expr)->target = SS_process_sublinks(((Aggref *) expr)->target);
-	else if (IsA(expr, Iter))
-		((Iter *) expr)->iterexpr = SS_process_sublinks(((Iter *) expr)->iterexpr);
-	else if (IsA(expr, ArrayRef))
-	{
-		((ArrayRef *) expr)->refupperindexpr = (List *)
-			SS_process_sublinks((Node *) ((ArrayRef *) expr)->refupperindexpr);
-		((ArrayRef *) expr)->reflowerindexpr = (List *)
-			SS_process_sublinks((Node *) ((ArrayRef *) expr)->reflowerindexpr);
-		((ArrayRef *) expr)->refexpr = SS_process_sublinks(((ArrayRef *) expr)->refexpr);
-		((ArrayRef *) expr)->refassgnexpr = SS_process_sublinks(((ArrayRef *) expr)->refassgnexpr);
-	}
-	else if (IsA(expr, CaseExpr))
-	{
-		CaseExpr   *caseexpr = (CaseExpr *) expr;
-		List	   *le;
-
-		foreach(le, caseexpr->args)
-		{
-			CaseWhen   *when = (CaseWhen *) lfirst(le);
-			Assert(IsA(when, CaseWhen));
-			when->expr = SS_process_sublinks(when->expr);
-			when->result = SS_process_sublinks(when->result);
-		}
-		/* caseexpr->arg should be null, but we'll check it anyway */
-		caseexpr->arg = SS_process_sublinks(caseexpr->arg);
-		caseexpr->defresult = SS_process_sublinks(caseexpr->defresult);
+		sublink->lefthand = (List *)
+			process_sublinks_mutator((Node *) sublink->lefthand, context);
+		/* Now build the SubPlan node and make the expr to return */
+		return make_subplan(sublink);
 	}
-	else
-		elog(ERROR, "SS_process_sublinks: can't handle node %d",
-			 nodeTag(expr));
+	/*
+	 * Note that we will never see a SubPlan expression in the input
+	 * (since this is the very routine that creates 'em to begin with).
+	 * So the code in expression_tree_mutator() that might do
+	 * inappropriate things with SubPlans or SubLinks will not be
+	 * exercised.
+	 */
+	Assert(! is_subplan(node));
 
-	return expr;
+	return expression_tree_mutator(node,
+								   process_sublinks_mutator,
+								   context);
 }
 
 List *
@@ -585,7 +575,9 @@ SS_finalize_plan(Plan *plan)
 	return results.paramids;
 }
 
-/* Construct a list of all subplans found within the given node tree */
+/*
+ * Construct a list of all subplans found within the given node tree.
+ */
 
 static bool SS_pull_subplan_walker(Node *node, List **listptr);
 
@@ -606,8 +598,7 @@ SS_pull_subplan_walker(Node *node, List **listptr)
 	if (is_subplan(node))
 	{
 		*listptr = lappend(*listptr, ((Expr *) node)->oper);
-		/* XXX original code did not examine args to subplan, is this right? */
-		return false;
+		/* fall through to check args to subplan */
 	}
 	return expression_tree_walker(node, SS_pull_subplan_walker,
 								  (void *) listptr);
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index fbb5a98e83db1501a7f779c863010f061a60c3ea..2d960b5cf03ac21cb9b284b062101f262ae0120d 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.48 1999/08/22 20:14:53 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.49 1999/08/25 23:21:41 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -817,8 +817,8 @@ CommuteClause(Expr *clause)
  * the args and slink->oper lists (which belong to the outer plan), but it
  * will *not* visit the inner plan, since that's typically what expression
  * tree walkers want.  A walker that wants to visit the subplan can force
- * appropriate behavior by recognizing subplan nodes and doing the right
- * thing.
+ * appropriate behavior by recognizing subplan expression nodes and doing
+ * the right thing.
  *
  * Bare SubLink nodes (without a SUBPLAN_EXPR) are handled by recursing into
  * the "lefthand" argument list only.  (A bare SubLink should be seen only if
@@ -854,26 +854,18 @@ expression_tree_walker(Node *node, bool (*walker) (), void *context)
 		case T_Expr:
 			{
 				Expr   *expr = (Expr *) node;
+
 				if (expr->opType == SUBPLAN_EXPR)
 				{
-					/* examine args list (params to be passed to subplan) */
-					if (expression_tree_walker((Node *) expr->args,
-											   walker, context))
-						return true;
-					/* examine oper list as well */
-					if (expression_tree_walker(
-						(Node *) ((SubPlan *) expr->oper)->sublink->oper,
-						walker, context))
-						return true;
-					/* but not the subplan itself */
-				}
-				else
-				{
-					/* for other Expr node types, just examine args list */
-					if (expression_tree_walker((Node *) expr->args,
-											   walker, context))
+					/* 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:
@@ -918,11 +910,20 @@ expression_tree_walker(Node *node, bool (*walker) (), void *context)
 			}
 			break;
 		case T_SubLink:
-			/* A "bare" SubLink (note we will not come here if we found
-			 * a SUBPLAN_EXPR node above it).  Examine the lefthand side,
-			 * but not the oper list nor the subquery.
-			 */
-			return walker(((SubLink *) node)->lefthand, context);
+			{
+				SubLink   *sublink = (SubLink *) node;
+
+				/* If the SubLink has already been processed by subselect.c,
+				 * it will have lefthand=NIL, and we only need to look at
+				 * the oper list.  Otherwise we only need to look at lefthand
+				 * (the Oper nodes in the oper list are deemed uninteresting).
+				 */
+				if (sublink->lefthand)
+					return walker((Node *) sublink->lefthand, context);
+				else
+					return walker((Node *) sublink->oper, context);
+			}
+			break;
 		case T_List:
 			foreach(temp, (List *) node)
 			{
@@ -988,8 +989,8 @@ expression_tree_walker(Node *node, bool (*walker) (), void *context)
  * the args and slink->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 nodes and doing the
- * right thing.
+ * 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
  * the "lefthand" argument list only.  (A bare SubLink should be seen only if
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 0ecee29f52d8b7ed989a5a1546f21692cd28d5af..a2280a745112cd06b693dab1e6288da8ca60952d 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -7,12 +7,14 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.56 1999/08/05 02:33:53 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.57 1999/08/25 23:21:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
+
+#include "catalog/pg_operator.h"
 #include "nodes/makefuncs.h"
 #include "nodes/params.h"
 #include "nodes/relation.h"
@@ -22,6 +24,7 @@
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_func.h"
+#include "parser/parse_oper.h"
 #include "parser/parse_relation.h"
 #include "parser/parse_target.h"
 #include "utils/builtins.h"
@@ -209,7 +212,15 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 					elog(ERROR, "parser: bad query in subselect");
 				sublink->subselect = (Node *) qtree;
 
-				if (sublink->subLinkType != EXISTS_SUBLINK)
+				if (sublink->subLinkType == EXISTS_SUBLINK)
+				{
+					/* EXISTS needs no lefthand or combining operator.
+					 * These fields should be NIL already, but make sure.
+					 */
+					sublink->lefthand = NIL;
+					sublink->oper = NIL;
+				}
+				else
 				{
 					char	   *op = lfirst(sublink->oper);
 					List	   *left_list = sublink->lefthand;
@@ -236,27 +247,39 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 					{
 						TargetEntry *tent = (TargetEntry *) lfirst(right_list);
 						Node	   *lexpr;
-						Expr	   *op_expr;
+						Operator	optup;
+						Form_pg_operator opform;
+						Oper	   *newop;
 
-						if (! tent->resdom->resjunk)
-						{
-							if (left_list == NIL)
-								elog(ERROR, "parser: Subselect has too many fields.");
-							lexpr = lfirst(left_list);
-							left_list = lnext(left_list);
-							op_expr = make_op(op, lexpr, tent->expr);
-							if (op_expr->typeOid != BOOLOID &&
-								sublink->subLinkType != EXPR_SUBLINK)
-								elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);
-							sublink->oper = lappend(sublink->oper, op_expr);
-						}
 						right_list = lnext(right_list);
+						if (tent->resdom->resjunk)
+							continue;
+
+						if (left_list == NIL)
+							elog(ERROR, "parser: Subselect has too many fields.");
+						lexpr = lfirst(left_list);
+						left_list = lnext(left_list);
+
+						optup = oper(op,
+									 exprType(lexpr),
+									 exprType(tent->expr),
+									 FALSE);
+						opform = (Form_pg_operator) GETSTRUCT(optup);
+
+						if (opform->oprresult != BOOLOID &&
+							sublink->subLinkType != EXPR_SUBLINK)
+							elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);
+
+						newop = makeOper(oprid(optup),/* opno */
+										 InvalidOid, /* opid */
+										 opform->oprresult,
+										 0,
+										 NULL);
+						sublink->oper = lappend(sublink->oper, newop);
 					}
 					if (left_list != NIL)
 						elog(ERROR, "parser: Subselect has too few fields.");
 				}
-				else
-					sublink->oper = NIL;
 				result = (Node *) expr;
 				break;
 			}
@@ -565,10 +588,13 @@ exprType(Node *expr)
 
 				if (sublink->subLinkType == EXPR_SUBLINK)
 				{
-					/* return the result type of the combining operator */
-					Expr	   *op_expr = (Expr *) lfirst(sublink->oper);
+					/* return the result type of the combining operator;
+					 * should only be one...
+					 */
+					Oper	   *op = (Oper *) lfirst(sublink->oper);
 
-					type = op_expr->typeOid;
+					Assert(IsA(op, Oper));
+					type = op->opresulttype;
 				}
 				else
 				{
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 88bef2237aa65724fa88d91c11aedb10626e9982..0fa7fd72d43681bfef5a290d7f857c40f8577ab8 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -6,19 +6,23 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.54 1999/07/17 20:17:37 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.55 1999/08/25 23:21:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/heapam.h"
+#include "catalog/pg_operator.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
+#include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/prep.h"
 #include "parser/analyze.h"
+#include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "parser/parse_oper.h"
 #include "parser/parse_target.h"
 #include "parser/parse_type.h"
 #include "parser/parsetree.h"
@@ -642,9 +646,6 @@ modifyAggrefUplevel(Node *node)
 				modifyAggrefUplevel(
 									(Node *) (sub->lefthand));
 
-				modifyAggrefUplevel(
-									(Node *) (sub->oper));
-
 				modifyAggrefUplevel(
 									(Node *) (sub->subselect));
 			}
@@ -816,12 +817,6 @@ modifyAggrefChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int subl
 										   new_index,
 										   sublevels_up);
 
-				modifyAggrefChangeVarnodes(
-										   (Node **) (&(sub->oper)),
-										   rt_index,
-										   new_index,
-										   sublevels_up);
-
 				modifyAggrefChangeVarnodes(
 										   (Node **) (&(sub->subselect)),
 										   rt_index,
@@ -989,6 +984,7 @@ modifyAggrefDropQual(Node **nodePtr, Node *orignode, Expr *expr)
 				SubLink    *sub = (SubLink *) node;
 				SubLink    *osub = (SubLink *) orignode;
 
+				/* what about the lefthand? */
 				modifyAggrefDropQual(
 									 (Node **) (&(sub->subselect)),
 									 (Node *) (osub->subselect),
@@ -1046,19 +1042,21 @@ modifyAggrefMakeSublink(Expr *origexp, Query *parsetree)
 		if (nodeTag(nth(1, exp->args)) == T_Aggref)
 			elog(ERROR, "rewrite: comparision of 2 aggregate columns not supported");
 		else
-			elog(ERROR, "rewrite: aggregate column of view must be at rigth side in qual");
+			elog(ERROR, "rewrite: aggregate column of view must be at right side in qual");
 	}
 
 	aggref = (Aggref *) nth(1, exp->args);
 	target = (Var *) (aggref->target);
+	/* XXX bogus --- agg's target might not be a Var! */
 	rte = (RangeTblEntry *) nth(target->varno - 1, parsetree->rtable);
+
 	tle = makeNode(TargetEntry);
 	resdom = makeNode(Resdom);
 
-	aggref->usenulls = TRUE;
+	aggref->usenulls = TRUE;	/* XXX safe for all aggs?? */
 
 	resdom->resno = 1;
-	resdom->restype = ((Oper *) (exp->oper))->opresulttype;
+	resdom->restype = aggref->aggtype;
 	resdom->restypmod = -1;
 	resdom->resname = pstrdup("<noname>");
 	resdom->reskey = 0;
@@ -1074,9 +1072,8 @@ modifyAggrefMakeSublink(Expr *origexp, Query *parsetree)
 	sublink = makeNode(SubLink);
 	sublink->subLinkType = EXPR_SUBLINK;
 	sublink->useor = FALSE;
-	sublink->lefthand = lappend(NIL, copyObject(lfirst(exp->args)));
-	sublink->oper = lappend(NIL, copyObject(exp));
-	sublink->subselect = NULL;
+	sublink->lefthand = lcons(lfirst(exp->args), NIL);
+	sublink->oper = lcons(exp->oper, NIL);
 
 	subquery = makeNode(Query);
 	sublink->subselect = (Node *) subquery;
@@ -1105,8 +1102,6 @@ modifyAggrefMakeSublink(Expr *origexp, Query *parsetree)
 
 	modifyAggrefChangeVarnodes((Node **) &(sublink->lefthand), target->varno,
 							   1, target->varlevelsup);
-	modifyAggrefChangeVarnodes((Node **) &(sublink->oper), target->varno,
-							   1, target->varlevelsup);
 	modifyAggrefChangeVarnodes((Node **) &(sublink->subselect), target->varno,
 							   1, target->varlevelsup);
 
@@ -1249,6 +1244,7 @@ modifyAggrefQual(Node **nodePtr, Query *parsetree)
 			{
 				SubLink    *sub = (SubLink *) node;
 
+				/* lefthand ??? */
 				modifyAggrefQual(
 								 (Node **) (&(sub->subselect)),
 								 (Query *) (sub->subselect));
@@ -1318,9 +1314,6 @@ checkQueryHasSubLink_walker(Node *node, void *context)
 		return false;
 	if (IsA(node, SubLink))
 		return true;			/* abort the tree traversal and return true */
-	/* Note: we assume the tree has not yet been rewritten by subselect.c,
-	 * therefore we will find bare SubLink nodes and not SUBPLAN nodes.
-	 */
 	return expression_tree_walker(node, checkQueryHasSubLink_walker, context);
 }
 
@@ -1654,8 +1647,6 @@ apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, in
 		case T_SubLink:
 			{
 				SubLink    *sub = (SubLink *) node;
-				List	   *tmp_lefthand,
-						   *tmp_oper;
 
 				apply_RIR_view(
 							   (Node **) (&(sub->lefthand)),
@@ -1672,14 +1663,6 @@ apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, in
 							   tlist,
 							   modified,
 							   sublevels_up + 1);
-
-				tmp_lefthand = sub->lefthand;
-				foreach(tmp_oper, sub->oper)
-				{
-					lfirst(((Expr *) lfirst(tmp_oper))->args) =
-						lfirst(tmp_lefthand);
-					tmp_lefthand = lnext(tmp_lefthand);
-				}
 			}
 			break;
 
@@ -3014,31 +2997,47 @@ Except_Intersect_Rewrite(Query *parsetree)
 			 * of the targetlist must be (IN) or must not be (NOT IN) the
 			 * subselect
 			 */
+			n->lefthand = NIL;
 			foreach(elist, intersect_node->targetList)
 			{
-				Node	   *expr = lfirst(elist);
-				TargetEntry *tent = (TargetEntry *) expr;
+				TargetEntry *tent = (TargetEntry *) lfirst(elist);
 
 				n->lefthand = lappend(n->lefthand, tent->expr);
 			}
 
 			/*
-			 * The first arguments of oper also have to be created for the
-			 * sublink (they are the same as the lefthand side!)
+			 * Also prepare the list of Opers that must be used for the
+			 * comparisons (they depend on the specific datatypes involved!)
 			 */
 			left_expr = n->lefthand;
 			right_expr = ((Query *) (n->subselect))->targetList;
+			n->oper = NIL;
 
 			foreach(elist, left_expr)
 			{
 				Node	   *lexpr = lfirst(elist);
-				Node	   *rexpr = lfirst(right_expr);
-				TargetEntry *tent = (TargetEntry *) rexpr;
-				Expr	   *op_expr;
+				TargetEntry *tent = (TargetEntry *) lfirst(right_expr);
+				Operator	optup;
+				Form_pg_operator opform;
+				Oper	   *newop;
+
+				optup = oper(op,
+							 exprType(lexpr),
+							 exprType(tent->expr),
+							 FALSE);
+				opform = (Form_pg_operator) GETSTRUCT(optup);
+
+				if (opform->oprresult != BOOLOID)
+					elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);
+
+				newop = makeOper(oprid(optup),/* opno */
+								 InvalidOid, /* opid */
+								 opform->oprresult,
+								 0,
+								 NULL);
 
-				op_expr = make_op(op, lexpr, tent->expr);
+				n->oper = lappend(n->oper, newop);
 
-				n->oper = lappend(n->oper, op_expr);
 				right_expr = lnext(right_expr);
 			}
 
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index f88e936412ac352e7fb412c2b9ac85691aee18d4..16b31eae84d0f97c186687bd640989cc453c49f3 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.39 1999/08/21 03:49:13 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.40 1999/08/25 23:21:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -137,13 +137,7 @@ OffsetVarNodes(Node *node, int offset, int sublevels_up)
 		case T_SubLink:
 			{
 				SubLink    *sub = (SubLink *) node;
-				List	   *tmp_oper,
-						   *tmp_lefthand;
 
-				/*
-				 * We also have to adapt the variables used in
-				 * sub->lefthand and sub->oper
-				 */
 				OffsetVarNodes(
 							   (Node *) (sub->lefthand),
 							   offset,
@@ -153,20 +147,6 @@ OffsetVarNodes(Node *node, int offset, int sublevels_up)
 							   (Node *) (sub->subselect),
 							   offset,
 							   sublevels_up + 1);
-
-				/*
-				 * Make sure the first argument of sub->oper points to the
-				 * same var as sub->lefthand does otherwise we will run
-				 * into troubles using aggregates (aggno will not be set
-				 * correctly)
-				 */
-				tmp_lefthand = sub->lefthand;
-				foreach(tmp_oper, sub->oper)
-				{
-					lfirst(((Expr *) lfirst(tmp_oper))->args) =
-						lfirst(tmp_lefthand);
-					tmp_lefthand = lnext(tmp_lefthand);
-				}
 			}
 			break;
 
@@ -357,8 +337,6 @@ ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
 		case T_SubLink:
 			{
 				SubLink    *sub = (SubLink *) node;
-				List	   *tmp_oper,
-						   *tmp_lefthand;
 
 				ChangeVarNodes(
 							   (Node *) (sub->lefthand),
@@ -371,20 +349,6 @@ ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
 							   rt_index,
 							   new_index,
 							   sublevels_up + 1);
-
-				/*
-				 * Make sure the first argument of sub->oper points to the
-				 * same var as sub->lefthand does otherwise we will run
-				 * into troubles using aggregates (aggno will not be set
-				 * correctly)
-				 */
-				tmp_lefthand = sub->lefthand;
-				foreach(tmp_oper, sub->oper)
-				{
-					lfirst(((Expr *) lfirst(tmp_oper))->args) =
-						lfirst(tmp_lefthand);
-					tmp_lefthand = lnext(tmp_lefthand);
-				}
 			}
 			break;
 
@@ -732,6 +696,7 @@ ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
 				SubLink    *sublink = (SubLink *) node;
 				Query	   *query = (Query *) sublink->subselect;
 
+				/* XXX what about lefthand?  What about rest of subquery? */
 				ResolveNew(info, targetlist, (Node **) &(query->qual), sublevels_up + 1);
 			}
 			break;
@@ -888,6 +853,7 @@ nodeHandleRIRAttributeRule(Node **nodePtr,
 				SubLink    *sublink = (SubLink *) node;
 				Query	   *query = (Query *) sublink->subselect;
 
+				/* XXX what about lefthand?  What about rest of subquery? */
 				nodeHandleRIRAttributeRule((Node **) &(query->qual), rtable, targetlist,
 									rt_index, attr_num, modified, badsql,
 										   sublevels_up + 1);
@@ -1062,9 +1028,6 @@ nodeHandleViewRule(Node **nodePtr,
 			{
 				SubLink    *sublink = (SubLink *) node;
 				Query	   *query = (Query *) sublink->subselect;
-				List	   *tmp_lefthand,
-						   *tmp_oper;
-
 
 				nodeHandleViewRule((Node **) &(query->qual), rtable, targetlist,
 								   rt_index, modified, sublevels_up + 1);
@@ -1078,30 +1041,10 @@ nodeHandleViewRule(Node **nodePtr,
 
 				/*
 				 * We also have to adapt the variables used in
-				 * sublink->lefthand and sublink->oper
+				 * sublink->lefthand
 				 */
 				nodeHandleViewRule((Node **) &(sublink->lefthand), rtable,
 						   targetlist, rt_index, modified, sublevels_up);
-
-				/*
-				 * Make sure the first argument of sublink->oper points to
-				 * the same var as sublink->lefthand does otherwise we
-				 * will run into troubles using aggregates (aggno will not
-				 * be set correctly
-				 */
-				pfree(lfirst(((Expr *) lfirst(sublink->oper))->args));
-				lfirst(((Expr *) lfirst(sublink->oper))->args) =
-					lfirst(sublink->lefthand);
-
-
-				/* INTERSECT want's this - Jan */
-
-				/*
-				 * tmp_lefthand = sublink->lefthand; foreach(tmp_oper,
-				 * sublink->oper) { lfirst(((Expr *)
-				 * lfirst(tmp_oper))->args) = lfirst(tmp_lefthand);
-				 * tmp_lefthand = lnext(tmp_lefthand); }
-				 */
 			}
 			break;
 		default:
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 008402e26f311473aaa545e10309258872e15761..ea7950ec5020ff072491c706c22719c49697bf17 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
  *			  out of it's tuple
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.22 1999/08/21 03:48:53 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.23 1999/08/25 23:21:35 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -1586,7 +1586,7 @@ get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
 {
 	SubLink    *sublink = (SubLink *) node;
 	Query	   *query = (Query *) (sublink->subselect);
-	Expr	   *expr;
+	Oper	   *oper;
 	List	   *l;
 	char	   *sep;
 	char		buf[BUFSIZE];
@@ -1620,20 +1620,20 @@ get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
 			break;
 
 		case ANY_SUBLINK:
-			expr = (Expr *) lfirst(sublink->oper);
-			strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
+			oper = (Oper *) lfirst(sublink->oper);
+			strcat(buf, get_opname(oper->opno));
 			strcat(buf, " ANY ");
 			break;
 
 		case ALL_SUBLINK:
-			expr = (Expr *) lfirst(sublink->oper);
-			strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
+			oper = (Oper *) lfirst(sublink->oper);
+			strcat(buf, get_opname(oper->opno));
 			strcat(buf, " ALL ");
 			break;
 
 		case EXPR_SUBLINK:
-			expr = (Expr *) lfirst(sublink->oper);
-			strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
+			oper = (Oper *) lfirst(sublink->oper);
+			strcat(buf, get_opname(oper->opno));
 			strcat(buf, " ");
 			break;
 
@@ -1766,6 +1766,7 @@ check_if_rte_used(int rt_index, Node *node, int sup)
 
 				if (check_if_rte_used(rt_index, (Node *) (query->qual), sup + 1))
 					return TRUE;
+				/* why aren't we looking at query->targetlist, havingQual? */
 
 				if (check_if_rte_used(rt_index, (Node *) (sublink->lefthand), sup))
 					return TRUE;
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 10e51e40268eed36463e7e0edd453d888c7c19eb..e2ef42218fc5b967c6a064f4d9813c66541fcd70 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: primnodes.h,v 1.35 1999/08/22 20:15:00 tgl Exp $
+ * $Id: primnodes.h,v 1.36 1999/08/25 23:21:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -319,10 +319,36 @@ typedef struct Aggref
 /* ----------------
  * SubLink
  *		subLinkType		- EXISTS, ALL, ANY, EXPR
- *		useor			- TRUE for <>
- *		lefthand		- list of Var/Const nodes on the left
+ *		useor			- TRUE for <> (combine op results with "or" not "and")
+ *		lefthand		- list of outer-query expressions on the left
  *		oper			- list of Oper nodes
  *		subselect		- subselect as Query* or parsetree
+ *
+ * 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 one-element list containing the string
+ *    name of the operator.
+ * 2. The parser's expression transformation transforms lefthand normally,
+ *    and replaces oper with a list of Oper 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
+ *    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 or Const nodes.
+ *    The lefthand field is set to NIL, since its expressions are now in
+ *    the Expr list.  This representation is passed to the executor.
+ *
+ * Planner routines that might see either representation 2 or 3 can tell
+ * the difference by checking whether lefthand is NIL or not.  Also,
+ * representation 2 appears in a "bare" SubLink, while representation 3 is
+ * found in SubLinks that are children of SubPlan nodes.
+ *
+ * In an EXISTS SubLink, both lefthand and oper are unused and are always NIL.
  * ----------------
  */
 typedef enum SubLinkType