diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 217bfc54471cd97df0dc61cacb6cbe45774a32cf..ba412332058f79af0ae60ce02ff5d4b578eb4076 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.86 1999/07/17 20:17:05 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.87 1999/07/24 23:21:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1317,7 +1317,6 @@ _copyRestrictInfo(RestrictInfo *from)
 	Node_Copy(from, newnode, clause);
 
 	newnode->selectivity = from->selectivity;
-	newnode->notclause = from->notclause;
 
 	Node_Copy(from, newnode, indexids);
 	Node_Copy(from, newnode, mergejoinorder);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 9f16875f343fc94cfeb5f589b5eac11a65907699..5560deaea53a5569099118f9a120ab7cf8efc1da 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.43 1999/07/17 20:17:05 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.44 1999/07/24 23:21:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -305,8 +305,6 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
 		return false;
 	if (a->selectivity != b->selectivity)
 		return false;
-	if (a->notclause != b->notclause)
-		return false;
 #ifdef EqualMergeOrderExists
 	if (!EqualMergeOrder(a->mergejoinorder, b->mergejoinorder))
 		return false;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 23c10fed5ed75071bfd554a891495a283de9c90c..4272bf04cc5208e6e0b6d5858d18a5618761c850 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: outfuncs.c,v 1.90 1999/07/18 19:02:49 tgl Exp $
+ *	$Id: outfuncs.c,v 1.91 1999/07/24 23:21:07 tgl Exp $
  *
  * NOTES
  *	  Every (plan) node in POSTGRES has an associated "out" routine which
