diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 08aee2010ef11a28f9823f05afe90a08de257b26..2a0c3d1c5d64b9373f152b343dabae645772e240 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.164 2004/08/29 05:06:43 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.165 2004/10/11 22:56:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -64,10 +64,9 @@ static bool match_join_clause_to_indexcol(RelOptInfo *rel, IndexOptInfo *index,
 							  RestrictInfo *rinfo);
 static Oid indexable_operator(Expr *clause, Oid opclass,
 				   bool indexkey_on_left);
-static bool pred_test(List *predicate_list, List *restrictinfo_list);
+static bool pred_test_recurse_pred(Expr *predicate, List *restrictinfo_list);
 static bool pred_test_restrict_list(Expr *predicate, List *restrictinfo_list);
-static bool pred_test_recurse_clause(Expr *predicate, Node *clause);
-static bool pred_test_recurse_pred(Expr *predicate, Node *clause);
+static bool pred_test_recurse_restrict(Expr *predicate, Node *clause);
 static bool pred_test_simple_clause(Expr *predicate, Node *clause);
 static Relids indexable_outerrelids(RelOptInfo *rel, IndexOptInfo *index);
 static Path *make_innerjoin_index_path(Query *root,
@@ -750,14 +749,13 @@ check_partial_indexes(Query *root, RelOptInfo *rel)
  *	  Recursively checks whether the clauses in restrictinfo_list imply
  *	  that the given predicate is true.
  *
- *	  This routine (together with the routines it calls) iterates over
- *	  ANDs in the predicate first, then reduces the qualification
- *	  clauses down to their constituent terms, and iterates over ORs
- *	  in the predicate last.  This order is important to make the test
- *	  succeed whenever possible (assuming the predicate has been converted
- *	  to CNF format). --Nels, Jan '93
+ *	  This routine (together with the routines it calls) first breaks down
+ *	  the predicate to its constituent AND/OR elements, then similarly
+ *	  breaks down the restriction clauses to AND/OR elements in an effort
+ *	  to prove that each predicate element is implied.  The top-level
+ *	  List structure of each list corresponds to an AND list.
  */
-static bool
+bool
 pred_test(List *predicate_list, List *restrictinfo_list)
 {
 	ListCell   *pred;
@@ -785,10 +783,9 @@ pred_test(List *predicate_list, List *restrictinfo_list)
 	{
 		/*
 		 * if any clause is not implied, the whole predicate is not
-		 * implied.  Note we assume that any sub-ANDs have been flattened
-		 * when the predicate was fed through canonicalize_qual().
+		 * implied.
 		 */
-		if (!pred_test_restrict_list(lfirst(pred), restrictinfo_list))
+		if (!pred_test_recurse_pred(lfirst(pred), restrictinfo_list))
 			return false;
 	}
 	return true;
@@ -796,9 +793,53 @@ pred_test(List *predicate_list, List *restrictinfo_list)
 
 
 /*
- * pred_test_restrict_list
+ * pred_test_recurse_pred
  *	  Does the "predicate inclusion test" for one conjunct of a predicate
- *	  expression.
+ *	  expression.  Here we recursively deal with the possibility that the
+ *	  predicate conjunct is itself an AND or OR structure.
+ */
+static bool
+pred_test_recurse_pred(Expr *predicate, List *restrictinfo_list)
+{
+	List	   *items;
+	ListCell   *item;
+
+	Assert(predicate != NULL);
+	if (or_clause((Node *) predicate))
+	{
+		items = ((BoolExpr *) predicate)->args;
+		foreach(item, items)
+		{
+			/* if any item is implied, the whole predicate is implied */
+			if (pred_test_recurse_pred(lfirst(item), restrictinfo_list))
+				return true;
+		}
+		return false;
+	}
+	else if (and_clause((Node *) predicate))
+	{
+		items = ((BoolExpr *) predicate)->args;
+		foreach(item, items)
+		{
+			/*
+			 * if any item is not implied, the whole predicate is not
+			 * implied
+			 */
+			if (!pred_test_recurse_pred(lfirst(item), restrictinfo_list))
+				return false;
+		}
+		return true;
+	}
+	else
+		return pred_test_restrict_list(predicate, restrictinfo_list);
+}
+
+
+/*
+ * pred_test_restrict_list
+ *	  Does the "predicate inclusion test" for one element of a predicate
+ *	  expression.  Here we take care of the AND semantics of the top-level
+ *	  restrictinfo list.
  */
 static bool
 pred_test_restrict_list(Expr *predicate, List *restrictinfo_list)
@@ -809,9 +850,11 @@ pred_test_restrict_list(Expr *predicate, List *restrictinfo_list)
 	{
 		RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(item);
 
+		Assert(IsA(restrictinfo, RestrictInfo));
+
 		/* if any clause implies the predicate, return true */
-		if (pred_test_recurse_clause(predicate,
-									 (Node *) restrictinfo->clause))
+		if (pred_test_recurse_restrict(predicate,
+									   (Node *) restrictinfo->clause))
 			return true;
 	}
 	return false;
@@ -819,13 +862,13 @@ pred_test_restrict_list(Expr *predicate, List *restrictinfo_list)
 
 
 /*
- * pred_test_recurse_clause
- *	  Does the "predicate inclusion test" for a general restriction-clause
+ * pred_test_recurse_restrict
+ *	  Does the "predicate inclusion test" for one element of a predicate
  *	  expression.  Here we recursively deal with the possibility that the
- *	  restriction clause is itself an AND or OR structure.
+ *	  restriction-list element is itself an AND or OR structure.
  */
 static bool
-pred_test_recurse_clause(Expr *predicate, Node *clause)
+pred_test_recurse_restrict(Expr *predicate, Node *clause)
 {
 	List	   *items;
 	ListCell   *item;
@@ -837,7 +880,7 @@ pred_test_recurse_clause(Expr *predicate, Node *clause)
 		foreach(item, items)
 		{
 			/* if any OR item doesn't imply the predicate, clause doesn't */
-			if (!pred_test_recurse_clause(predicate, lfirst(item)))
+			if (!pred_test_recurse_restrict(predicate, lfirst(item)))
 				return false;
 		}
 		return true;
@@ -851,55 +894,11 @@ pred_test_recurse_clause(Expr *predicate, Node *clause)
 			 * if any AND item implies the predicate, the whole clause
 			 * does
 			 */
-			if (pred_test_recurse_clause(predicate, lfirst(item)))
+			if (pred_test_recurse_restrict(predicate, lfirst(item)))
 				return true;
 		}
 		return false;
 	}
-	else
-		return pred_test_recurse_pred(predicate, clause);
-}
-
-
-/*
- * pred_test_recurse_pred
- *	  Does the "predicate inclusion test" for one conjunct of a predicate
- *	  expression for a simple restriction clause.  Here we recursively deal
- *	  with the possibility that the predicate conjunct is itself an AND or
- *	  OR structure.
- */
-static bool
-pred_test_recurse_pred(Expr *predicate, Node *clause)
-{
-	List	   *items;
-	ListCell   *item;
-
-	Assert(predicate != NULL);
-	if (or_clause((Node *) predicate))
-	{
-		items = ((BoolExpr *) predicate)->args;
-		foreach(item, items)
-		{
-			/* if any item is implied, the whole predicate is implied */
-			if (pred_test_recurse_pred(lfirst(item), clause))
-				return true;
-		}
-		return false;
-	}
-	else if (and_clause((Node *) predicate))
-	{
-		items = ((BoolExpr *) predicate)->args;
-		foreach(item, items)
-		{
-			/*
-			 * if any item is not implied, the whole predicate is not
-			 * implied
-			 */
-			if (!pred_test_recurse_pred(lfirst(item), clause))
-				return false;
-		}
-		return true;
-	}
 	else
 		return pred_test_simple_clause(predicate, clause);
 }
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c
index c2de25aa4c6a39b80bb56bae780af10337a74c99..09c2aa161b620af6b8224825e9fe6df1d32951a9 100644
--- a/src/backend/optimizer/path/orindxpath.c
+++ b/src/backend/optimizer/path/orindxpath.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.62 2004/08/29 05:06:43 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.63 2004/10/11 22:56:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -355,15 +355,42 @@ best_or_subclause_index(Query *root,
 		List	   *indexquals;
 		Path		subclause_path;
 
-		/* Ignore partial indexes that do not match the query */
+		/*
+		 * Ignore partial indexes that do not match the query.  If predOK
+		 * is true then the index's predicate is implied by top-level
+		 * restriction clauses, so we can use it.  However, it might also
+		 * be implied by the current OR subclause (perhaps in conjunction
+		 * with the top-level clauses), in which case we can use it for this
+		 * particular scan.
+		 *
+		 * XXX this code is partially redundant with logic in
+		 * group_clauses_by_indexkey_for_or(); consider refactoring.
+		 */
 		if (index->indpred != NIL && !index->predOK)
-			continue;
+		{
+			List   *subclauserinfos;
+
+			if (and_clause((Node *) subclause))
+				subclauserinfos = list_copy(((BoolExpr *) subclause)->args);
+			else if (IsA(subclause, RestrictInfo))
+				subclauserinfos = list_make1(subclause);
+			else
+				continue;		/* probably can't happen */
+			if (!pred_test(index->indpred,
+						   list_concat(subclauserinfos, 
+									   rel->baserestrictinfo)))
+				continue;
+		}
 
 		/* Collect index clauses usable with this index */
 		indexclauses = group_clauses_by_indexkey_for_or(rel, index, subclause);
 
-		/* Ignore index if it doesn't match the subclause at all */
-		if (indexclauses == NIL)
+		/*
+		 * Ignore index if it doesn't match the subclause at all; except
+		 * that if it's a partial index, consider it anyway, since the
+		 * selectivity of the predicate alone might make the index useful.
+		 */
+		if (indexclauses == NIL && index->indpred == NIL)
 			continue;
 
 		/* Convert clauses to indexquals the executor can handle */
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index b9bfeddaa2ef560a0c50ff5b2f5aee0f8df826d5..845f6557613cc117367b789d978a973c4ddbff36 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.75 2004/08/29 05:06:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.76 2004/10/11 22:57:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,6 +44,7 @@ extern List *group_clauses_by_indexkey_for_or(RelOptInfo *rel,
 extern List *expand_indexqual_conditions(IndexOptInfo *index,
 							List *clausegroups);
 extern void check_partial_indexes(Query *root, RelOptInfo *rel);
+extern bool pred_test(List *predicate_list, List *restrictinfo_list);
 extern List *flatten_clausegroups_list(List *clausegroups);
 extern Expr *make_expr_from_indexclauses(List *indexclauses);