diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 0a669d9..1fc5068 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -1338,7 +1338,6 @@ ExplainNode(PlanState *planstate, List *ancestors,
 			show_tablesample(((SampleScan *) plan)->tablesample,
 							 planstate, ancestors, es);
 			/* FALL THRU to print additional fields the same as SeqScan */
-		case T_SeqScan:
 		case T_ValuesScan:
 		case T_CteScan:
 		case T_WorkTableScan:
@@ -1348,6 +1347,20 @@ ExplainNode(PlanState *planstate, List *ancestors,
 				show_instrumentation_count("Rows Removed by Filter", 1,
 										   planstate, es);
 			break;
+		case T_SeqScan:
+			{
+				SeqScan		*scan = (SeqScan*)plan;
+				show_scan_qual(scan->simplequal, "Scan Key", planstate,
+						ancestors, es);
+				show_scan_qual(plan->qual, "Filter", planstate, ancestors, es);
+				if (scan->simplequal)
+					show_instrumentation_count("Rows Removed by Scan Key", 2,
+											planstate, es);
+				if (plan->qual)
+					show_instrumentation_count("Rows Removed by Filter", 1,
+											planstate, es);
+			}
+			break;
 		case T_Gather:
 			{
 				Gather	   *gather = (Gather *) plan;
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 00bf3a5..8da2884 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -30,9 +30,12 @@
 #include "executor/execdebug.h"
 #include "executor/nodeSeqscan.h"
 #include "utils/rel.h"
+#include "optimizer/clauses.h"
+#include "utils/memutils.h"
 
 static void InitScanRelation(SeqScanState *node, EState *estate, int eflags);
 static TupleTableSlot *SeqNext(SeqScanState *node);
+static void prepare_scankey(ScanState *node, List *qual);
 
 /* ----------------------------------------------------------------
  *						Scan Support
@@ -53,6 +56,8 @@ SeqNext(SeqScanState *node)
 	EState	   *estate;
 	ScanDirection direction;
 	TupleTableSlot *slot;
+	bool			valid = false;
+	MemoryContext 	oldctx;
 
 	/*
 	 * get information from the estate and scan state
@@ -74,27 +79,56 @@ SeqNext(SeqScanState *node)
 		node->ss.ss_currentScanDesc = scandesc;
 	}
 
-	/*
-	 * get the next tuple from the table
-	 */
-	tuple = heap_getnext(scandesc, direction);
+	for (;;)
+	{
+		/*
+		 * get the next tuple from the table
+		 */
+		tuple = heap_getnext(scandesc, direction);
 
-	/*
-	 * save the tuple and the buffer returned to us by the access methods in
-	 * our scan tuple slot and return the slot.  Note: we pass 'false' because
-	 * tuples returned by heap_getnext() are pointers onto disk pages and were
-	 * not created with palloc() and so should not be pfree()'d.  Note also
-	 * that ExecStoreTuple will increment the refcount of the buffer; the
-	 * refcount will not be dropped until the tuple table slot is cleared.
-	 */
-	if (tuple)
-		ExecStoreTuple(tuple,	/* tuple to store */
-					   slot,	/* slot to store in */
-					   scandesc->rs_cbuf,		/* buffer associated with this
-												 * tuple */
-					   false);	/* don't pfree this pointer */
-	else
-		ExecClearTuple(slot);
+		/*
+		 * save the tuple and the buffer returned to us by the access methods
+		 * in our scan tuple slot and return the slot.  Note: we pass 'false'
+		 * because tuples returned by heap_getnext() are pointers onto disk
+		 * pages and were not created with palloc() and so should not be
+		 * pfree()'d.  Note also that ExecStoreTuple will increment the
+		 * refcount of the buffer; the refcount will not be dropped until the
+		 * tuple table slot is cleared.
+		 */
+		if (tuple)
+			ExecStoreTuple(tuple,	/* tuple to store */
+						   slot,	/* slot to store in */
+						   scandesc->rs_cbuf,		/* buffer associated with this
+													 * tuple */
+						   false);	/* don't pfree this pointer */
+		else
+		{
+			ExecClearTuple(slot);
+			break;
+		}
+
+		oldctx = MemoryContextSwitchTo(
+						node->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
+
+		ExecKeyTest(tuple, RelationGetDescr(node->ss.ss_currentRelation),
+				slot, scandesc->rs_cbuf, NULL, node->ss.nkey,
+				node->ss.keys, valid);
+		if (valid != true)
+		{
+			/*
+			 * tuple fail qual so reset the expression context and move
+			 * to next tuple.
+			 */
+			MemoryContextSwitchTo(oldctx);
+			ResetExprContext(node->ss.ps.ps_ExprContext);
+			InstrCountFiltered2(node, 1);
+			continue;
+		}
+
+		MemoryContextSwitchTo(oldctx);
+
+		return slot;
+	}
 
 	return slot;
 }
@@ -195,6 +229,8 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
 		ExecInitExpr((Expr *) node->plan.qual,
 					 (PlanState *) scanstate);
 
+	prepare_scankey(&scanstate->ss, node->simplequal);
+
 	/*
 	 * tuple table initialization
 	 */
@@ -342,3 +378,63 @@ ExecSeqScanInitializeWorker(SeqScanState *node, shm_toc *toc)
 	node->ss.ss_currentScanDesc =
 		heap_beginscan_parallel(node->ss.ss_currentRelation, pscan);
 }
+
+/*
+ * prepare_scankey
+ *
+ * process complete simplequal list and create scankey entry.
+ */
+static void
+prepare_scankey(ScanState *node, List *qual)
+{
+	ListCell   		*l;
+	Expr 	   		*expr;
+	ScanKey			 keys;
+	Expr			*leftop;
+	Expr			*rightop;
+	AttrNumber	 	 varattno;
+	Datum		 	 scanvalue;
+
+	if (qual == NULL)
+		return;
+
+	node->nkey = list_length(qual);
+	keys = node->keys = (ScanKey) palloc(sizeof(ScanKeyData) * node->nkey);
+
+	foreach(l, qual)
+	{
+		expr = (Expr *) lfirst(l);
+
+		Assert(IsA(expr, OpExpr));
+
+		leftop = (Expr *) get_leftop(expr);
+		rightop = (Expr *) get_rightop(expr);
+
+		Assert(leftop && rightop);
+
+		/* Right op must be of RelabelType or Var type */
+		Assert(IsA(leftop, RelabelType) || IsA(leftop, Var));
+
+		/* Lest op must be of RelabelType or Const type*/
+		Assert(IsA(leftop, RelabelType) || IsA(leftop, Const));
+
+		if (IsA(leftop, RelabelType))
+			leftop = ((RelabelType *) leftop)->arg;
+
+		if (IsA(rightop, RelabelType))
+			rightop = ((RelabelType *) rightop)->arg;
+
+		varattno = ((Var *) leftop)->varattno;
+		scanvalue = ((Const *) rightop)->constvalue;
+
+		/* Create scan key entry */
+		ScanKeyInit(keys,
+				varattno,
+				InvalidStrategy,
+				((OpExpr *) expr)->opfuncid,
+				scanvalue);
+
+		keys->sk_collation = ((OpExpr *) expr)->inputcollid;
+		keys++;
+	}
+}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 04e49b7..90bdfd8 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -354,6 +354,7 @@ CopyScanFields(const Scan *from, Scan *newnode)
 	CopyPlanFields((const Plan *) from, (Plan *) newnode);
 
 	COPY_SCALAR_FIELD(scanrelid);
+	COPY_NODE_FIELD(simplequal);
 }
 
 /*
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 748b687..32c1824 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -291,6 +291,7 @@ _outScanInfo(StringInfo str, const Scan *node)
 	_outPlanInfo(str, (const Plan *) node);
 
 	WRITE_UINT_FIELD(scanrelid);
+	WRITE_NODE_FIELD(simplequal);
 }
 
 /*
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 917e6c8..b8f32aa 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1604,6 +1604,7 @@ ReadCommonScan(Scan *local_node)
 	ReadCommonPlan(&local_node->plan);
 
 	READ_UINT_FIELD(scanrelid);
+	READ_NODE_FIELD(simplequal);
 }
 
 /*
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index ad49674..c795a7a 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -158,7 +158,8 @@ static void copy_generic_path_info(Plan *dest, Path *src);
 static void copy_plan_costsize(Plan *dest, Plan *src);
 static void label_sort_with_costsize(PlannerInfo *root, Sort *plan,
 						 double limit_tuples);
-static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
+static SeqScan *make_seqscan(List *qptlist, List *qpqual, List *simplequal,
+						Index scanrelid);
 static SampleScan *make_samplescan(List *qptlist, List *qpqual, Index scanrelid,
 				TableSampleClause *tsc);
 static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
@@ -2265,6 +2266,9 @@ create_seqscan_plan(PlannerInfo *root, Path *best_path,
 {
 	SeqScan    *scan_plan;
 	Index		scan_relid = best_path->parent->relid;
+	List	   *qpqual;
+	List	   *simplequal;
+	ListCell   *l;
 
 	/* it should be a base rel... */
 	Assert(scan_relid > 0);
@@ -2273,19 +2277,32 @@ create_seqscan_plan(PlannerInfo *root, Path *best_path,
 	/* Sort clauses into best execution order */
 	scan_clauses = order_qual_clauses(root, scan_clauses);
 
+	qpqual = NIL;
+	foreach(l, scan_clauses)
+	{
+		RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
+
+		Assert(IsA(rinfo, RestrictInfo));
+		if (list_member_ptr(best_path->simplequal, rinfo))
+			continue;			/* simple duplicate */
+		qpqual = lappend(qpqual, rinfo);
+	}
+
 	/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
-	scan_clauses = extract_actual_clauses(scan_clauses, false);
+	qpqual = extract_actual_clauses(qpqual, false);
+	simplequal = extract_actual_clauses(best_path->simplequal, false);
+
 
 	/* Replace any outer-relation variables with nestloop params */
 	if (best_path->param_info)
 	{
-		scan_clauses = (List *)
-			replace_nestloop_params(root, (Node *) scan_clauses);
+		qpqual = (List *) replace_nestloop_params(root, (Node *) qpqual);
 	}
 
 	scan_plan = make_seqscan(tlist,
-							 scan_clauses,
-							 scan_relid);
+							qpqual,
+							simplequal,
+							scan_relid);
 
 	copy_generic_path_info(&scan_plan->plan, best_path);
 
@@ -4656,6 +4673,7 @@ label_sort_with_costsize(PlannerInfo *root, Sort *plan, double limit_tuples)
 static SeqScan *
 make_seqscan(List *qptlist,
 			 List *qpqual,
+			 List *simplequal,
 			 Index scanrelid)
 {
 	SeqScan    *node = makeNode(SeqScan);
@@ -4666,7 +4684,7 @@ make_seqscan(List *qptlist,
 	plan->lefttree = NULL;
 	plan->righttree = NULL;
 	node->scanrelid = scanrelid;
-
+	node->simplequal = simplequal;
 	return node;
 }
 
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index d91bc3b..2dea1de 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -453,6 +453,8 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 				SeqScan    *splan = (SeqScan *) plan;
 
 				splan->scanrelid += rtoffset;
+				splan->simplequal =
+					fix_scan_list(root, splan->simplequal, rtoffset);
 				splan->plan.targetlist =
 					fix_scan_list(root, splan->plan.targetlist, rtoffset);
 				splan->plan.qual =
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 6d3ccfd..0df72a0 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -46,6 +46,7 @@ typedef enum
 #define STD_FUZZ_FACTOR 1.01
 
 static List *translate_sub_tlist(List *tlist, int relid);
+static void create_simple_qual(RelOptInfo *rel, Path *path);
 
 
 /*****************************************************************************
@@ -957,6 +958,9 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel,
 
 	cost_seqscan(pathnode, root, rel, pathnode->param_info);
 
+	/* create simple qual from baserestrictinfo */
+	create_simple_qual(rel, pathnode);
+
 	return pathnode;
 }
 
@@ -3209,3 +3213,61 @@ reparameterize_path(PlannerInfo *root, Path *path,
 	}
 	return NULL;
 }