@@ -1110,9 +1110,8 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
 	_outNode(str, node->clause);
 
 	appendStringInfo(str,
-					 " :selectivity %f :notclause %s :indexids ",
-					 node->selectivity,
-					 node->notclause ? "true" : "false");
+					 " :selectivity %f :indexids ",
+					 node->selectivity);
 	_outNode(str, node->indexids);
 
 	appendStringInfo(str, " :mergejoinorder ");
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 9d46b7e39da2df8616618e92b13b5a1b4b38d4b6..e16398fb85481b10b9dc20d3d162094bec38133e 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.69 1999/07/17 20:17:08 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.70 1999/07/24 23:21:08 tgl Exp $
  *
  * NOTES
  *	  Most of the read functions for plan nodes are tested. (In fact, they
@@ -1856,14 +1856,6 @@ _readRestrictInfo()
 
 	local_node->selectivity = atof(token);
 
-	token = lsptok(NULL, &length);		/* get :notclause */
-	token = lsptok(NULL, &length);		/* now read it */
-
-	if (!strncmp(token, "true", 4))
-		local_node->notclause = true;
-	else
-		local_node->notclause = false;
-
 	token = lsptok(NULL, &length);		/* get :indexids */
 	local_node->indexids = nodeRead(true);		/* now read it */
 
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 220b3cd0471e6be40392614f495fa1ea4ebf0edd..373d982c497825a705595b5c63a205bb04caab81 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.50 1999/07/17 20:17:11 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.51 1999/07/24 23:21:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -86,8 +86,8 @@ make_one_rel(Query *root, List *rels)
  * set_base_rel_pathlist
  *	  Finds all paths available for scanning each relation entry in
  *	  'rels'.  Sequential scan and any available indices are considered
- *	  if possible(indices are not considered for lower nesting levels).
- *	  All unique paths are attached to the relation's 'pathlist' field.
+ *	  if possible (indices are not considered for lower nesting levels).
+ *	  All useful paths are attached to the relation's 'pathlist' field.
  *
  *	  MODIFIES: rels
  */
@@ -98,21 +98,32 @@ set_base_rel_pathlist(Query *root, List *rels)
 
 	foreach(temp, rels)
 	{
+		RelOptInfo *rel = (RelOptInfo *) lfirst(temp);
+		List	   *indices = find_relation_indices(root, rel);
 		List	   *sequential_scan_list;
 		List	   *rel_index_scan_list;
 		List	   *or_index_scan_list;
-		RelOptInfo *rel = (RelOptInfo *) lfirst(temp);
 
 		sequential_scan_list = lcons(create_seqscan_path(rel), NIL);
 
 		rel_index_scan_list = create_index_paths(root,
 												 rel,
-										find_relation_indices(root, rel),
+												 indices,
 												 rel->restrictinfo,
 												 rel->joininfo);
 
-		or_index_scan_list = create_or_index_paths(root, rel, rel->restrictinfo);
+		/* Note: create_or_index_paths depends on create_index_paths
+		 * to have marked OR restriction clauses with relevant indices;
+		 * this is why it doesn't need to be given the full list of indices.
+		 */
 
+		or_index_scan_list = create_or_index_paths(root, rel,
+												   rel->restrictinfo);
+
+		/* add_pathlist will discard any paths that are dominated by
+		 * another available path, keeping only those paths that are
+		 * superior along at least one dimension of cost or sortedness.
+		 */
 		rel->pathlist = add_pathlist(rel,
 									 sequential_scan_list,
 									 nconc(rel_index_scan_list,
@@ -128,7 +139,6 @@ set_base_rel_pathlist(Query *root, List *rels)
 		rel->size = compute_rel_size(rel);
 		rel->width = compute_rel_width(rel);
 	}
-	return;
 }
 
 /*
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index df0b4aabb4c5df4f14bd0b28a0736139a5f52e22..00d3780a352d5827cc19c65d986a4ad7cecee57b 100644
--- a/src/backend/optimizer/path/clausesel.c
+++ b/src/backend/optimizer/path/clausesel.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.23 1999/07/16 04:59:14 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.24 1999/07/24 23:21:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,32 +23,26 @@
 #include "utils/lsyscache.h"
 
 
-static Cost compute_selec(Query *root, List *clauses, List *or_selectivities);
-
 /****************************************************************************
  *		ROUTINES TO SET CLAUSE SELECTIVITIES
  ****************************************************************************/
 
 /*
  * set_clause_selectivities -
- *	  Sets the selectivity field for each of clause in 'restrictinfo-list'
- *	  to 'new-selectivity'.  If the selectivity has already been set, reset
- *	  it only if the new one is better.
- *
- * Returns nothing of interest.
- *
+ *	  Sets the selectivity field for each clause in 'restrictinfo-list'
+ *	  to 'new-selectivity'.  If the selectivity has already been set,
+ *	  change it only if the new one is better.
  */
 void
 set_clause_selectivities(List *restrictinfo_list, Cost new_selectivity)
 {
-	List	   *temp;
-	RestrictInfo *clausenode;
-	Cost		cost_clause;
+	List	   *rlist;
 
-	foreach(temp, restrictinfo_list)
+	foreach(rlist, restrictinfo_list)
 	{
-		clausenode = (RestrictInfo *) lfirst(temp);
-		cost_clause = clausenode->selectivity;
+		RestrictInfo *clausenode = (RestrictInfo *) lfirst(rlist);
+		Cost		cost_clause = clausenode->selectivity;
+
 		if (cost_clause <= 0 || new_selectivity < cost_clause)
 			clausenode->selectivity = new_selectivity;
 	}
@@ -63,18 +57,12 @@ set_clause_selectivities(List *restrictinfo_list, Cost new_selectivity)
 Cost
 product_selec(List *restrictinfo_list)
 {
-	Cost		result = 1.0;
+	Cost		result = (Cost) 1.0;
+	List	   *rlist;
 
-	if (restrictinfo_list != NIL)
+	foreach(rlist, restrictinfo_list)
 	{
-		List	   *xclausenode = NIL;
-		Cost		temp;
-
-		foreach(xclausenode, restrictinfo_list)
-		{
-			temp = ((RestrictInfo *) lfirst(xclausenode))->selectivity;
-			result = result * temp;
-		}
+		result *= ((RestrictInfo *) lfirst(rlist))->selectivity;
 	}
 	return result;
 }
@@ -84,19 +72,16 @@ product_selec(List *restrictinfo_list)
  *	  Scans through clauses on each relation and assigns a selectivity to
  *	  those clauses that haven't been assigned a selectivity by an index.
  *
- * Returns nothing of interest.
- * MODIFIES: selectivities of the various rel's restrictinfo
- *		  slots.
+ * MODIFIES: selectivities of the various rel's restrictinfo slots.
  */
 void
 set_rest_relselec(Query *root, List *rel_list)
 {
-	RelOptInfo *rel;
 	List	   *x;
 
 	foreach(x, rel_list)
 	{
-		rel = (RelOptInfo *) lfirst(x);
+		RelOptInfo *rel = (RelOptInfo *) lfirst(x);
 		set_rest_selec(root, rel->restrictinfo);
 	}
 }
@@ -105,31 +90,20 @@ set_rest_relselec(Query *root, List *rel_list)
  * set_rest_selec -
  *	  Sets the selectivity fields for those clauses within a single
  *	  relation's 'restrictinfo-list' that haven't already been set.
- *
- * Returns nothing of interest.
- *
  */
 void
 set_rest_selec(Query *root, List *restrictinfo_list)
 {
-	List	   *temp = NIL;
-	RestrictInfo *clausenode = (RestrictInfo *) NULL;
-	Cost		cost_clause;
+	List	   *rlist;
 
-	foreach(temp, restrictinfo_list)
+	foreach(rlist, restrictinfo_list)
 	{
-		clausenode = (RestrictInfo *) lfirst(temp);
-		cost_clause = clausenode->selectivity;
+		RestrictInfo *clause = (RestrictInfo *) lfirst(rlist);
 
-		/*
-		 * Check to see if the selectivity of this clause or any 'or'
-		 * subclauses (if any) haven't been set yet.
-		 */
-		if (cost_clause <= 0 || valid_or_clause(clausenode))
+		if (clause->selectivity <= 0)
 		{
-			clausenode->selectivity = compute_clause_selec(root,
-											 (Node *) clausenode->clause,
-									 lcons(makeFloat(cost_clause), NIL));
+			clause->selectivity =
+				compute_clause_selec(root, (Node *) clause->clause);
 		}
 	}
 }
@@ -140,89 +114,29 @@ set_rest_selec(Query *root, List *restrictinfo_list)
 
 /*
  * compute_clause_selec -
- *	  Given a clause, this routine will compute the selectivity of the
- *	  clause by calling 'compute_selec' with the appropriate parameters
- *	  and possibly use that return value to compute the real selectivity
- *	  of a clause.
- *
- * 'or-selectivities' are selectivities that have already been assigned
- *		to subclauses of an 'or' clause.
- *
- * Returns a flonum corresponding to the clause selectivity.
- *
- */
-Cost
-compute_clause_selec(Query *root, Node *clause, List *or_selectivities)
-{
-	if (is_opclause(clause))
-		return compute_selec(root, lcons(clause, NIL), or_selectivities);
-	else if (not_clause(clause))
-	{
-
-		/*
-		 * 'not' gets "1.0 - selectivity-of-inner-clause".
-		 */
-		return (1.000000 - compute_selec(root,
-								 lcons(get_notclausearg((Expr *) clause),
-									   NIL),
-										 or_selectivities));
-	}
-	else if (or_clause(clause))
-	{
-
-		/*
-		 * Both 'or' and 'and' clauses are evaluated as described in
-		 * (compute_selec).
-		 */
-		return compute_selec(root, ((Expr *) clause)->args, or_selectivities);
-	}
-	else
-		return compute_selec(root, lcons(clause, NIL), or_selectivities);
-}
-
-/*
- * compute_selec -
  *	  Computes the selectivity of a clause.
- *
- *	  If there is more than one clause in the argument 'clauses', then the
- *	  desired selectivity is that of an 'or' clause.  Selectivities for an
- *	  'or' clause such as (OR a b) are computed by finding the selectivity
- *	  of a (s1) and b (s2) and computing s1+s2 - s1*s2.
- *
- *	  In addition, if the clause is an 'or' clause, individual selectivities
- *	  may have already been assigned by indices to subclauses.	These values
- *	  are contained in the list 'or-selectivities'.
- *
- * Returns the clause selectivity as a flonum.
- *
  */
-static Cost
-compute_selec(Query *root, List *clauses, List *or_selectivities)
+Cost
+compute_clause_selec(Query *root, Node *clause)
 {
-	Cost		s1 = 0;
-	List	   *clause = lfirst(clauses);
+	Cost		s1 = 1.0;		/* default for any unhandled clause type */
 
 	if (clause == NULL)
-		s1 = 1.0;
-	else if (IsA(clause, Param))
-	{
-		/* XXX How're we handling this before?? -ay */
-		s1 = 1.0;
-	}
-	else if (IsA(clause, Const))
-		s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0;
-	else if (IsA(clause, Var))
+		return s1;
+	if (IsA(clause, Var))
 	{
-		Oid			relid = getrelid(((Var *) clause)->varno,
-									 root->rtable);
-
 		/*
 		 * we have a bool Var.	This is exactly equivalent to the clause:
 		 * reln.attribute = 't' so we compute the selectivity as if that
 		 * is what we have. The magic #define constants are a hack.  I
 		 * didn't want to have to do system cache look ups to find out all
 		 * of that info.
+		 *
+		 * XXX why are we using varno and varoattno?  Seems like it should
+		 * be varno/varattno or varnoold/varoattno, not mix & match...
 		 */
+		Oid			relid = getrelid(((Var *) clause)->varno,
+									 root->rtable);
 
 		s1 = restriction_selectivity(F_EQSEL,
 									 BooleanEqualOperator,
@@ -231,134 +145,141 @@ compute_selec(Query *root, List *clauses, List *or_selectivities)
 									 "t",
 									 _SELEC_CONSTANT_RIGHT_);
 	}
-	else if (or_selectivities)
+	else if (IsA(clause, Param))
 	{
-		/* If s1 has already been assigned by an index, use that value. */
-		List	   *this_sel = lfirst(or_selectivities);
-
-		s1 = floatVal(this_sel);
+		/* XXX any way to do better? */
+		s1 = 1.0;
 	}
-	else if (is_funcclause((Node *) clause))
+	else if (IsA(clause, Const))
+	{
+		/* bool constant is pretty easy... */
+		s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0;
+	}
+	else if (not_clause(clause))
+	{
+		/* inverse of the selectivity of the underlying clause */
+		s1 = 1.0 - compute_clause_selec(root,
+										(Node *) get_notclausearg((Expr *) clause));
+	}
+	else if (and_clause(clause))
+	{
+		/* Use the product of the selectivities of the subclauses.
+		 * XXX this is probably too optimistic, since the subclauses
+		 * are very likely not independent...
+		 */
+		List   *arg;
+		s1 = 1.0;
+		foreach(arg, ((Expr *) clause)->args)
+		{
+			Cost		s2 = compute_clause_selec(root, (Node *) lfirst(arg));
+			s1 = s1 * s2;
+		}
+	}
+	else if (or_clause(clause))
+	{
+		/* Selectivities for an 'or' clause are computed as s1+s2 - s1*s2
+		 * to account for the probable overlap of selected tuple sets.
+		 * XXX is this too conservative?
+		 */
+		List   *arg;
+		s1 = 0.0;
+		foreach(arg, ((Expr *) clause)->args)
+		{
+			Cost		s2 = compute_clause_selec(root, (Node *) lfirst(arg));
+			s1 = s1 + s2 - s1 * s2;
+		}
+	}
+	else if (is_funcclause(clause))
 	{
-		/* this isn't an Oper, it's a Func!! */
-
 		/*
 		 * This is not an operator, so we guess at the selectivity. THIS
 		 * IS A HACK TO GET V4 OUT THE DOOR.  FUNCS SHOULD BE ABLE TO HAVE
 		 * SELECTIVITIES THEMSELVES.	   -- JMH 7/9/92
 		 */
-		s1 = 0.1;
+		s1 = (Cost) 0.3333333;
 	}
-	else if (not_clause((Node *) clause))
+	else if (is_subplan(clause))
 	{
-		/* negate this baby */
-		return 1 - compute_selec(root, ((Expr *) clause)->args, or_selectivities);
-	}
-	else if (is_subplan((Node *) clause))
-	{
-
 		/*
 		 * Just for the moment! FIX ME! - vadim 02/04/98
 		 */
 		s1 = 1.0;
 	}
-	else if (NumRelids((Node *) clause) == 1)
+	else if (is_opclause(clause))
 	{
-
-		/*
-		 * ...otherwise, calculate s1 from 'clauses'. The clause is not a
-		 * join clause, since there is only one relid in the clause.  The
-		 * clause selectivity will be based on the operator selectivity
-		 * and operand values.
-		 */
-		Oid			opno = ((Oper *) ((Expr *) clause)->oper)->opno;
-		RegProcedure oprrest = get_oprrest(opno);
-		Oid			relid;
-		int			relidx;
-		AttrNumber	attno;
-		Datum		constval;
-		int			flag;
-
-		get_relattval((Node *) clause, &relidx, &attno, &constval, &flag);
-		relid = getrelid(relidx, root->rtable);
-
-		/*
-		 * if the oprrest procedure is missing for whatever reason, use a
-		 * selectivity of 0.5
-		 */
-		if (!oprrest)
-			s1 = (Cost) (0.5);
-		else if (attno == InvalidAttrNumber)
+		if (NumRelids(clause) == 1)
 		{
+			/* The clause is not a join clause, since there is only one
+			 * relid in the clause.  The clause selectivity will be based on
+			 * the operator selectivity and operand values.
+			 */
+			Oid			opno = ((Oper *) ((Expr *) clause)->oper)->opno;
+			RegProcedure oprrest = get_oprrest(opno);
+			Oid			relid;
+			int			relidx;
+			AttrNumber	attno;
+			Datum		constval;
+			int			flag;
+
+			get_relattval(clause, &relidx, &attno, &constval, &flag);
+			relid = getrelid(relidx, root->rtable);
 
 			/*
-			 * attno can be Invalid if the clause had a function in it,
-			 * i.e.   WHERE myFunc(f) = 10
+			 * if the oprrest procedure is missing for whatever reason, use a
+			 * selectivity of 0.5
 			 */
-			/* this should be FIXED somehow to use function selectivity */
-			s1 = (Cost) (0.5);
+			if (!oprrest)
+				s1 = (Cost) 0.5;
+			else if (attno == InvalidAttrNumber)
+			{
+				/*
+				 * attno can be Invalid if the clause had a function in it,
+				 * i.e.   WHERE myFunc(f) = 10
+				 */
+				/* this should be FIXED somehow to use function selectivity */
+				s1 = (Cost) (0.5);
+			}
+			else
+				s1 = (Cost) restriction_selectivity(oprrest,
+													opno,
+													relid,
+													attno,
+													(char *) constval,
+													flag);
 		}
 		else
-			s1 = (Cost) restriction_selectivity(oprrest,
-												opno,
-												relid,
-												attno,
-												(char *) constval,
-												flag);
-
-	}
-	else
-	{
-
-		/*
-		 * The clause must be a join clause.  The clause selectivity will
-		 * be based on the relations to be scanned and the attributes they
-		 * are to be joined on.
-		 */
-		Oid			opno = ((Oper *) ((Expr *) clause)->oper)->opno;
-		RegProcedure oprjoin = get_oprjoin(opno);
-		int			relid1,
-					relid2;
-		AttrNumber	attno1,
-					attno2;
+		{
+			/*
+			 * The clause must be a join clause.  The clause selectivity will
+			 * be based on the relations to be scanned and the attributes they
+			 * are to be joined on.
+			 */
+			Oid			opno = ((Oper *) ((Expr *) clause)->oper)->opno;
+			RegProcedure oprjoin = get_oprjoin(opno);
+			int			relid1,
+						relid2;
+			AttrNumber	attno1,
+						attno2;
 
-		get_rels_atts((Node *) clause, &relid1, &attno1, &relid2, &attno2);
-		relid1 = getrelid(relid1, root->rtable);
-		relid2 = getrelid(relid2, root->rtable);
+			get_rels_atts(clause, &relid1, &attno1, &relid2, &attno2);
+			relid1 = getrelid(relid1, root->rtable);
+			relid2 = getrelid(relid2, root->rtable);
 
-		/*
-		 * if the oprjoin procedure is missing for whatever reason, use a
-		 * selectivity of 0.5
-		 */
-		if (!oprjoin)
-			s1 = (Cost) (0.5);
-		else
-			s1 = (Cost) join_selectivity(oprjoin,
-										 opno,
-										 relid1,
-										 attno1,
-										 relid2,
-										 attno2);
+			/*
+			 * if the oprjoin procedure is missing for whatever reason, use a
+			 * selectivity of 0.5
+			 */
+			if (!oprjoin)
+				s1 = (Cost) (0.5);
+			else
+				s1 = (Cost) join_selectivity(oprjoin,
+											 opno,
+											 relid1,
+											 attno1,
+											 relid2,
+											 attno2);
+		}
 	}
 
-	/*
-	 * A null clause list eliminates no tuples, so return a selectivity of
-	 * 1.0.  If there is only one clause, the selectivity is not that of
-	 * an 'or' clause, but rather that of the single clause.
-	 */
-
-	if (lnext(clauses) == NIL)
-		return s1;
-	else
-	{
-		/* Compute selectivity of the 'or'ed subclauses. */
-		/* Added check for taking lnext(NIL).  -- JMH 3/9/92 */
-		Cost		s2;
-
-		if (or_selectivities != NIL)
-			s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities));
-		else
-			s2 = compute_selec(root, lnext(clauses), NIL);
-		return s1 + s2 - s1 * s2;
-	}
+	return s1;
 }
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index c539b1f90517475e7eca05f127cabcf2df520ec1..d2da20a5b347a20e8c06d952a651a04a7fe0e781 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.62 1999/07/23 03:34:49 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.63 1999/07/24 23:21:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -109,12 +109,25 @@ create_index_paths(Query *root,
 				continue;
 
 		/*
-		 * 1. Try matching the index against subclauses of an 'or' clause.
-		 * The fields of the restrictinfo nodes are marked with lists of
-		 * the matching indices.  No paths are actually created.  We
-		 * currently only look to match the first key.	We don't find
-		 * multi-key index cases where an AND matches the first key, and
-		 * the OR matches the second key.
+		 * 1. Try matching the index against subclauses of restriction 'or'
+		 * clauses (ie, 'or' clauses that reference only this relation).
+		 * The restrictinfo nodes for the 'or' clauses are marked with lists
+		 * of the matching indices.  No paths are actually created now;
+		 * that will be done in orindxpath.c after all indexes for the rel
+		 * have been examined.  (We need to do it that way because we can
+		 * potentially use a different index for each subclause of an 'or',
+		 * so we can't build a path for an 'or' clause until all indexes have
+		 * been matched against it.)
+		 *
+		 * We currently only look to match the first key of each index against
+		 * 'or' subclauses.  There are cases where a later key of a multi-key
+		 * index could be used (if other top-level clauses match earlier keys
+		 * of the index), but our poor brains are hurting already...
+		 *
+		 * We don't even think about special handling of 'or' clauses that
+		 * involve more than one relation, since they can't be processed by
+		 * a single indexscan path anyway.  Currently, cnfify() is certain
+		 * to have restructured any such toplevel 'or' clauses anyway.
 		 */
 		match_index_orclauses(rel,
 							  index,
@@ -123,7 +136,7 @@ create_index_paths(Query *root,
 							  restrictinfo_list);
 
 		/*
-		 * 2. If the keys of this index match any of the available
+		 * 2. If the keys of this index match any of the available non-'or'
 		 * restriction clauses, then create a path using those clauses
 		 * as indexquals.
 		 */
@@ -179,11 +192,14 @@ create_index_paths(Query *root,
 /*
  * match_index_orclauses
  *	  Attempt to match an index against subclauses within 'or' clauses.
- *	  If the index does match, then the clause is marked with information
- *	  about the index.
+ *	  Each subclause that does match is marked with the index's node.
  *
- *	  Essentially, this adds 'index' to the list of indices in the
- *	  RestrictInfo field of each of the clauses which it matches.
+ *	  Essentially, this adds 'index' to the list of subclause indices in
+ *	  the RestrictInfo field of each of the 'or' clauses where it matches.
+ *	  NOTE: we can use storage in the RestrictInfo for this purpose because
+ *	  this processing is only done on single-relation restriction clauses.
+ *	  Therefore, we will never have indexes for more than one relation
+ *	  mentioned in the same RestrictInfo node's list.
  *
  * 'rel' is the node of the relation on which the index is defined.
  * 'index' is the index node.
@@ -204,12 +220,11 @@ match_index_orclauses(RelOptInfo *rel,
 	{
 		RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i);
 
-		if (valid_or_clause(restrictinfo))
+		if (restriction_is_or_clause(restrictinfo))
 		{
 			/*
-			 * Mark the 'or' clause with a list of indices which match
-			 * each of its subclauses.	We add entries to the existing
-			 * list, if any.
+			 * Add this index to the subclause index list for each
+			 * subclause that it matches.
 			 */
 			restrictinfo->indexids =
 				match_index_orclause(rel, index,
@@ -253,7 +268,9 @@ match_index_orclause(RelOptInfo *rel,
 	List	   *index_list;
 	List	   *clist;
 
-	/* first time through, we create empty list of same length as OR clause */
+	/* first time through, we create list of same length as OR clause,
+	 * containing an empty sublist for each subclause.
+	 */
 	if (!other_matching_indices)
 	{
 		matching_indices = NIL;
@@ -1186,9 +1203,13 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
 		pathnode->path.pathorder->ord.sortop = index->ordering;
 		pathnode->path.pathkeys = NIL;
 
+		/* Note that we are making a pathnode for a single-scan indexscan;
+		 * therefore, both indexid and indexqual should be single-element
+		 * lists.
+		 */
 		pathnode->indexid = index->relids;
 		pathnode->indexkeys = index->indexkeys;
-		pathnode->indexqual = clausegroup;
+		pathnode->indexqual = lcons(get_actual_clauses(clausegroup), NIL);
 
 		pathnode->path.joinid = ((RestrictInfo *) lfirst(clausegroup))->restrictinfojoinid;
 
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c
index ceb8c3eb47f9a899bd6434236684b36c2256eff3..4a511372a53d8deb989a4c44a64fd3c528cdc97b 100644
--- a/src/backend/optimizer/path/orindxpath.c
+++ b/src/backend/optimizer/path/orindxpath.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.28 1999/07/16 04:59:15 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.29 1999/07/24 23:21:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,61 +26,66 @@
 #include "parser/parsetree.h"
 
 
-static void best_or_subclause_indices(Query *root, RelOptInfo *rel, List *subclauses,
-				List *indices, List **indexids, Cost *cost, Cost *selec);
-static void best_or_subclause_index(Query *root, RelOptInfo *rel, Expr *subclause,
-				   List *indices, int *indexid, Cost *cost, Cost *selec);
+static void best_or_subclause_indices(Query *root, RelOptInfo *rel,
+									  List *subclauses, List *indices,
+									  List **indexids,
+									  Cost *cost, Cost *selec);
+static void best_or_subclause_index(Query *root, RelOptInfo *rel,
+									Expr *subclause, List *indices,
+									int *indexid, Cost *cost, Cost *selec);
 
 
 /*
  * create_or_index_paths
  *	  Creates index paths for indices that match 'or' clauses.
+ *	  create_index_paths() must already have been called.
  *
  * 'rel' is the relation entry for which the paths are to be defined on
  * 'clauses' is the list of available restriction clause nodes
  *
- * Returns a list of these index path nodes.
+ * Returns a list of index path nodes.
  *
  */
 List *
 create_or_index_paths(Query *root,
 					  RelOptInfo *rel, List *clauses)
 {
-	List	   *t_list = NIL;
+	List	   *path_list = NIL;
 	List	   *clist;
 
 	foreach(clist, clauses)
 	{
-		RestrictInfo *clausenode = (RestrictInfo *) (lfirst(clist));
+		RestrictInfo *clausenode = (RestrictInfo *) lfirst(clist);
 
 		/*
 		 * Check to see if this clause is an 'or' clause, and, if so,
 		 * whether or not each of the subclauses within the 'or' clause
-		 * has been matched by an index (the 'Index field was set in
-		 * (match_or)  if no index matches a given subclause, one of the
-		 * lists of index nodes returned by (get_index) will be 'nil').
+		 * has been matched by an index.  The information used was
+		 * saved by create_index_paths().
 		 */
-		if (valid_or_clause(clausenode) &&
+		if (restriction_is_or_clause(clausenode) &&
 			clausenode->indexids)
 		{
-			List	   *temp = NIL;
-			List	   *index_list = NIL;
-			bool		index_flag = true;
+			bool		all_indexable = true;
+			List	   *temp;
 
-			index_list = clausenode->indexids;
-			foreach(temp, index_list)
+			foreach(temp, clausenode->indexids)
 			{
-				if (!lfirst(temp))
+				if (lfirst(temp) == NIL)
 				{
-					index_flag = false;
+					all_indexable = false;
 					break;
 				}
 			}
-			/* do they all have indexes? */
-			if (index_flag)
-			{					/* used to be a lisp every function */
+			if (all_indexable)
+			{
+				/*
+				 * OK, build an IndexPath for this OR clause, using the
+				 * best available index for each subclause.
+				 */
 				IndexPath  *pathnode = makeNode(IndexPath);
-				List	   *indexids = NIL;
+				List	   *indexids;
+				List	   *orclause;
 				Cost		cost;
 				Cost		selec;
 
@@ -98,16 +103,35 @@ create_or_index_paths(Query *root,
 				pathnode->path.pathorder->ordtype = SORTOP_ORDER;
 
 				/*
-				 * This is an IndexScan, but it does index lookups based
-				 * on the order of the fields specified in the WHERE
-				 * clause, not in any order, so the sortop is NULL.
+				 * This is an IndexScan, but the overall result will consist
+				 * of tuples extracted in multiple passes (one for each
+				 * subclause of the OR), so the result cannot be claimed
+				 * to have any particular ordering.
 				 */
 				pathnode->path.pathorder->ord.sortop = NULL;
 				pathnode->path.pathkeys = NIL;
 
-				pathnode->indexqual = lcons(clausenode, NIL);
+				/*
+				 * Generate an indexqual list from the OR clause's args.
+				 * We want two levels of sublist: the first is implicit OR
+				 * and the second is implicit AND.  (Currently, we will never
+				 * see a sub-AND-clause because of cnfify(), but someday maybe
+				 * the code below will do something useful...)
+				 */
+				pathnode->indexqual = NIL;
+				foreach(orclause, clausenode->clause->args)
+				{
+					List	*sublist;
+					if (and_clause(lfirst(orclause)))
+						sublist = ((Expr *) lfirst(orclause))->args;
+					else
+						sublist = lcons(lfirst(orclause), NIL);
+					pathnode->indexqual = lappend(pathnode->indexqual,
+												  sublist);
+				}
 				pathnode->indexid = indexids;
 				pathnode->path.path_cost = cost;
+				clausenode->selectivity = (Cost) selec;
 
 				/*
 				 * copy restrictinfo list into path for expensive function
@@ -121,33 +145,28 @@ create_or_index_paths(Query *root,
 				if (XfuncMode != XFUNC_OFF)
 					((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path) pathnode);
 #endif
-				clausenode->selectivity = (Cost) selec;
-				t_list = lappend(t_list, pathnode);
+				path_list = lappend(path_list, pathnode);
 			}
 		}
 	}
 
-	return t_list;
+	return path_list;
 }
 
 /*
  * best_or_subclause_indices
  *	  Determines the best index to be used in conjunction with each subclause
  *	  of an 'or' clause and the cost of scanning a relation using these
- *	  indices.	The cost is the sum of the individual index costs.
+ *	  indices.	The cost is the sum of the individual index costs, since
+ *	  the executor will perform a scan for each subclause of the 'or'.
  *
- * 'rel' is the node of the relation on which the index is defined
+ * 'rel' is the node of the relation on which the indexes are defined
  * 'subclauses' are the subclauses of the 'or' clause
- * 'indices' are those index nodes that matched subclauses of the 'or'
- *		clause
- * 'examined_indexids' is a list of those index ids to be used with
- *		subclauses that have already been examined
- * 'subcost' is the cost of using the indices in 'examined_indexids'
- * 'selec' is a list of all subclauses that have already been examined
- *
- * Returns a list of the indexids, cost, and selectivities of each
- * subclause, e.g., ((i1 i2 i3) cost (s1 s2 s3)), where 'i' is an OID,
- * 'cost' is a flonum, and 's' is a flonum.
+ * 'indices' is a list of sublists of the index nodes that matched each
+ *		subclause of the 'or' clause
+ * '*indexids' gets a list of the best index ID to use for each subclause
+ * '*cost' gets the total cost of the path
+ * '*selec' gets the total selectivity of the path.
  */
 static void
 best_or_subclause_indices(Query *root,
@@ -155,11 +174,12 @@ best_or_subclause_indices(Query *root,
 						  List *subclauses,
 						  List *indices,
 						  List **indexids,		/* return value */
-						  Cost *cost,	/* return value */
-						  Cost *selec)	/* return value */
+						  Cost *cost,			/* return value */
+						  Cost *selec)			/* return value */
 {
 	List	   *slist;
 
+	*indexids = NIL;
 	*selec = (Cost) 0.0;
 	*cost = (Cost) 0.0;
 
@@ -180,8 +200,6 @@ best_or_subclause_indices(Query *root,
 
 		indices = lnext(indices);
 	}
-
-	return;
 }
 
 /*
@@ -193,10 +211,9 @@ best_or_subclause_indices(Query *root,
  * 'rel' is the node of the relation on which the index is defined
  * 'subclause' is the subclause
  * 'indices' is a list of index nodes that match the subclause
- *
- * Returns a list (index_id index_subcost index_selectivity)
- * (a fixnum, a fixnum, and a flonum respectively).
- *
+ * '*retIndexid' gets the ID of the best index
+ * '*retCost' gets the cost of a scan with that index
+ * '*retSelec' gets the selectivity of that scan
  */
 static void
 best_or_subclause_index(Query *root,
@@ -207,49 +224,60 @@ best_or_subclause_index(Query *root,
 						Cost *retCost,	/* return value */
 						Cost *retSelec) /* return value */
 {
-	List	   *ilist;
+	Oid			relid = getrelid(lfirsti(rel->relids),
+								 root->rtable);
+	Oid			opno = ((Oper *) subclause->oper)->opno;
+	AttrNumber	attno = (get_leftop(subclause))->varattno;
+	bool		constant_on_right = non_null((Expr *) get_rightop(subclause));
+	Datum		value;
+	int			flag;
+	List	   *opnos,
+			   *attnos,
+			   *values,
+			   *flags;
 	bool		first_run = true;
+	List	   *ilist;
 
 	/* if we don't match anything, return zeros */
 	*retIndexid = 0;
-	*retCost = 0.0;
-	*retSelec = 0.0;
+	*retCost = (Cost) 0.0;
+	*retSelec = (Cost) 0.0;
+
+	if (constant_on_right)		/* XXX looks pretty bogus ... tgl */
+		value = ((Const *) get_rightop(subclause))->constvalue;
+	else
+		value = NameGetDatum("");
+	if (constant_on_right)
+		flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
+	else
+		flag = _SELEC_CONSTANT_RIGHT_;
+
+	/* prebuild lists since we will pass same list to each index */
+	opnos = lconsi(opno, NIL);
+	attnos = lconsi(attno, NIL);
+	values = lconsi(value, NIL);
+	flags = lconsi(flag, NIL);
 
 	foreach(ilist, indices)
 	{
 		RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
-
-		Datum		value;
-		int			flag = 0;
+		Oid			indexid = (Oid) lfirsti(index->relids);
 		Cost		subcost;
-		AttrNumber	attno = (get_leftop(subclause))->varattno;
-		Oid			opno = ((Oper *) subclause->oper)->opno;
-		bool		constant_on_right = non_null((Expr *) get_rightop(subclause));
 		float		npages,
 					selec;
 
-		if (constant_on_right)
-			value = ((Const *) get_rightop(subclause))->constvalue;
-		else
-			value = NameGetDatum("");
-		if (constant_on_right)
-			flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
-		else
-			flag = _SELEC_CONSTANT_RIGHT_;
-
-		index_selectivity(lfirsti(index->relids),
+		index_selectivity(indexid,
 						  index->classlist,
-						  lconsi(opno, NIL),
-						  getrelid(lfirsti(rel->relids),
-								   root->rtable),
-						  lconsi(attno, NIL),
-						  lconsi(value, NIL),
-						  lconsi(flag, NIL),
+						  opnos,
+						  relid,
+						  attnos,
+						  values,
+						  flags,
 						  1,
 						  &npages,
 						  &selec);
 
-		subcost = cost_index((Oid) lfirsti(index->relids),
+		subcost = cost_index(indexid,
 							 (int) npages,
 							 (Cost) selec,
 							 rel->pages,
@@ -260,12 +288,11 @@ best_or_subclause_index(Query *root,
 
 		if (first_run || subcost < *retCost)
 		{
-			*retIndexid = lfirsti(index->relids);
+			*retIndexid = indexid;
 			*retCost = subcost;
 			*retSelec = selec;
 			first_run = false;
 		}
 	}
 
-	return;
 }
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 1dc0e9a0d5d39273f62b10557dab544b4681f256..0148d4912e198feca8c57c9dfa6470d42f3111ee 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.62 1999/07/17 20:17:13 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.63 1999/07/24 23:21:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -301,54 +301,30 @@ create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
  * create_indexscan_node
  *	  Returns a indexscan node for the base relation scanned by 'best_path'
  *	  with restriction clauses 'scan_clauses' and targetlist 'tlist'.
+ *
+ * If an 'or' clause is to be used with this index, the indxqual field
+ * will contain a list of the 'or' clause arguments, e.g., the
+ * clause(OR a b c) will generate: ((a) (b) (c)).  Otherwise, the
+ * indxqual will simply contain one conjunctive qualification: ((a)).
  */
 static IndexScan *
 create_indexscan_node(IndexPath *best_path,
 					  List *tlist,
 					  List *scan_clauses)
 {
-
-	/*
-	 * Extract the(first if conjunct, only if disjunct) clause from the
-	 * restrictinfo list.
-	 */
-	Expr	   *index_clause = (Expr *) NULL;
-	List	   *indxqual = NIL;
-	List	   *qpqual = NIL;
-	List	   *fixed_indxqual = NIL;
+	List	   *indxqual = best_path->indexqual;
+	List	   *qpqual;
+	List	   *fixed_indxqual;
 	List	   *ixid;
-	IndexScan  *scan_node = (IndexScan *) NULL;
-	bool		lossy = FALSE;
-	HeapTuple	indexTuple;
-	Form_pg_index index;
-
-	/*
-	 * If an 'or' clause is to be used with this index, the indxqual field
-	 * will contain a list of the 'or' clause arguments, e.g., the
-	 * clause(OR a b c) will generate: ((a) (b) (c)).  Otherwise, the
-	 * indxqual will simply contain one conjunctive qualification: ((a)).
-	 */
-	if (best_path->indexqual != NULL)
-		/* added call to fix_opids, JMH 6/23/92 */
-		index_clause = (Expr *)
-			lfirst(fix_opids(get_actual_clauses(best_path->indexqual)));
-
-	if (or_clause((Node *) index_clause))
-	{
-		List	   *temp = NIL;
-
-		foreach(temp, index_clause->args)
-			indxqual = lappend(indxqual, lcons(lfirst(temp), NIL));
-	}
-	else
-	{
-		indxqual = lcons(get_actual_clauses(best_path->indexqual),
-						 NIL);
-	}
+	IndexScan  *scan_node;
+	bool		lossy = false;
 
 	/* check and see if any indices are lossy */
 	foreach(ixid, best_path->indexid)
 	{
+		HeapTuple	indexTuple;
+		Form_pg_index index;
+
 		indexTuple = SearchSysCacheTuple(INDEXRELID,
 										 ObjectIdGetDatum(lfirsti(ixid)),
 										 0, 0, 0);
@@ -356,34 +332,70 @@ create_indexscan_node(IndexPath *best_path,
 			elog(ERROR, "create_plan: index %u not found", lfirsti(ixid));
 		index = (Form_pg_index) GETSTRUCT(indexTuple);
 		if (index->indislossy)
-			lossy = TRUE;
+		{
+			lossy = true;
+			break;
+		}
 	}
 
-
 	/*
-	 * The qpqual field contains all restrictions not automatically
+	 * The qpqual list must contain all restrictions not automatically
 	 * handled by the index.  Note that for non-lossy indices, the
 	 * predicates in the indxqual are handled by the index, while for
 	 * lossy indices the indxqual predicates need to be double-checked
 	 * after the index fetches the best-guess tuples.
+	 *
+	 * There should not be any clauses in scan_clauses that duplicate
+	 * expressions checked by the index, but just in case, we will
+	 * get rid of them via set_difference.
 	 */
-	if (or_clause((Node *) index_clause))
+	if (length(indxqual) > 1)
 	{
+		/*
+		 * Build an expression representation of the indexqual, expanding
+		 * the implicit OR and AND semantics of the first- and second-level
+		 * lists.  XXX Is it really necessary to do a deep copy here?
+		 */
+		List	   *orclauses = NIL;
+		List	   *orclause;
+		Expr	   *indxqual_expr;
+
+		foreach(orclause, indxqual)
+		{
+			orclauses = lappend(orclauses,
+								make_ands_explicit((List *) copyObject(lfirst(orclause))));
+		}
+		indxqual_expr = make_orclause(orclauses);
+
+		/* this set_difference is almost certainly a waste of time... */
 		qpqual = set_difference(scan_clauses,
-								lcons(index_clause, NIL));
+								lcons(indxqual_expr, NIL));
 
 		if (lossy)
-			qpqual = lappend(qpqual, (List *) copyObject(index_clause));
+			qpqual = lappend(qpqual, indxqual_expr);
 	}
-	else
+	else if (indxqual != NIL)
 	{
+		/* Here, we can simply treat the first sublist as an independent
+		 * set of qual expressions, since there is no top-level OR behavior.
+		 */
 		qpqual = set_difference(scan_clauses, lfirst(indxqual));
 		if (lossy)
-			qpqual = nconc(qpqual,
-						   (List *) copyObject(lfirst(indxqual)));
+			qpqual = nconc(qpqual, (List *) copyObject(lfirst(indxqual)));
 	}
+	else
+		qpqual = NIL;
+
+	/*
+	 * Fix opids in the completed indxqual.  We don't want to do this sooner
+	 * since it would screw up the set_difference calcs above.  Really,
+	 * this ought to only happen at final exit from the planner...
+	 */
+	indxqual = fix_opids(indxqual);
 
-	fixed_indxqual = (List *) fix_indxqual_references((Node *) indxqual, (Path *) best_path);
+	/* The executor needs a copy with index attrs substituted for table ones */
+	fixed_indxqual = (List *) fix_indxqual_references((Node *) indxqual,
+													  (Path *) best_path);
 
 	scan_node = make_indexscan(tlist,
 							   qpqual,
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 2270a0e4eab4aec684acb7f0172ce43a3dd2e3ab..08ed6a7316341f4e19d4684f052b4bfa118186d4 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.34 1999/07/16 04:59:19 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.35 1999/07/24 23:21:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,12 +25,11 @@
 #include "optimizer/var.h"
 #include "utils/lsyscache.h"
 
-extern int	Quiet;
 
-static void add_restrict_and_join_to_rel(Query *root, List *clause);
+static void add_restrict_and_join_to_rel(Query *root, Node *clause);
 static void add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
 					  Relids join_relids);
-static void add_vars_to_targetlist(Query *root, List *vars, Relids join_relids);
+static void add_vars_to_targetlist(Query *root, List *vars);
 
 static MergeOrder *mergejoinop(Expr *clause);
 static Oid	hashjoinop(Expr *clause);
@@ -129,7 +128,7 @@ add_missing_vars_to_tlist(Query *root, List *tlist)
  *	  relations appearing within clauses.  Creates new relation entries if
  *	  necessary, adding them to *query_relation_list*.
  *
- *	  Returns nothing of interest.
+ * 'clauses': the list of clauses in the cnfify'd query qualification.
  */
 void
 add_restrict_and_join_to_rels(Query *root, List *clauses)
@@ -137,95 +136,71 @@ add_restrict_and_join_to_rels(Query *root, List *clauses)
 	List	   *clause;
 
 	foreach(clause, clauses)
-		add_restrict_and_join_to_rel(root, lfirst(clause));
-	return;
+		add_restrict_and_join_to_rel(root, (Node*) lfirst(clause));
 }
 
 /*
  * add_restrict_and_join_to_rel-
  *	  Add clause information to either the 'RestrictInfo' or 'JoinInfo' field
- *	  of a relation entry(depending on whether or not the clause is a join)
+ *	  of a relation entry (depending on whether or not the clause is a join)
  *	  by creating a new RestrictInfo node and setting appropriate fields
  *	  within the nodes.
- *
- *	  Returns nothing of interest.
  */
 static void
-add_restrict_and_join_to_rel(Query *root, List *clause)
+add_restrict_and_join_to_rel(Query *root, Node *clause)
 {
+	RestrictInfo *restrictinfo = makeNode(RestrictInfo);
 	Relids		relids;
 	List	   *vars;
-	RestrictInfo *restrictinfo = makeNode(RestrictInfo);
-
-	/*
-	 * Retrieve all relids and vars contained within the clause.
-	 */
-	clause_get_relids_vars((Node *) clause, &relids, &vars);
 
 	restrictinfo->clause = (Expr *) clause;
-	restrictinfo->notclause = contains_not((Node *) clause);
-	restrictinfo->selectivity = 0;
 	restrictinfo->indexids = NIL;
 	restrictinfo->mergejoinorder = (MergeOrder *) NULL;
 	restrictinfo->hashjoinoperator = (Oid) 0;
 
+	/*
+	 * The selectivity of the clause must be computed regardless of
+	 * whether it's a restriction or a join clause
+	 */
+	restrictinfo->selectivity = compute_clause_selec(root, clause);
+
+	/*
+	 * Retrieve all relids and vars contained within the clause.
+	 */
+	clause_get_relids_vars(clause, &relids, &vars);
+
 	if (length(relids) == 1)
 	{
-
 		/*
 		 * There is only one relation participating in 'clause', so
-		 * 'clause' must be a restriction clause.
+		 * 'clause' must be a restriction clause for that relation.
 		 */
 		RelOptInfo *rel = get_base_rel(root, lfirsti(relids));
 
-		/*
-		 * The selectivity of the clause must be computed regardless of
-		 * whether it's a restriction or a join clause
-		 */
-		if (is_funcclause((Node *) clause))
-
-			/*
-			 * XXX If we have a func clause set selectivity to 1/3, really
-			 * need a true selectivity function.
-			 */
-			restrictinfo->selectivity = (Cost) 0.3333333;
-		else
-			restrictinfo->selectivity = compute_clause_selec(root, (Node *) clause, NIL);
-
 		rel->restrictinfo = lcons(restrictinfo, rel->restrictinfo);
 	}
 	else
 	{
-
 		/*
 		 * 'clause' is a join clause, since there is more than one atom in
-		 * the relid list.
+		 * the relid list.  Add it to the join lists of all the relevant
+		 * relations.  (If, perchance, 'clause' contains NO vars, then
+		 * nothing will happen...)
 		 */
-		if (is_funcclause((Node *) clause))
-
-			/*
-			 * XXX If we have a func clause set selectivity to 1/3, really
-			 * need a true selectivity function.
-			 */
-			restrictinfo->selectivity = (Cost) 0.3333333;
-		else
-			restrictinfo->selectivity = compute_clause_selec(root, (Node *) clause, NIL);
-
 		add_join_info_to_rels(root, restrictinfo, relids);
-		/* we are going to be doing a join, so add var to targetlist */
-		add_vars_to_targetlist(root, vars, relids);
+		/* we are going to be doing a join, so add vars to targetlists */
+		add_vars_to_targetlist(root, vars);
 	}
 }
 
 /*
  * add_join_info_to_rels
  *	  For every relation participating in a join clause, add 'restrictinfo' to
- *	  the appropriate joininfo node(creating a new one and adding it to the
+ *	  the appropriate joininfo node (creating a new one and adding it to the
  *	  appropriate rel node if necessary).
  *
  * 'restrictinfo' describes the join clause
  * 'join_relids' is the list of relations participating in the join clause
- *
  */
 static void
 add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
@@ -233,7 +208,7 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
 {
 	List	   *join_relid;
 
-	/* For every relid, find the rel, and add the proper join entries */
+	/* For every relid, find the joininfo, and add the proper join entries */
 	foreach(join_relid, join_relids)
 	{
 		JoinInfo   *joininfo;
@@ -247,43 +222,39 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
 				unjoined_relids = lappendi(unjoined_relids, lfirsti(rel));
 		}
 
+		/*
+		 * Find or make the joininfo node for this combination of rels
+		 */
 		joininfo = find_joininfo_node(get_base_rel(root, lfirsti(join_relid)),
 									  unjoined_relids);
+
+		/*
+		 * And add the restrictinfo node to it.  NOTE that each joininfo
+		 * gets its own copy of the restrictinfo node!  (Is this really
+		 * necessary?  Possibly ... later parts of the optimizer destructively
+		 * modify restrict/join clauses...)
+		 */
 		joininfo->jinfo_restrictinfo = lcons(copyObject((void *) restrictinfo),
-										   joininfo->jinfo_restrictinfo);
+											 joininfo->jinfo_restrictinfo);
 	}
 }
 
 /*
  * add_vars_to_targetlist
- *	  For each variable appearing in a clause,
- *	  (1) If a targetlist entry for the variable is not already present in
- *		  the appropriate relation's target list, add one.
- *	  (2) If a targetlist entry is already present, but the var is part of a
- *		  join clause, add the relids of the join relations to the JoinList
- *		  entry of the targetlist entry.
- *
- *	  'vars' is the list of var nodes
- *	  'join_relids' is the list of relids appearing in the join clause
- *		(if this is a join clause)
- *
- *	  Returns nothing.
+ *	  For each variable appearing in a clause, add it to the relation's
+ *	  targetlist if not already present.
  */
 static void
-add_vars_to_targetlist(Query *root, List *vars, Relids join_relids)
+add_vars_to_targetlist(Query *root, List *vars)
 {
-	Var		   *var;
-	List	   *temp = NIL;
-	RelOptInfo *rel = (RelOptInfo *) NULL;
-	TargetEntry *tlistentry;
+	List	   *temp;
 
 	foreach(temp, vars)
 	{
-		var = (Var *) lfirst(temp);
-		rel = get_base_rel(root, var->varno);
-		tlistentry = tlistentry_member(var, rel->targetlist);
-		if (tlistentry == NULL)
-			/* add a new entry */
+		Var		   *var = (Var *) lfirst(temp);
+		RelOptInfo *rel = get_base_rel(root, var->varno);
+
+		if (tlistentry_member(var, rel->targetlist) == NULL)
 			add_var_to_tlist(rel, var);
 	}
 }
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 84db3df008d67f355a11c140475ec4fdfcb38a25..5c9e4175adebff97139e9bf13eeb5393cb3af56a 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.40 1999/07/16 04:59:23 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.41 1999/07/24 23:21:13 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -290,6 +290,21 @@ make_andclause(List *andclauses)
 	return expr;
 }
 
+/*
+ * Sometimes (such as in the result of cnfify), we use lists of expression
+ * nodes with implicit AND semantics.  This function converts back to an
+ * explicit-AND representation.
+ */
+Expr *
+make_ands_explicit(List *andclauses)
+{
+	if (andclauses == NIL)
+		return NULL;
+	else if (length(andclauses) == 1)
+		return (Expr *) lfirst(andclauses);
+	else
+		return make_andclause(andclauses);
+}
 
 /*****************************************************************************
  *		CASE clause functions
@@ -410,38 +425,6 @@ NumRelids(Node *clause)
 	return length(var_list);
 }
 
-/*
- * contains_not
- *
- * Returns t iff the clause is a 'not' clause or if any of the
- * subclauses within an 'or' clause contain 'not's.
- *
- * NOTE that only the top-level AND/OR structure is searched for NOTs;
- * we are not interested in buried substructure.
- */
-bool
-contains_not(Node *clause)
-{
-	if (single_node(clause))
-		return false;
-
-	if (not_clause(clause))
-		return true;
-
-	if (or_clause(clause) || and_clause(clause))
-	{
-		List	   *a;
-
-		foreach(a, ((Expr *) clause)->args)
-		{
-			if (contains_not(lfirst(a)))
-				return true;
-		}
-	}
-
-	return false;
-}
-
 /*
  * is_joinable
  *
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 3c9e0a4dc846fbeb951c88d349b685a9964ac07e..52689d96a4d5184c59627208db77d35910ed7faa 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.46 1999/07/16 04:59:25 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.47 1999/07/24 23:21:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -426,7 +426,8 @@ create_index_path(Query *root,
 		/* each clause gets an equal selectivity */
 		clausesel = pow(selec, 1.0 / (double) length(restriction_clauses));
 
-		pathnode->indexqual = restriction_clauses;
+		pathnode->indexqual = lcons(get_actual_clauses(restriction_clauses),
+									NIL);
 		pathnode->path.path_cost = cost_index(lfirsti(index->relids),
 											  (int) npages,
 											  selec,
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index 12b95a61af37f7456ed21cce7764e9322ca33f47..4dfdf66fcbce676d079e39992c8c8dd0d2a2fbce 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.6 1999/07/16 04:59:27 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.7 1999/07/24 23:21:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,17 +20,15 @@
 #include "optimizer/restrictinfo.h"
 
 /*
- * valid_or_clause
+ * restriction_is_or_clause
  *
- * Returns t iff the restrictinfo node contains a 'normal' 'or' clause.
+ * Returns t iff the restrictinfo node contains an 'or' clause.
  *
  */
 bool
-valid_or_clause(RestrictInfo *restrictinfo)
+restriction_is_or_clause(RestrictInfo *restrictinfo)
 {
 	if (restrictinfo != NULL &&
-		!single_node((Node *) restrictinfo->clause) &&
-		!restrictinfo->notclause &&
 		or_clause((Node *) restrictinfo->clause))
 		return true;
 	else
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index e305870aa7b71242169c2bc80f8b14fd07b31b3c..416cdb0c55b2e80e07edef4eab05f1fdf7196aaa 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: relation.h,v 1.34 1999/07/15 23:03:56 momjian Exp $
+ * $Id: relation.h,v 1.35 1999/07/24 23:21:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -151,6 +151,23 @@ typedef struct Path
 	List	   *loc_restrictinfo;
 } Path;
 
+/*----------
+ * IndexPath represents an index scan.  Although an indexscan can only read
+ * a single relation, it can scan it more than once, potentially using a
+ * different index during each scan.  The result is the union (OR) of all the
+ * tuples matched during any scan.  (The executor is smart enough not to return
+ * the same tuple more than once, even if it is matched in multiple scans.)
+ * 'indexid' is a list of index relation OIDs, one per scan to be performed.
+ * 'indexqual' is a list of index qualifications, also one per scan.
+ * Each entry in 'indexqual' is a sublist of qualification expressions with
+ * implicit AND semantics across the sublist items.  Each one of the sublist
+ * items must be an operator expression of the form (var op something) or
+ * (something op var), where the var is a field the associated index keys on
+ * and the op is a member of the operator class of the index.
+ * NOTE that the semantics of the top-level list in 'indexqual' is OR
+ * combination, while the sublists are implicitly AND combinations!
+ *----------
+ */
 typedef struct IndexPath
 {
 	Path		path;
@@ -205,16 +222,20 @@ typedef struct JoinKey
 } JoinKey;
 
 /*
- * clause info
+ * Restriction clause info.
+ * We create one of these for each AND sub-clause of a restriction condition
+ * (WHERE clause).  Since the restriction clauses are logically ANDed, we
+ * can use any one of them or any subset of them to filter out tuples,
+ * without having to evaluate the rest.  The RestrictInfo node itself stores
+ * data used by the optimizer while choosing the best query plan.
  */
 
 typedef struct RestrictInfo
 {
 	NodeTag		type;
-	Expr	   *clause;			/* should be an OP clause */
-	Cost		selectivity;
-	bool		notclause;
-	List	   *indexids;
+	Expr	   *clause;			/* the represented subclause of WHERE cond */
+	Cost		selectivity;	/* estimated selectivity */
+	List	   *indexids;		/* subclause index IDs if clause is an OR */
 
 	/* mergejoin only */
 	MergeOrder *mergejoinorder;
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index de135ca1d5397481eeca73ad5bcc5148580de9f1..e362b7c64d9eebeca2d19070e7b4f2fe01af1bff 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: clauses.h,v 1.21 1999/07/15 23:03:57 momjian Exp $
+ * $Id: clauses.h,v 1.22 1999/07/24 23:21:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,13 +34,13 @@ extern Expr *get_notclausearg(Expr *notclause);
 
 extern bool and_clause(Node *clause);
 extern Expr *make_andclause(List *andclauses);
+extern Expr *make_ands_explicit(List *andclauses);
 
 extern bool case_clause(Node *clause);
 
 extern List *pull_constant_clauses(List *quals, List **constantQual);
 extern void clause_get_relids_vars(Node *clause, Relids *relids, List **vars);
 extern int	NumRelids(Node *clause);
-extern bool contains_not(Node *clause);
 extern bool is_joinable(Node *clause);
 extern bool qual_clause_p(Node *clause);
 extern void fix_opid(Node *clause);
diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h
index b9fc710370692e76ddc6c7bf4bc965f38e9e0770..1dfe975226228cb6915501c6d690b085dc83969c 100644
--- a/src/include/optimizer/cost.h
+++ b/src/include/optimizer/cost.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: cost.h,v 1.21 1999/07/15 15:21:20 momjian Exp $
+ * $Id: cost.h,v 1.22 1999/07/24 23:21:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,7 +59,6 @@ extern void set_clause_selectivities(List *restrictinfo_list, Cost new_selectivi
 extern Cost product_selec(List *restrictinfo_list);
 extern void set_rest_relselec(Query *root, List *rel_list);
 extern void set_rest_selec(Query *root, List *restrictinfo_list);
-extern Cost compute_clause_selec(Query *root,
-					 Node *clause, List *or_selectivities);
+extern Cost compute_clause_selec(Query *root, Node *clause);
 
 #endif	 /* COST_H */
diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h
index 2f5c4dca20cd8935eaf83fb6edcd85aad8626e5e..7412ca46fa0bf10aa2b1ff16dc49abb823e1bb88 100644
--- a/src/include/optimizer/restrictinfo.h
+++ b/src/include/optimizer/restrictinfo.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: restrictinfo.h,v 1.5 1999/07/15 15:21:23 momjian Exp $
+ * $Id: restrictinfo.h,v 1.6 1999/07/24 23:21:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,7 +15,7 @@
 
 #include "nodes/relation.h"
 
-extern bool valid_or_clause(RestrictInfo *restrictinfo);
+extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
 extern List *get_actual_clauses(List *restrictinfo_list);
 extern void get_relattvals(List *restrictinfo_list, List **attnos,
 			   List **values, List **flags);