diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 1144a4c..bb4ce03 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2128,6 +2128,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 4f60b85..3fdb522 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 943fcde..87e6abd 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -427,22 +427,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..6a9a2a7 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -30,8 +30,10 @@
 #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 "parser/parsetree.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/lsyscache.h"
@@ -136,8 +138,7 @@ static double adjust_rowcount_for_semijoins(PlannerInfo *root,
 							  Index outer_relid,
 							  double rowcount);
 static double approximate_joinrel_size(PlannerInfo *root, Relids relids);
-static void match_restriction_clauses_to_index(RelOptInfo *rel,
-								   IndexOptInfo *index,
+static void match_restriction_clauses_to_index(IndexOptInfo *index,
 								   IndexClauseSet *clauseset);
 static void match_join_clauses_to_index(PlannerInfo *root,
 							RelOptInfo *rel, IndexOptInfo *index,
@@ -266,7 +267,7 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
 		 * Identify the restriction clauses that can match the index.
 		 */
 		MemSet(&rclauseset, 0, sizeof(rclauseset));
-		match_restriction_clauses_to_index(rel, index, &rclauseset);
+		match_restriction_clauses_to_index(index, &rclauseset);
 
 		/*
 		 * Build index paths from the restriction clauses.  These will be
@@ -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 also removable 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);
 
@@ -2020,10 +2021,10 @@ approximate_joinrel_size(PlannerInfo *root, Relids relids)
  *	  Matching clauses are added to *clauseset.
  */
 static void
-match_restriction_clauses_to_index(RelOptInfo *rel, IndexOptInfo *index,
+match_restriction_clauses_to_index(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 re-creating restrictions list if not necessary but
+		 * the cost saved by such optimization is expected relavively low.
+		 * So unconditionally replace it even if it is virtually unchanged
+		 * as the result.
+		 */
+		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 087cb9c..e327e77 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,26 @@ 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:
+		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 +513,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
+	 * have its own baserestrictinfo which may different from that of the
+	 * parent relations.
 	 */
-	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 +2423,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..a4be820 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);
+
+			/*
+			 * indrelinfos is to have maybe-modified baserestrictinfo but the
+			 * baserestrictinfo is not fixed at this point.
+			 */
+			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 5032696..3e12e97 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 
