diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 32d03f7..7010076 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2129,6 +2129,7 @@ _outIndexOptInfo(StringInfo str, const IndexOptInfo *node)
 	WRITE_OID_FIELD(relam);
 	/* indexprs is redundant since we print indextlist */
 	WRITE_NODE_FIELD(indpred);
+	WRITE_NODE_FIELD(baserestrictinfo);
 	WRITE_NODE_FIELD(indextlist);
 	WRITE_BOOL_FIELD(predOK);
 	WRITE_BOOL_FIELD(unique);
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index e1a5d33..7f94475 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -334,6 +334,24 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		switch (rel->rtekind)
 		{
 			case RTE_RELATION:
+				/*
+				 * For index scans, some clauses in baserestrictinfo can be
+				 * culled according to index definitions. So we are to
+				 * retrieve baserestrictinfo for indexscans from
+				 * IndexOptInfo. The baserestrictinfo has not been fixed until
+				 * just before here so we initialize it here.
+				 */
+				if (rel->indexlist && rel->baserestrictinfo)
+				{
+					ListCell *lc;
+
+					foreach (lc, rel->indexlist)
+					{
+						IndexOptInfo *index = (IndexOptInfo *) lfirst(lc);
+						index->baserestrictinfo = rel->baserestrictinfo;
+					}
+				}
+
 				if (rte->relkind == RELKIND_FOREIGN_TABLE)
 				{
 					/* Foreign table */
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index b86fc5e..6a6e0c9 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -434,22 +434,26 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count)
 	/*
 	 * Mark the path with the correct row estimate, and identify which quals
 	 * will need to be enforced as qpquals.
+	 *
+	 * Usually, qpquals come from the rel's restriction clauses and
+	 * ppi_clauses.  For partial indexes, we may ignore clauses implied by
+	 * the index predicate.  This reduced subset of restriction clauses was
+	 * already computed in check_partial_indexes() and is available in
+	 * IndexOptInfo, so we simply retrieve it from there.
 	 */
 	if (path->path.param_info)
 	{
 		path->path.rows = path->path.param_info->ppi_rows;
-		/* qpquals come from the rel's restriction clauses and ppi_clauses */
 		qpquals = list_concat(
-					   extract_nonindex_conditions(baserel->baserestrictinfo,
-												   path->indexquals),
+			  extract_nonindex_conditions(path->indexinfo->baserestrictinfo,
+										  path->indexquals),
 			  extract_nonindex_conditions(path->path.param_info->ppi_clauses,
 										  path->indexquals));
 	}
 	else
 	{
 		path->path.rows = baserel->rows;
-		/* qpquals come from just the rel's restriction clauses */
-		qpquals = extract_nonindex_conditions(baserel->baserestrictinfo,
+		qpquals = extract_nonindex_conditions(path->indexinfo->baserestrictinfo,
 											  path->indexquals);
 	}
 
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index b48f5f2..2748ecf 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -30,6 +30,7 @@
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/predtest.h"
+#include "optimizer/prep.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/var.h"
 #include "utils/builtins.h"
@@ -1801,13 +1802,13 @@ check_index_only(RelOptInfo *rel, IndexOptInfo *index)
 	 * Check that all needed attributes of the relation are available from the
 	 * index.
 	 *
-	 * XXX this is overly conservative for partial indexes, since we will
-	 * consider attributes involved in the index predicate as required even
-	 * though the predicate won't need to be checked at runtime.  (The same is
-	 * true for attributes used only in index quals, if we are certain that
-	 * the index is not lossy.)  However, it would be quite expensive to
-	 * determine that accurately at this point, so for now we take the easy
-	 * way out.
+	 * For partial indexes we won't consider attributes involved in clauses
+	 * implied by the index predicate, as those won't be needed at runtime.
+	 *
+	 * XXX Attributes used only in index quals are not needed at runtime
+	 * either, if we are certain that the index is not lossy; however, it
+	 * would be quite expensive to determine that accurately at this point, so
+	 * for now we take the easy way out.
 	 */
 
 	/*
@@ -1817,8 +1818,8 @@ check_index_only(RelOptInfo *rel, IndexOptInfo *index)
 	 */
 	pull_varattnos((Node *) rel->reltarget->exprs, rel->relid, &attrs_used);
 
-	/* Add all the attributes used by restriction clauses. */
-	foreach(lc, rel->baserestrictinfo)
+	/* Add all the attributes used by index restriction clauses. */
+	foreach(lc, index->baserestrictinfo)
 	{
 		RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
 
@@ -2023,7 +2024,7 @@ static void
 match_restriction_clauses_to_index(RelOptInfo *rel, IndexOptInfo *index,
 								   IndexClauseSet *clauseset)
 {
-	match_clauses_to_index(index, rel->baserestrictinfo, clauseset);
+	match_clauses_to_index(index, index->baserestrictinfo, clauseset);
 }
 
 /*
@@ -2743,10 +2744,14 @@ check_partial_indexes(PlannerInfo *root, RelOptInfo *rel)
 														 otherrels,
 														 rel));
 
-	/* Now try to prove each index predicate true */
+	/*
+	 * Now try to prove each index predicate true. We'll also tweak the index
+	 * restrictions to exclude clauses implied by the predicate.
+	 */
 	foreach(lc, rel->indexlist)
 	{
 		IndexOptInfo *index = (IndexOptInfo *) lfirst(lc);
+		ListCell   *lcr;
 
 		if (index->indpred == NIL)
 			continue;			/* ignore non-partial indexes */
@@ -2755,6 +2760,35 @@ check_partial_indexes(PlannerInfo *root, RelOptInfo *rel)
 			continue;			/* don't repeat work if already proven OK */
 
 		index->predOK = predicate_implied_by(index->indpred, clauselist);
+
+		/*
+		 * Update restrictinfo for this index by excluding clauses that are
+		 * implied by the index predicates. We first quickly check if we can
+		 * safely remove clauses.
+		 */
+
+		if (rel->relid == root->parse->resultRelation ||
+			get_plan_rowmark(root->rowMarks, rel->relid) != NULL)
+			continue;
+
+		/*
+		 * We could avoid creating a new baserestrictinfo for the index if it
+		 * will match the one for the relation, but the few cycles saved from
+		 * such an optimization are not worth the code complexity. Just create
+		 * it unconditionally even though the lists may match.
+		 */
+		index->baserestrictinfo = NIL;
+		foreach (lcr, rel->baserestrictinfo)
+		{
+			RestrictInfo *rinfo = (RestrictInfo *) lfirst(lcr);
+
+			/* add to index clauses if initial or not implied */
+			if (contain_mutable_functions((Node *) rinfo->clause) ||
+				!predicate_implied_by(list_make1(rinfo->clause),
+									  index->indpred))
+				index->baserestrictinfo =
+					lappend(index->baserestrictinfo, rinfo);
+		}
 	}
 }
 
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index d159a17..4922e05 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -70,6 +70,7 @@
 
 static Plan *create_plan_recurse(PlannerInfo *root, Path *best_path,
 					int flags);
+static List *get_baserestrictinfo(PlannerInfo *root, Path *best_path);
 static Plan *create_scan_plan(PlannerInfo *root, Path *best_path,
 				 int flags);
 static List *build_path_tlist(PlannerInfo *root, Path *path);
@@ -477,6 +478,27 @@ create_plan_recurse(PlannerInfo *root, Path *best_path, int flags)
 }
 
 /*
+ * get_baserestrictinfo
+ *	 Return the list of restriction clauses for the path.
+ *
+ * For index paths we return the list produced by by check_partial_indexes,
+ * i.e. without clauses implied by the index predicate (if present).
+ */
+static List *
+get_baserestrictinfo(PlannerInfo *root, Path *best_path)
+{
+	switch (best_path->pathtype)
+	{
+		case T_IndexScan:
+		case T_IndexOnlyScan:
+			Assert(IsA(best_path, IndexPath));
+			return ((IndexPath *) best_path)->indexinfo->baserestrictinfo;
+		default:
+			return best_path->parent->baserestrictinfo;
+	}
+}
+
+/*
  * create_scan_plan
  *	 Create a scan plan for the parent relation of 'best_path'.
  */