+
+/*
+ * create_simple_qual
+ *
+ *		Find the simple qual from baserestriction info.
+ *	Process baserestriction and find out all qual which is of form
+ *	var op const.
+ */
+static void
+create_simple_qual(RelOptInfo *rel, Path *path)
+{
+	ListCell	*lc;
+	List		*clauses = rel->baserestrictinfo;
+
+	foreach(lc, clauses)
+	{
+		RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+		Expr	     *clause = rinfo->clause;
+		Node	     *leftop,
+				     *rightop;
+
+		if (is_opclause(clause))
+		{
+			leftop = get_leftop(clause);
+			rightop = get_rightop(clause);
+
+			if (!leftop || !rightop)
+				continue;
+
+			if (leftop && IsA(leftop, RelabelType))
+				leftop = (Node*)(((RelabelType *) leftop)->arg);
+
+			Assert(leftop != NULL);
+
+			/* If leftop is not var then continue and check next qual. */
+			if (!(IsA(leftop, Var)))
+			{
+				continue;
+			}
+
+			if (rightop && IsA(rightop, RelabelType))
+				rightop = (Node*)(((RelabelType *) rightop)->arg);
+
+			Assert(rightop != NULL);
+
+			/*
+			 * If right op is not constant then this can not be executed as
+			 * simple qual.
+			 */
+			if (!IsA(rightop, Const))
+			{
+				continue;
+			}
+
+			path->simplequal = lappend(path->simplequal, rinfo);
+		}
+	}
+}
diff --git a/src/include/executor/nodeSeqscan.h b/src/include/executor/nodeSeqscan.h
index f2e61ff..44c00d9 100644
--- a/src/include/executor/nodeSeqscan.h
+++ b/src/include/executor/nodeSeqscan.h
@@ -27,4 +27,50 @@ extern void ExecSeqScanEstimate(SeqScanState *node, ParallelContext *pcxt);
 extern void ExecSeqScanInitializeDSM(SeqScanState *node, ParallelContext *pcxt);
 extern void ExecSeqScanInitializeWorker(SeqScanState *node, shm_toc *toc);
 
