diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 2952bfb..6abeda1 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_opfamily.h"
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/pathnode.h"
@@ -130,7 +131,13 @@ static PathClauseUsage *classify_index_clause_usage(Path *path,
 static Relids get_bitmap_tree_required_outer(Path *bitmapqual);
 static void find_indexpath_quals(Path *bitmapqual, List **quals, List **preds);
 static int	find_list_position(Node *node, List **nodelist);
-static bool check_index_only(RelOptInfo *rel, IndexOptInfo *index);
+static bool check_index_only(PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index);
+static bool check_index_only_targetlist(PlannerInfo *root,
+							RelOptInfo *rel,
+							IndexOptInfo *index,
+							Bitmapset *index_canreturn_attrs);
+static bool check_index_only_clauses(List *clauses,
+						 IndexOptInfo *index);
 static double get_loop_count(PlannerInfo *root, Index cur_relid, Relids outer_relids);
 static double adjust_rowcount_for_semijoins(PlannerInfo *root,
 							  Index cur_relid,
@@ -1020,7 +1027,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 	 * index data retrieval anyway.
 	 */
 	index_only_scan = (scantype != ST_BITMAPSCAN &&
-					   check_index_only(rel, index));
+					   check_index_only(root, rel, index));
 
 	/*
 	 * 4. Generate an indexscan path if there are relevant restriction clauses
@@ -1786,7 +1793,7 @@ find_list_position(Node *node, List **nodelist)
  *		Determine whether an index-only scan is possible for this index.
  */
 static bool
-check_index_only(RelOptInfo *rel, IndexOptInfo *index)
+check_index_only(PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index)
 {
 	bool		result;
 	Bitmapset  *attrs_used = NULL;
@@ -1837,8 +1844,10 @@ check_index_only(RelOptInfo *rel, IndexOptInfo *index)
 		int			attno = index->indexkeys[i];
 
 		/*
-		 * For the moment, we just ignore index expressions.  It might be nice
-		 * to do something with them, later.
+		 * We ignore expressions here and only look at plain attributes. Analyzing
+		 * expressions is also a bit more expensive, so we first try to match the
+		 * expressions to attributes indexed directly, and spend additional CPU time
+		 * on analyzing the expressions only if needed.
 		 */
 		if (attno == 0)
 			continue;
@@ -1852,12 +1861,206 @@ check_index_only(RelOptInfo *rel, IndexOptInfo *index)
 	/* Do we have all the necessary attributes? */
 	result = bms_is_subset(attrs_used, index_canreturn_attrs);
 
+	/*
+	 * If the directly indexed attributes are not sufficient, it's time to look
+	 * at index expressions and try to match them to targetlist and index clauses.
+	 */
+	if (!result && index->indexprs)
+		result =
+			check_index_only_targetlist(root, rel, index, index_canreturn_attrs) &&
+			check_index_only_clauses(index->indrestrictinfo, index);
+
 	bms_free(attrs_used);
 	bms_free(index_canreturn_attrs);
 
 	return result;
 }
 
+typedef struct check_index_only_walker_ctx
+{
+	IndexOptInfo   *index;
+	Bitmapset	   *index_canreturn_attrs;	/* attributes that can be returned
+											 * by index */
+	bool			match;					/* TRUE if expression matches
+											 * index */
+} check_index_only_walker_ctx;
+
+/*
+ * check_index_only_expr_walker
+ * 		Recursive walker that checks if each part of the expression can be
+ *		build with index expressions or attributes
+ */
+static bool
+check_index_only_expr_walker(Node *node, check_index_only_walker_ctx *ctx)
+{
+	int i;
+
+	/*
+	 * If node is empty or some subexpression has already reported that it
+	 * isn't match the index then quit looking any further
+	 */
+	if (node == NULL || ctx->match == false)
+		return false;
+
+	/* If this is a Var then check if it can be returned by the index */
+	if (IsA(node, Var))
+	{
+		Var *var = (Var *) node;
+
+		if (var->varno == ctx->index->rel->relid &&
+			!bms_is_member(var->varattno - FirstLowInvalidHeapAttributeNumber,
+						   ctx->index_canreturn_attrs))
+			ctx->match = false;
+		return false;
+	}
+
+	/*
+	 * Not a Var, so it has to be an expression. So we try to match it to
+	 * index expressions. If it matches, we're done with this subtree.
+	 *
+	 * XXX This also check the expression against indexed attributes, but
+	 * that seems a bit pointless as that can only match Vars, which we
+	 * already handled above. It's a fairly cheap check, but maybe on
+	 * indexes with many columns it might be noticeable (and only looking
+	 * at index->indexprs would help?).
+	 */
+	for (i = 0; i < ctx->index->ncolumns; i++)
+		if (match_index_to_operand(node, i, ctx->index))
+			return false;
+
+	/* Recursive check */
+	return expression_tree_walker(node, check_index_only_expr_walker, (void *) ctx);
+}
+
+/*
+ * check_index_only_targetlist
+ *		Checks that every target of index->relation can be returned by index
+ *
+ * In this function we're looking through root->parse->targetlist and pick
+ * those targets which contain index->relation's attributes. For each selected
+ * target we use recursive function check_index_only_expr_walker() to check if
+ * target can be build with the index expressions and attributes and none of
+ * the other index->relation's attributes
+ */
+static bool
+check_index_only_targetlist(PlannerInfo *root,
+							RelOptInfo *rel,
+							IndexOptInfo *index,
+							Bitmapset *index_canreturn_attrs)
+{
+	ListCell *lc;
+	bool	result = true;
+
+	/* Check expressions from targetlist */
+	foreach(lc, root->parse->targetList)
+	{
+		TargetEntry *te = (TargetEntry *) lfirst(lc);
+		Bitmapset *varnos = pull_varnos((Node *) te->expr);
+
+		/* Ignore targetlist entries not related to the indexed relation. */
+		if (bms_is_member(rel->relid, varnos))
+		{
+			bool		is_matched = false; /* assume the expression is not matched */
+			Bitmapset  *attrs = NULL;
+
+			pull_varattnos((Node *) te->expr, rel->relid, &attrs);
+
+			if (bms_is_subset(attrs, index_canreturn_attrs))
+				is_matched = true;
+			else
+			{
+				check_index_only_walker_ctx *ctx;
+
+				ctx = (check_index_only_walker_ctx *) palloc(sizeof(check_index_only_walker_ctx));
+				ctx->index = index;
+				ctx->match = true;
+				ctx->index_canreturn_attrs = index_canreturn_attrs;
+				check_index_only_expr_walker((Node *) te->expr, ctx);
+
+				if (ctx->match)
+					is_matched = true;
+
+				pfree(ctx);
+			}
+
+			bms_free(attrs);
+
+			/* if the expression is not matched, we don't need to look any further */
+			if (! is_matched)
+			{
+				result = false;
+				break;
+			}
+		}
+
+		bms_free(varnos);
+	}
+
+	return result;
+}
+
+/*
+ * check_index_only_clauses
+ *		Recursive function that checks that each clause matches the index
+ *
+ * clauses is a list of RestrictInfos or a BoolExpr containing RestrictInfos
+ */
+static bool
+check_index_only_clauses(List *clauses,
+						 IndexOptInfo *index)
+{
+	int 		indexcol;
+	ListCell   *lc;
+
+	foreach(lc, clauses)
+	{
+		bool	match = false;
+		Node   *node = (Node *) lfirst(lc);
+
+		/*
+		 * We expect here either a RestrictInfo or a boolean
+		 * expression containing other RestrictInfos
+		 */
+		if (IsA(node, RestrictInfo))
+		{
+			RestrictInfo *rinfo = (RestrictInfo *) node;
+
+			if (!restriction_is_or_clause(rinfo))
+			{
+				for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
+				{
+					if (match_clause_to_indexcol(index, indexcol, rinfo))
+					{
+						match = true;
+						break;
+					}
+				}
+			}
+			else
+			{
+				List *subclauses = ((BoolExpr *) rinfo->orclause)->args;
+
+				match = check_index_only_clauses(subclauses, index);
+			}
+		}
+		else if (IsA(node, BoolExpr))
+		{
+			BoolExpr *boolexpr = (BoolExpr *) node;
+
+			match = check_index_only_clauses(boolexpr->args, index);
+		}
+
+		/*
+		 * If at least one restriction doesn't match index then return false
+		 */
+		if (!match)
+			return false;
+	}
+
+	/* If we got here then everything's fine */
+	return true;
+}
+
 /*
  * get_loop_count
  *		Choose the loop count estimate to use for costing a parameterized path