@@ -492,9 +514,11 @@ create_scan_plan(PlannerInfo *root, Path *best_path, int flags)
 	/*
 	 * Extract the relevant restriction clauses from the parent relation. The
 	 * executor must apply all these restrictions during the scan, except for
-	 * pseudoconstants which we'll take care of below.
+	 * pseudoconstants which we'll take care of below. Some types of paths
+	 * override the baserestrictinfo of the parent relation (e.g., a partial
+	 * index excludes redundant index conditions).
 	 */
-	scan_clauses = rel->baserestrictinfo;
+	scan_clauses = get_baserestrictinfo(root, best_path);
 
 	/*
 	 * If this is a parameterized scan, we also need to enforce all the join
@@ -2400,21 +2424,14 @@ create_indexscan_plan(PlannerInfo *root,
 			continue;			/* simple duplicate */
 		if (is_redundant_derived_clause(rinfo, indexquals))
 			continue;			/* derived from same EquivalenceClass */
-		if (!contain_mutable_functions((Node *) rinfo->clause))
-		{
-			List	   *clausel = list_make1(rinfo->clause);
+		/*
+		 * scan_clauses don't contain clauses implied by index predicate. See
+		 * check_partial_indexes() for detail.
+		 */
+		if (!contain_mutable_functions((Node *) rinfo->clause) &&
+			predicate_implied_by(list_make1(rinfo->clause), indexquals))
+			continue;		/* provably implied by indexquals */
 
-			if (predicate_implied_by(clausel, indexquals))
-				continue;		/* provably implied by indexquals */
-			if (best_path->indexinfo->indpred)
-			{
-				if (baserelid != root->parse->resultRelation &&
-					get_plan_rowmark(root->rowMarks, baserelid) == NULL)
-					if (predicate_implied_by(clausel,
-											 best_path->indexinfo->indpred))
-						continue;		/* implied by index predicate */
-			}
-		}
 		qpqual = lappend(qpqual, rinfo);
 	}
 
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 546067b..b662859 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -331,6 +331,12 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 			 */
 			info->indexprs = RelationGetIndexExpressions(indexRelation);
 			info->indpred = RelationGetIndexPredicate(indexRelation);