+/*
+ *		ExecKeyTest
+ *
+ *		Test a heap tuple to see if it satisfies a scan key.
+ */
+#define ExecKeyTest(tuple, \
+					tupdesc, \
+					slot, \
+					buf, \
+					context, \
+					nkeys, \
+					keys, \
+					result) \
+do \
+{ \
+	/* Use underscores to protect the variables passed in as parameters */ \
+	int				__cur_nkeys = (nkeys); \
+	ScanKey			__cur_keys = (keys); \
+	\
+	(result) = true; /* may change */ \
+	for (; __cur_nkeys--; __cur_keys++) \
+	{ \
+		Datum	__atp; \
+		bool	__isnull; \
+		Datum	__test; \
+\
+		__atp = slot_getattr((slot), __cur_keys->sk_attno, &__isnull); \
+ \
+		if (__isnull) \
+		{ \
+			(result) = false; \
+			break; \
+		} \
+ \
+		__test = FunctionCall2Coll(&__cur_keys->sk_func, \
+								   __cur_keys->sk_collation, \
+								   __atp, __cur_keys->sk_argument); \
+ \
+		if (!DatumGetBool(__test)) \
+		{ \
+			(result) = false; \
+			break; \
+		} \
+	} \
+} while (0)
+
 #endif   /* NODESEQSCAN_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index f6f73f3..faad0a1 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1256,6 +1256,8 @@ typedef struct ScanState
 	Relation	ss_currentRelation;
 	HeapScanDesc ss_currentScanDesc;
 	TupleTableSlot *ss_ScanTupleSlot;
+	int			nkey;
+	ScanKey		keys;
 } ScanState;
 
 /* ----------------
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index e2fbc7d..fd736c5 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -282,8 +282,9 @@ typedef struct BitmapOr
  */
 typedef struct Scan
 {
-	Plan		plan;
-	Index		scanrelid;		/* relid is index into the range table */
+	Plan		 plan;
+	Index		 scanrelid;		/* relid is index into the range table */
+	List		*simplequal;	/* simple var op const qual of seq scan */
 } Scan;
 
 /* ----------------
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 3a1255a..62e96fa 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -895,7 +895,7 @@ typedef struct Path
 	double		rows;			/* estimated number of result tuples */
 	Cost		startup_cost;	/* cost expended before fetching any tuples */
 	Cost		total_cost;		/* total cost (assuming all tuples fetched) */
-
+	List	   *simplequal;		/* quals which can be converted to scankey */
 	List	   *pathkeys;		/* sort ordering of path's output */
 	/* pathkeys is a List of PathKey nodes; see above */
 } Path;