+
+			/*
+			 * Index baserestrictinfo cannot be calculated yet; leave it NULL
+			 * for now.
+			 */
+			info->baserestrictinfo = NULL;
 			if (info->indexprs && varno != 1)
 				ChangeVarNodes((Node *) info->indexprs, 1, varno, 0);
 			if (info->indpred && varno != 1)
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index ee7007a..cc0a08f 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -592,9 +592,11 @@ typedef struct IndexOptInfo
 
 	List	   *indexprs;		/* expressions for non-simple index columns */
 	List	   *indpred;		/* predicate if a partial index, else NIL */
-
+	List	   *baserestrictinfo; /* a list of RestrictInfo nodes from the
+								   * query's WHERE or JOIN conditions, maybe
+								   * excluding those implied by the index
+								   * predicate */
 	List	   *indextlist;		/* targetlist representing index columns */
-
 	bool		predOK;			/* true if predicate matches query */
 	bool		unique;			/* true if a unique index */
 	bool		immediate;		/* is uniqueness enforced immediately? */
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out
index 601bdb4..3ff6691 100644
--- a/src/test/regress/expected/aggregates.out
+++ b/src/test/regress/expected/aggregates.out
@@ -780,7 +780,6 @@ explain (costs off)
                  ->  Index Only Scan Backward using minmaxtest2i on minmaxtest2
                        Index Cond: (f1 IS NOT NULL)
                  ->  Index Only Scan using minmaxtest3i on minmaxtest3
-                       Index Cond: (f1 IS NOT NULL)
    InitPlan 2 (returns $1)
      ->  Limit
            ->  Merge Append
@@ -792,8 +791,7 @@ explain (costs off)
                  ->  Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest2_1
                        Index Cond: (f1 IS NOT NULL)
                  ->  Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest3_1
-                       Index Cond: (f1 IS NOT NULL)
-(25 rows)
+(23 rows)
 
 select min(f1), max(f1) from minmaxtest;
  min | max 
@@ -818,7 +816,6 @@ explain (costs off)
                  ->  Index Only Scan Backward using minmaxtest2i on minmaxtest2
                        Index Cond: (f1 IS NOT NULL)
                  ->  Index Only Scan using minmaxtest3i on minmaxtest3
-                       Index Cond: (f1 IS NOT NULL)
    InitPlan 2 (returns $1)
      ->  Limit
            ->  Merge Append
@@ -830,11 +827,10 @@ explain (costs off)
                  ->  Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest2_1
                        Index Cond: (f1 IS NOT NULL)
                  ->  Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest3_1
-                       Index Cond: (f1 IS NOT NULL)
    ->  Sort
          Sort Key: ($0), ($1)
          ->  Result
-(28 rows)
+(26 rows)
 
 select distinct min(f1), max(f1) from minmaxtest;
  min | max 
