diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 7fb8a14..d03fbde 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -729,6 +729,7 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
 	switch (nodeTag(plan))
 	{
 		case T_SeqScan:
+		case T_PartialSeqScan:
 		case T_SampleScan:
 		case T_IndexScan:
 		case T_IndexOnlyScan:
@@ -850,6 +851,9 @@ ExplainNode(PlanState *planstate, List *ancestors,
 		case T_SeqScan:
 			pname = sname = "Seq Scan";
 			break;
+		case T_PartialSeqScan:
+			pname = sname = "Partial Seq Scan";
+			break;
 		case T_SampleScan:
 			pname = sname = "Sample Scan";
 			break;
@@ -1005,6 +1009,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
 	switch (nodeTag(plan))
 	{
 		case T_SeqScan:
+		case T_PartialSeqScan:
 		case T_SampleScan:
 		case T_BitmapHeapScan:
 		case T_TidScan:
@@ -1270,6 +1275,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
 							 planstate, ancestors, es);
 			/* FALL THRU to print additional fields the same as SeqScan */
 		case T_SeqScan:
+		case T_PartialSeqScan:
 		case T_ValuesScan:
 		case T_CteScan:
 		case T_WorkTableScan:
@@ -2353,6 +2359,7 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
 	switch (nodeTag(plan))
 	{
 		case T_SeqScan:
+		case T_PartialSeqScan:
 		case T_SampleScan:
 		case T_IndexScan:
 		case T_IndexOnlyScan:
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index 51edd4c..38a92fe 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -21,8 +21,8 @@ OBJS = execAmi.o execCurrent.o execGrouping.o execIndexing.o execJunk.o \
        nodeHash.o nodeHashjoin.o nodeIndexscan.o nodeIndexonlyscan.o \
        nodeLimit.o nodeLockRows.o \
        nodeMaterial.o nodeMergeAppend.o nodeMergejoin.o nodeModifyTable.o \
-       nodeNestloop.o nodeFunctionscan.o nodeRecursiveunion.o nodeResult.o \
-       nodeSamplescan.o nodeSeqscan.o nodeSetOp.o nodeSort.o nodeUnique.o \
+       nodeNestloop.o nodeFunctionscan.o nodePartialSeqscan.o nodeRecursiveunion.o \
+       nodeResult.o nodeSamplescan.o nodeSeqscan.o nodeSetOp.o nodeSort.o nodeUnique.o \
        nodeValuesscan.o nodeCtescan.o nodeWorktablescan.o \
        nodeGroup.o nodeSubplan.o nodeSubqueryscan.o nodeTidscan.o \
        nodeForeignscan.o nodeWindowAgg.o tstoreReceiver.o tqueue.o spi.o
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 163650c..b3d041c 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -38,6 +38,7 @@
 #include "executor/nodeMergejoin.h"
 #include "executor/nodeModifyTable.h"
 #include "executor/nodeNestloop.h"
+#include "executor/nodePartialSeqscan.h"
 #include "executor/nodeRecursiveunion.h"
 #include "executor/nodeResult.h"
 #include "executor/nodeSamplescan.h"
@@ -157,6 +158,10 @@ ExecReScan(PlanState *node)
 			ExecReScanSeqScan((SeqScanState *) node);
 			break;
 
+		case T_PartialSeqScanState:
+			ExecReScanPartialSeqScan((PartialSeqScanState *) node);
+			break;
+
 		case T_SampleScanState:
 			ExecReScanSampleScan((SampleScanState *) node);
 			break;
@@ -468,6 +473,9 @@ ExecSupportsBackwardScan(Plan *node)
 		case T_CteScan:
 			return TargetListSupportsBackwardScan(node->targetlist);
 
+		case T_PartialSeqScan:
+			return false;
+
 		case T_SampleScan:
 			/* Simplify life for tablesample methods by disallowing this */
 			return false;
diff --git a/src/backend/executor/execCurrent.c b/src/backend/executor/execCurrent.c
index bcd287f..6e05598 100644
--- a/src/backend/executor/execCurrent.c
+++ b/src/backend/executor/execCurrent.c
@@ -261,6 +261,7 @@ search_plan_tree(PlanState *node, Oid table_oid)
 			 * Relation scan nodes can all be treated alike
 			 */
 		case T_SeqScanState:
+		case T_PartialSeqScanState:
 		case T_SampleScanState:
 		case T_IndexScanState:
 		case T_IndexOnlyScanState:
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index e6930c1..b0a7ce4 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -17,6 +17,7 @@
 
 #include "executor/execParallel.h"
 #include "executor/executor.h"
+#include "executor/nodePartialSeqscan.h"
 #include "executor/tqueue.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/planmain.h"
@@ -158,10 +159,19 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
 	/* Count this node. */
 	e->nnodes++;
 
-	/*
-	 * XXX. Call estimators for parallel-aware nodes here, when we have
-	 * some.
-	 */
+	/* Call estimators for parallel-aware nodes. */
+	switch (nodeTag(planstate))
+	{
+		case T_PartialSeqScanState:
+			{
+				ExecPartialSeqScanEstimate((PartialSeqScanState *) planstate,
+										   e->pcxt);
+				return true;
+			}
+			break;
+		default:
+			break;
+	}
 
 	return planstate_tree_walker(planstate, ExecParallelEstimate, e);
 }
@@ -196,10 +206,19 @@ ExecParallelInitializeDSM(PlanState *planstate,
 	/* Count this node. */
 	d->nnodes++;
 
-	/*
-	 * XXX. Call initializers for parallel-aware plan nodes, when we have
-	 * some.
-	 */
+	/* Call initializers for parallel-aware plan nodes. */
+	switch (nodeTag(planstate))
+	{
+		case T_PartialSeqScanState:
+			{
+				ExecPartialSeqScanInitializeDSM((PartialSeqScanState *) planstate,
+												d->pcxt);
+				return true;
+			}
+			break;
+		default:
+			break;
+	}
 
 	return planstate_tree_walker(planstate, ExecParallelInitializeDSM, d);
 }
@@ -531,6 +550,35 @@ ExecParallelReportInstrumentation(PlanState *planstate,
 }
 
 /*
+ * Initialize the PlanState and it's descendents with the information
+ * retrieved from shared memory.  This has to be done once the PlanState
+ * is allocated and initialized by executor for each node aka after
+ * ExecutorStart().
+ */
+static bool
+ExecParallelInitializeWorker(PlanState *planstate, shm_toc *toc)
+{
+	if (planstate == NULL)
+		return false;
+
+	/* Call initializers for parallel-aware plan nodes. */
+	switch (nodeTag(planstate))
+	{
+		case T_PartialSeqScanState:
+			{
+				ExecPartialSeqScanInitParallelScanDesc((PartialSeqScanState *) planstate,
+													   toc);
+				return true;
+			}
+			break;
+		default:
+			break;
+	}
+
+	return planstate_tree_walker(planstate, ExecParallelInitializeWorker, toc);
+}
+
+/*
  * Main entrypoint for parallel query worker processes.
  *
  * We reach this function from ParallelMain, so the setup necessary to create
@@ -566,6 +614,7 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc)
 
 	/* Start up the executor, have it run the plan, and then shut it down. */
 	ExecutorStart(queryDesc, 0);
+	ExecParallelInitializeWorker(queryDesc->planstate, toc);
 	ExecutorRun(queryDesc, ForwardScanDirection, 0L);
 	ExecutorFinish(queryDesc);
 
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 5bc1d48..4591268 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -100,6 +100,7 @@
 #include "executor/nodeMergejoin.h"
 #include "executor/nodeModifyTable.h"
 #include "executor/nodeNestloop.h"
+#include "executor/nodePartialSeqscan.h"
 #include "executor/nodeGather.h"
 #include "executor/nodeRecursiveunion.h"
 #include "executor/nodeResult.h"
@@ -193,6 +194,11 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
 												   estate, eflags);
 			break;
 
+		case T_PartialSeqScan:
+			result = (PlanState *) ExecInitPartialSeqScan((PartialSeqScan *) node,
+														  estate, eflags);
+			break;
+
 		case T_SampleScan:
 			result = (PlanState *) ExecInitSampleScan((SampleScan *) node,
 													  estate, eflags);
@@ -419,6 +425,10 @@ ExecProcNode(PlanState *node)
 			result = ExecSeqScan((SeqScanState *) node);
 			break;
 
+		case T_PartialSeqScanState:
+			result = ExecPartialSeqScan((PartialSeqScanState *) node);
+			break;
+
 		case T_SampleScanState:
 			result = ExecSampleScan((SampleScanState *) node);
 			break;
@@ -665,6 +675,10 @@ ExecEndNode(PlanState *node)
 			ExecEndSeqScan((SeqScanState *) node);
 			break;
 
+		case T_PartialSeqScanState:
+			ExecEndPartialSeqScan((PartialSeqScanState *) node);
+			break;
+
 		case T_SampleScanState:
 			ExecEndSampleScan((SampleScanState *) node);
 			break;
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index c689a4d..8edc2fd 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -247,7 +247,7 @@ gather_getnext(GatherState *gatherstate)
 void
 ExecShutdownGather(GatherState *node)
 {
-	Gather *gather;
+	Gather	   *gather;
 
 	if (node->pei == NULL || node->pei->pcxt == NULL)
 		return;
@@ -295,5 +295,15 @@ ExecReScanGather(GatherState *node)
 	 */
 	ExecShutdownGather(node);
 
+	/*
+	 * free the parallel executor information so that during next execution,
+	 * parallel context and workers could be initialized.
+	 */
+	if (node->pei)
+	{
+		pfree(node->pei);
+		node->pei = NULL;
+	}
+
 	ExecReScan(node->ps.lefttree);
 }
diff --git a/src/backend/executor/nodePartialSeqscan.c b/src/backend/executor/nodePartialSeqscan.c
new file mode 100644
index 0000000..3168f0c
--- /dev/null
+++ b/src/backend/executor/nodePartialSeqscan.c
@@ -0,0 +1,348 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodePartialSeqscan.c
+ *	  Support routines for partial sequential scans of relations.
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/executor/nodePartialSeqscan.c
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ * INTERFACE ROUTINES
+ *		ExecPartialSeqScan				scans a relation partially.
+ *		PartialSeqNext					retrieve next tuple from heap.
+ *		ExecInitPartialSeqScan			creates and initializes a partial seqscan node.
+ *		ExecEndPartialSeqScan			releases any storage allocated.
+ */
+#include "postgres.h"
+
+#include "access/relscan.h"
+#include "executor/execdebug.h"
+#include "executor/execParallel.h"
+#include "executor/nodePartialSeqscan.h"
+#include "utils/rel.h"
+
+
+
+/* ----------------------------------------------------------------
+ *						Scan Support
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------------------------------------------------------
+ *		PartialSeqNext
+ *
+ *		This is a workhorse for ExecPartialSeqScan
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+PartialSeqNext(PartialSeqScanState *node)
+{
+	HeapTuple	tuple;
+	HeapScanDesc scandesc;
+	EState	   *estate;
+	ScanDirection direction;
+	TupleTableSlot *slot;
+
+	/*
+	 * get information from the estate and scan state
+	 */
+	scandesc = node->ss.ss_currentScanDesc;
+	estate = node->ss.ps.state;
+	direction = estate->es_direction;
+	slot = node->ss.ss_ScanTupleSlot;
+
+	/*
+	 * 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);
+
+	return slot;
+}
+
+/*
+ * PartialSeqRecheck -- access method routine to recheck a tuple in EvalPlanQual
+ */
+static bool
+PartialSeqRecheck(PartialSeqScanState *node, TupleTableSlot *slot)
+{
+	/*
+	 * Note that unlike IndexScan, PartialSeqScan never use keys in
+	 * heap_beginscan (and this is very bad) - so, here we do not check are
+	 * keys ok or not.
+	 */
+	return true;
+}
+
+/* ----------------------------------------------------------------
+ *		InitPartialScanRelation
+ *
+ *		Set up to access the scan relation.
+ * ----------------------------------------------------------------
+ */
+static void
+InitPartialScanRelation(PartialSeqScanState *node, EState *estate, int eflags)
+{
+	Relation	currentRelation;
+
+	/*
+	 * get the relation object id from the relid'th entry in the range table,
+	 * open that relation and acquire appropriate lock on it.
+	 */
+	currentRelation = ExecOpenScanRelation(estate,
+									  ((Scan *) node->ss.ps.plan)->scanrelid,
+										   eflags);
+
+	node->ss.ss_currentRelation = currentRelation;
+
+	/* and report the scan tuple slot's rowtype */
+	ExecAssignScanType(&node->ss, RelationGetDescr(currentRelation));
+}
+
+/* ----------------------------------------------------------------
+ *		ExecPartialSeqScanEstimate
+ *
+ *		estimates the space required to serialize partial seqscan node.
+ * ----------------------------------------------------------------
+ */
+void
+ExecPartialSeqScanEstimate(PartialSeqScanState *node,
+						   ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+
+	node->pscan_len = heap_parallelscan_estimate(estate->es_snapshot);
+	shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
+
+	/* key for partial scan information. */
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecPartialSeqScanInitializeDSM
+ *
+ *		Initialize the DSM with the contents required to perform
+ *		partial seqscan.
+ * ----------------------------------------------------------------
+ */
+void
+ExecPartialSeqScanInitializeDSM(PartialSeqScanState *node,
+								ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+
+	/*
+	 * Store parallel heap scan descriptor in dynamic shared memory.
+	 */
+	node->pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
+	heap_parallelscan_initialize(node->pscan,
+								 node->ss.ss_currentRelation,
+								 estate->es_snapshot,
+								 true);
+	shm_toc_insert(pcxt->toc,
+				   node->ss.ps.plan->plan_node_id,
+				   node->pscan);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecPartialSeqScanInitParallelDesc
+ *
+ *		Retrieve the contents from DSM related to partial seq scan node
+ *		and initialize the partial seqscan node.
+ * ----------------------------------------------------------------
+ */
+void
+ExecPartialSeqScanInitParallelScanDesc(PartialSeqScanState *node,
+									   shm_toc *toc)
+{
+	node->pscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecInitPartialSeqScan
+ * ----------------------------------------------------------------
+ */
+PartialSeqScanState *
+ExecInitPartialSeqScan(PartialSeqScan *node, EState *estate, int eflags)
+{
+	PartialSeqScanState *scanstate;
+
+	/*
+	 * Once upon a time it was possible to have an outerPlan of a SeqScan, but
+	 * not any more.
+	 */
+	Assert(outerPlan(node) == NULL);
+	Assert(innerPlan(node) == NULL);
+
+	/*
+	 * create state structure
+	 */
+	scanstate = makeNode(PartialSeqScanState);
+	scanstate->ss.ps.plan = (Plan *) node;
+	scanstate->ss.ps.state = estate;
+
+	/*
+	 * Miscellaneous initialization
+	 *
+	 * create expression context for node
+	 */
+	ExecAssignExprContext(estate, &scanstate->ss.ps);
+
+	/*
+	 * initialize child expressions
+	 */
+	scanstate->ss.ps.targetlist = (List *)
+		ExecInitExpr((Expr *) node->plan.targetlist,
+					 (PlanState *) scanstate);
+	scanstate->ss.ps.qual = (List *)
+		ExecInitExpr((Expr *) node->plan.qual,
+					 (PlanState *) scanstate);
+
+	/*
+	 * tuple table initialization
+	 */
+	ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
+	ExecInitScanTupleSlot(estate, &scanstate->ss);
+
+	/*
+	 * initialize scan relation
+	 */
+	InitPartialScanRelation(scanstate, estate, eflags);
+
+	scanstate->ss.ps.ps_TupFromTlist = false;
+
+	/*
+	 * Initialize result tuple type and projection info.
+	 */
+	ExecAssignResultTypeFromTL(&scanstate->ss.ps);
+	ExecAssignScanProjectionInfo(&scanstate->ss);
+
+	scanstate->scan_initialized = false;
+
+	return scanstate;
+}
+
+/* ----------------------------------------------------------------
+ *		ExecPartialSeqScan(node)
+ *
+ *		Scans the relation and returns the next qualifying tuple.
+ *		We call the ExecScan() routine and pass it the appropriate
+ *		access method functions.
+ * ----------------------------------------------------------------
+ */
+TupleTableSlot *
+ExecPartialSeqScan(PartialSeqScanState *node)
+{
+	/*
+	 * Initialize the scan on first execution, normally we initialize it
+	 * during ExecutorStart phase, however we need ParallelHeapScanDesc to
+	 * initialize the scan in case of this node and the same is initialized by
+	 * the Gather node during ExecutorRun phase.
+	 */
+	if (!node->scan_initialized)
+	{
+		/*
+		 * If the scan descriptor is available on first execution, then we
+		 * need to re-initialize for rescan.
+		 */
+
+		if (!node->ss.ss_currentScanDesc)
+		{
+			node->ss.ss_currentScanDesc =
+				heap_beginscan_parallel(node->ss.ss_currentRelation, node->pscan);
+		}
+		else
+		{
+			heap_parallel_rescan(node->pscan, node->ss.ss_currentScanDesc);
+		}
+
+		node->scan_initialized = true;
+	}
+
+	return ExecScan((ScanState *) node,
+					(ExecScanAccessMtd) PartialSeqNext,
+					(ExecScanRecheckMtd) PartialSeqRecheck);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecEndPartialSeqScan
+ *
+ *		frees any storage allocated through C routines.
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndPartialSeqScan(PartialSeqScanState *node)
+{
+	Relation	relation;
+	HeapScanDesc scanDesc;
+
+	/*
+	 * get information from node
+	 */
+	relation = node->ss.ss_currentRelation;
+	scanDesc = node->ss.ss_currentScanDesc;
+
+	/*
+	 * Free the exprcontext
+	 */
+	ExecFreeExprContext(&node->ss.ps);
+
+	/*
+	 * clean out the tuple table
+	 */
+	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+	ExecClearTuple(node->ss.ss_ScanTupleSlot);
+
+	/*
+	 * close heap scan
+	 */
+	if (scanDesc)
+		heap_endscan(scanDesc);
+
+	/*
+	 * close the heap relation.
+	 */
+	ExecCloseScanRelation(relation);
+}
+
+/* ----------------------------------------------------------------
+ *						Join Support
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------------------------------------------------------
+ *		ExecReScanPartialSeqScan
+ *
+ *		Rescans the relation.
+ * ----------------------------------------------------------------
+ */
+void
+ExecReScanPartialSeqScan(PartialSeqScanState *node)
+{
+	if (node->scan_initialized)
+		node->scan_initialized = false;
+
+	ExecScanReScan((ScanState *) node);
+}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 0b4ab23..1261737 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -384,6 +384,22 @@ _copySeqScan(const SeqScan *from)
 }
 
 /*
+ * _copyPartialSeqScan
+ */
+static PartialSeqScan *
+_copyPartialSeqScan(const SeqScan *from)
+{
+	PartialSeqScan    *newnode = makeNode(PartialSeqScan);
+
+	/*
+	 * copy node superclass fields
+	 */
+	CopyScanFields((const Scan *) from, (Scan *) newnode);
+
+	return newnode;
+}
+
+/*
  * _copySampleScan
  */
 static SampleScan *
@@ -4263,6 +4279,9 @@ copyObject(const void *from)
 		case T_SeqScan:
 			retval = _copySeqScan(from);
 			break;
+		case T_PartialSeqScan:
+			retval = _copyPartialSeqScan(from);
+			break;
 		case T_SampleScan:
 			retval = _copySampleScan(from);
 			break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index df7f6e1..25e780f 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -460,6 +460,14 @@ _outSeqScan(StringInfo str, const SeqScan *node)
 }
 
 static void
+_outPartialSeqScan(StringInfo str, const SeqScan *node)
+{
+	WRITE_NODE_TYPE("PARTIALSEQSCAN");
+
+	_outScanInfo(str, (const Scan *) node);
+}
+
+static void
 _outSampleScan(StringInfo str, const SampleScan *node)
 {
 	WRITE_NODE_TYPE("SAMPLESCAN");
@@ -3019,6 +3027,9 @@ _outNode(StringInfo str, const void *obj)
 			case T_SeqScan:
 				_outSeqScan(str, obj);
 				break;
+			case T_PartialSeqScan:
+				_outPartialSeqScan(str, obj);
+				break;
 			case T_SampleScan:
 				_outSampleScan(str, obj);
 				break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 5802a73..4405f38 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1606,6 +1606,19 @@ _readSeqScan(void)
 }
 
 /*
+ * _readPartialSeqScan
+ */
+static PartialSeqScan *
+_readPartialSeqScan(void)
+{
+	READ_LOCALS_NO_FIELDS(PartialSeqScan);
+
+	ReadCommonScan(local_node);
+
+	READ_DONE();
+}
+
+/*
  * _readSampleScan
  */
 static SampleScan *
@@ -2336,6 +2349,8 @@ parseNodeString(void)
 		return_value = _readScan();
 	else if (MATCH("SEQSCAN", 7))
 		return_value = _readSeqScan();
+	else if (MATCH("PARTIALSEQSCAN", 14))
+		return_value = _readPartialSeqScan();
 	else if (MATCH("SAMPLESCAN", 10))
 		return_value = _readSampleScan();
 	else if (MATCH("INDEXSCAN", 9))
diff --git a/src/backend/optimizer/path/Makefile b/src/backend/optimizer/path/Makefile
index 6864a62..6e462b1 100644
--- a/src/backend/optimizer/path/Makefile
+++ b/src/backend/optimizer/path/Makefile
@@ -13,6 +13,6 @@ top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
 OBJS = allpaths.o clausesel.o costsize.o equivclass.o indxpath.o \
-       joinpath.o joinrels.o pathkeys.o tidpath.o
+       joinpath.o joinrels.o pathkeys.o parallelpath.o tidpath.o
 
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 8fc1cfd..c2ae95d 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -477,6 +477,9 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
 	/* Consider sequential scan */
 	add_path(rel, create_seqscan_path(root, rel, required_outer));
 
+	/* Consider parallel scans */
+	create_parallelscan_paths(root, rel, required_outer);
+
 	/* Consider index scans */
 	create_index_paths(root, rel);
 
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 1b61fd9..3239cec 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -227,6 +227,49 @@ cost_seqscan(Path *path, PlannerInfo *root,
 }
 
 /*
+ * cost_partialseqscan
+ *	  Determines and returns the cost of scanning a relation partially.
+ *
+ * 'baserel' is the relation to be scanned
+ * 'param_info' is the ParamPathInfo if this is a parameterized path, else NULL
+ * 'nworkers' are the number of workers among which the work will be
+ *			distributed
+ */
+void
+cost_partialseqscan(Path *path, PlannerInfo *root,
+					RelOptInfo *baserel, ParamPathInfo *param_info,
+					int nworkers)
+{
+	Cost		startup_cost = 0;
+	Cost		run_cost = 0;
+
+	cost_seqscan(path, root, baserel, param_info);
+
+	startup_cost = path->startup_cost;
+
+	run_cost = path->total_cost - startup_cost;
+
+	/*
+	 * Account for small cost for communication related to scan via the
+	 * ParallelHeapScanDesc.
+	 */
+	run_cost += 0.01;
+
+	/*
+	 * Runtime cost will be equally shared by all workers. Here assumption is
+	 * that disk access cost will also be equally shared between workers which
+	 * is generally true unless there are too many workers working on a
+	 * relatively lesser number of blocks.  If we come across any such case,
+	 * then we can think of changing the current cost model for partial
+	 * sequiantial scan.
+	 */
+	run_cost = run_cost / (nworkers + 1);
+
+	path->startup_cost = startup_cost;
+	path->total_cost = startup_cost + run_cost;
+}
+
+/*
  * cost_samplescan
  *	  Determines and returns the cost of scanning a relation using sampling.
  *
diff --git a/src/backend/optimizer/path/parallelpath.c b/src/backend/optimizer/path/parallelpath.c
new file mode 100644
index 0000000..02d2392
--- /dev/null
+++ b/src/backend/optimizer/path/parallelpath.c
@@ -0,0 +1,132 @@
+/*-------------------------------------------------------------------------
+ *
+ * parallelpath.c
+ *	  Routines to determine parallel paths for scanning a given relation.
+ *
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/optimizer/path/parallelpath.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "optimizer/clauses.h"
+#include "optimizer/cost.h"
+#include "optimizer/pathnode.h"
+#include "optimizer/paths.h"
+#include "parser/parsetree.h"
+#include "utils/rel.h"
+
+
+/*
+ * expr_is_parallel_safe
+ *	  is a paraticular expression parallel safe
+ *
+ * Conditions checked here:
+ *
+ * 1. The expresion must not contain any parallel unsafe or parallel
+ * restricted functions.
+ *
+ * 2. The expression must not contain any initplan or subplan.  We can
+ * probably remove this restriction once we have support of infrastructure
+ * for execution of initplans and subplans at parallel (Gather) nodes.
+ */
+bool
+expr_is_parallel_safe(Node *node)
+{
+	if (check_parallel_safety(node, false))
+		return false;
+
+	if (contain_subplans_or_initplans(node))
+		return false;
+
+	return true;
+}
+
+/*
+ * create_parallelscan_paths
+ *	  Create paths corresponding to parallel scans of the given rel.
+ *	  Currently we only support partial sequential scan.
+ *
+ *	  Candidate paths are added to the rel's pathlist (using add_path).
+ */
+void
+create_parallelscan_paths(PlannerInfo *root, RelOptInfo *rel,
+						  Relids required_outer)
+{
+	int			num_parallel_workers = 0;
+	int			estimated_parallel_workers = 0;
+	Oid			reloid;
+	Relation	relation;
+	Path	   *subpath;
+	ListCell   *l;
+
+	/*
+	 * parallel scan is possible only if user has set parallel_seqscan_degree
+	 * to value greater than 0 and the query is parallel-safe.
+	 */
+	if (max_parallel_degree <= 0 || !root->glob->parallelModeOK)
+		return;
+
+	/*
+	 * There should be atleast a thousand pages to scan for each worker. This
+	 * number is somewhat arbitratry, however we don't want to spawn workers
+	 * to scan smaller relations as that will be costly.
+	 */
+	estimated_parallel_workers = rel->pages / 1000;
+
+	if (estimated_parallel_workers <= 0)
+		return;
+
+	reloid = planner_rt_fetch(rel->relid, root)->relid;
+
+	relation = heap_open(reloid, NoLock);
+
+	/*
+	 * Temporary relations can't be scanned by parallel workers as they are
+	 * visible only to local sessions.
+	 */
+	if (RelationUsesLocalBuffers(relation))
+	{
+		heap_close(relation, NoLock);
+		return;
+	}
+
+	heap_close(relation, NoLock);
+
+	/*
+	 * Allow parallel paths only if all the clauses for relation are parallel
+	 * safe.  We can allow execution of parallel restricted clauses in master
+	 * backend, but for that planner should have infrastructure to pull all
+	 * the parallel restricted clauses from below nodes to the Gather node
+	 * which will then execute such clauses in master backend.
+	 */
+	foreach(l, rel->baserestrictinfo)
+	{
+		RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
+
+		if (!expr_is_parallel_safe((Node *) rinfo->clause))
+			return;
+	}
+
+	num_parallel_workers = Min(max_parallel_degree,
+							   estimated_parallel_workers);
+
+	/*
+	 * Create the partial scan path which each worker backend needs to
+	 * execute.
+	 */
+	subpath = create_partialseqscan_path(root, rel, required_outer,
+										 num_parallel_workers);
+
+	/* Create the funnel path which master backend needs to execute. */
+	add_path(rel, (Path *) create_gather_path(root, rel, subpath,
+											  required_outer,
+											  num_parallel_workers));
+}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 0ee7392..d06a826 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -58,6 +58,8 @@ static Material *create_material_plan(PlannerInfo *root, MaterialPath *best_path
 static Plan *create_unique_plan(PlannerInfo *root, UniquePath *best_path);
 static SeqScan *create_seqscan_plan(PlannerInfo *root, Path *best_path,
 					List *tlist, List *scan_clauses);
+static Scan *create_partialseqscan_plan(PlannerInfo *root, Path *best_path,
+						   List *tlist, List *scan_clauses);
 static SampleScan *create_samplescan_plan(PlannerInfo *root, Path *best_path,
 					   List *tlist, List *scan_clauses);
 static Gather *create_gather_plan(PlannerInfo *root,
@@ -104,6 +106,8 @@ static List *order_qual_clauses(PlannerInfo *root, List *clauses);
 static void copy_path_costsize(Plan *dest, Path *src);
 static void copy_plan_costsize(Plan *dest, Plan *src);
 static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
+static PartialSeqScan *make_partialseqscan(List *qptlist, List *qpqual,
+					Index scanrelid);
 static SampleScan *make_samplescan(List *qptlist, List *qpqual, Index scanrelid,
 				TableSampleClause *tsc);
 static Gather *make_gather(List *qptlist, List *qpqual,
@@ -237,6 +241,7 @@ create_plan_recurse(PlannerInfo *root, Path *best_path)
 	switch (best_path->pathtype)
 	{
 		case T_SeqScan:
+		case T_PartialSeqScan:
 		case T_SampleScan:
 		case T_IndexScan:
 		case T_IndexOnlyScan:
@@ -357,6 +362,13 @@ create_scan_plan(PlannerInfo *root, Path *best_path)
 												scan_clauses);
 			break;
 
+		case T_PartialSeqScan:
+			plan = (Plan *) create_partialseqscan_plan(root,
+													   best_path,
+													   tlist,
+													   scan_clauses);
+			break;
+
 		case T_SampleScan:
 			plan = (Plan *) create_samplescan_plan(root,
 												   best_path,
@@ -567,6 +579,7 @@ disuse_physical_tlist(PlannerInfo *root, Plan *plan, Path *path)
 	switch (path->pathtype)
 	{
 		case T_SeqScan:
+		case T_PartialSeqScan:
 		case T_SampleScan:
 		case T_IndexScan:
 		case T_IndexOnlyScan:
@@ -1184,6 +1197,46 @@ create_seqscan_plan(PlannerInfo *root, Path *best_path,
 }
 
 /*
+ * create_partialseqscan_plan
+ *
+ * Returns a partial seqscan plan for the base relation scanned by
+ * 'best_path' with restriction clauses 'scan_clauses' and targetlist
+ * 'tlist'.
+ */
+static Scan *
+create_partialseqscan_plan(PlannerInfo *root, Path *best_path,
+						   List *tlist, List *scan_clauses)
+{
+	Scan	   *scan_plan;
+	Index		scan_relid = best_path->parent->relid;
+
+	/* it should be a base rel... */
+	Assert(scan_relid > 0);
+	Assert(best_path->parent->rtekind == RTE_RELATION);
+
+	/* Sort clauses into best execution order */
+	scan_clauses = order_qual_clauses(root, scan_clauses);
+
+	/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
+	scan_clauses = extract_actual_clauses(scan_clauses, false);
+
+	/* Replace any outer-relation variables with nestloop params */
+	if (best_path->param_info)
+	{
+		scan_clauses = (List *)
+			replace_nestloop_params(root, (Node *) scan_clauses);
+	}
+
+	scan_plan = (Scan *) make_partialseqscan(tlist,
+											 scan_clauses,
+											 scan_relid);
+
+	copy_path_costsize(&scan_plan->plan, best_path);
+
+	return scan_plan;
+}
+
+/*
  * create_samplescan_plan
  *	 Returns a samplescan plan for the base relation scanned by 'best_path'
  *	 with restriction clauses 'scan_clauses' and targetlist 'tlist'.
@@ -3478,6 +3531,24 @@ make_seqscan(List *qptlist,
 	return node;
 }
 
+static PartialSeqScan *
+make_partialseqscan(List *qptlist,
+					List *qpqual,
+					Index scanrelid)
+{
+	PartialSeqScan *node = makeNode(PartialSeqScan);
+	Plan	   *plan = &node->plan;
+
+	/* cost should be inserted by caller */
+	plan->targetlist = qptlist;
+	plan->qual = qpqual;
+	plan->lefttree = NULL;
+	plan->righttree = NULL;
+	node->scanrelid = scanrelid;
+
+	return node;
+}
+
 static SampleScan *
 make_samplescan(List *qptlist,
 				List *qpqual,
@@ -5169,6 +5240,7 @@ is_projection_capable_plan(Plan *plan)
 		case T_Append:
 		case T_MergeAppend:
 		case T_RecursiveUnion:
+		case T_Gather:
 			return false;
 		default:
 			break;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index e1ee67c..4ebbabf 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -201,13 +201,13 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 	glob->hasRowSecurity = false;
 
 	/*
-	 * Assess whether it's feasible to use parallel mode for this query.
-	 * We can't do this in a standalone backend, or if the command will
-	 * try to modify any data, or if this is a cursor operation, or if any
+	 * Assess whether it's feasible to use parallel mode for this query. We
+	 * can't do this in a standalone backend, or if the command will try to
+	 * modify any data, or if this is a cursor operation, or if any
 	 * parallel-unsafe functions are present in the query tree.
 	 *
-	 * For now, we don't try to use parallel mode if we're running inside
-	 * a parallel worker.  We might eventually be able to relax this
+	 * For now, we don't try to use parallel mode if we're running inside a
+	 * parallel worker.  We might eventually be able to relax this
 	 * restriction, but for now it seems best not to have parallel workers
 	 * trying to create their own parallel workers.
 	 */
@@ -215,7 +215,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 		IsUnderPostmaster && dynamic_shared_memory_type != DSM_IMPL_NONE &&
 		parse->commandType == CMD_SELECT && !parse->hasModifyingCTE &&
 		parse->utilityStmt == NULL && !IsParallelWorker() &&
-		!contain_parallel_unsafe((Node *) parse);
+		!check_parallel_safety((Node *) parse, true);
 
 	/*
 	 * glob->parallelModeOK should tell us whether it's necessary to impose
@@ -228,9 +228,9 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 	 *
 	 * (It's been suggested that we should always impose these restrictions
 	 * whenever glob->parallelModeOK is true, so that it's easier to notice
-	 * incorrectly-labeled functions sooner.  That might be the right thing
-	 * to do, but for now I've taken this approach.  We could also control
-	 * this with a GUC.)
+	 * incorrectly-labeled functions sooner.  That might be the right thing to
+	 * do, but for now I've taken this approach.  We could also control this
+	 * with a GUC.)
 	 *
 	 * FIXME: It's assumed that code further down will set parallelModeNeeded
 	 * to true if a parallel path is actually chosen.  Since the core
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 9392d61..aff78fc 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -447,6 +447,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 	switch (nodeTag(plan))
 	{
 		case T_SeqScan:
+		case T_PartialSeqScan:
 			{
 				SeqScan    *splan = (SeqScan *) plan;
 
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 6b32f85..b85e4f6 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -2234,6 +2234,7 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
 			break;
 
 		case T_SeqScan:
+		case T_PartialSeqScan:
 			context.paramids = bms_add_members(context.paramids, scan_params);
 			break;
 
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index f2c8551..2355cc6 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -87,16 +87,25 @@ typedef struct
 	char	   *prosrc;
 } inline_error_callback_arg;
 
+typedef struct
+{
+	bool		allow_restricted;
+}	check_parallel_safety_arg;
+
 static bool contain_agg_clause_walker(Node *node, void *context);
 static bool count_agg_clauses_walker(Node *node,
 						 count_agg_clauses_context *context);
 static bool find_window_functions_walker(Node *node, WindowFuncLists *lists);
 static bool expression_returns_set_rows_walker(Node *node, double *count);
 static bool contain_subplans_walker(Node *node, void *context);
+static bool contain_subplans_or_initplans_walker(Node *node, void *context);
 static bool contain_mutable_functions_walker(Node *node, void *context);
 static bool contain_volatile_functions_walker(Node *node, void *context);
 static bool contain_volatile_functions_not_nextval_walker(Node *node, void *context);
-static bool contain_parallel_unsafe_walker(Node *node, void *context);
+static bool check_parallel_safety_walker(Node *node,
+							 check_parallel_safety_arg * context);
+static bool parallel_too_dangerous(char proparallel,
+					   check_parallel_safety_arg * context);
 static bool contain_nonstrict_functions_walker(Node *node, void *context);
 static bool contain_leaked_vars_walker(Node *node, void *context);
 static Relids find_nonnullable_rels_walker(Node *node, bool top_level);
@@ -1204,13 +1213,16 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
  *****************************************************************************/
 
 bool
-contain_parallel_unsafe(Node *node)
+check_parallel_safety(Node *node, bool allow_restricted)
 {
-	return contain_parallel_unsafe_walker(node, NULL);
+	check_parallel_safety_arg context;
+
+	context.allow_restricted = allow_restricted;
+	return check_parallel_safety_walker(node, &context);
 }
 
 static bool
-contain_parallel_unsafe_walker(Node *node, void *context)
+check_parallel_safety_walker(Node *node, check_parallel_safety_arg * context)
 {
 	if (node == NULL)
 		return false;
@@ -1218,7 +1230,7 @@ contain_parallel_unsafe_walker(Node *node, void *context)
 	{
 		FuncExpr   *expr = (FuncExpr *) node;
 
-		if (func_parallel(expr->funcid) == PROPARALLEL_UNSAFE)
+		if (parallel_too_dangerous(func_parallel(expr->funcid), context))
 			return true;
 		/* else fall through to check args */
 	}
@@ -1227,7 +1239,7 @@ contain_parallel_unsafe_walker(Node *node, void *context)
 		OpExpr	   *expr = (OpExpr *) node;
 
 		set_opfuncid(expr);
-		if (func_parallel(expr->opfuncid) == PROPARALLEL_UNSAFE)
+		if (parallel_too_dangerous(func_parallel(expr->opfuncid), context))
 			return true;
 		/* else fall through to check args */
 	}
@@ -1236,7 +1248,7 @@ contain_parallel_unsafe_walker(Node *node, void *context)
 		DistinctExpr *expr = (DistinctExpr *) node;
 
 		set_opfuncid((OpExpr *) expr);	/* rely on struct equivalence */
-		if (func_parallel(expr->opfuncid) == PROPARALLEL_UNSAFE)
+		if (parallel_too_dangerous(func_parallel(expr->opfuncid), context))
 			return true;
 		/* else fall through to check args */
 	}
@@ -1245,7 +1257,7 @@ contain_parallel_unsafe_walker(Node *node, void *context)
 		NullIfExpr *expr = (NullIfExpr *) node;
 
 		set_opfuncid((OpExpr *) expr);	/* rely on struct equivalence */
-		if (func_parallel(expr->opfuncid) == PROPARALLEL_UNSAFE)
+		if (parallel_too_dangerous(func_parallel(expr->opfuncid), context))
 			return true;
 		/* else fall through to check args */
 	}
@@ -1254,7 +1266,7 @@ contain_parallel_unsafe_walker(Node *node, void *context)
 		ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
 
 		set_sa_opfuncid(expr);
-		if (func_parallel(expr->opfuncid) == PROPARALLEL_UNSAFE)
+		if (parallel_too_dangerous(func_parallel(expr->opfuncid), context))
 			return true;
 		/* else fall through to check args */
 	}
@@ -1268,12 +1280,12 @@ contain_parallel_unsafe_walker(Node *node, void *context)
 		/* check the result type's input function */
 		getTypeInputInfo(expr->resulttype,
 						 &iofunc, &typioparam);
-		if (func_parallel(iofunc) == PROPARALLEL_UNSAFE)
+		if (parallel_too_dangerous(func_parallel(iofunc), context))
 			return true;
 		/* check the input type's output function */
 		getTypeOutputInfo(exprType((Node *) expr->arg),
 						  &iofunc, &typisvarlena);
-		if (func_parallel(iofunc) == PROPARALLEL_UNSAFE)
+		if (parallel_too_dangerous(func_parallel(iofunc), context))
 			return true;
 		/* else fall through to check args */
 	}
@@ -1282,7 +1294,7 @@ contain_parallel_unsafe_walker(Node *node, void *context)
 		ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
 
 		if (OidIsValid(expr->elemfuncid) &&
-			func_parallel(expr->elemfuncid) == PROPARALLEL_UNSAFE)
+			parallel_too_dangerous(func_parallel(expr->elemfuncid), context))
 			return true;
 		/* else fall through to check args */
 	}
@@ -1294,28 +1306,77 @@ contain_parallel_unsafe_walker(Node *node, void *context)
 
 		foreach(opid, rcexpr->opnos)
 		{
-			if (op_volatile(lfirst_oid(opid)) == PROPARALLEL_UNSAFE)
+			if (parallel_too_dangerous(op_volatile(lfirst_oid(opid)), context))
 				return true;
 		}
 		/* else fall through to check args */
 	}
 	else if (IsA(node, Query))
 	{
-		Query *query = (Query *) node;
+		Query	   *query = (Query *) node;
 
 		if (query->rowMarks != NULL)
 			return true;
 
 		/* Recurse into subselects */
 		return query_tree_walker(query,
-								 contain_parallel_unsafe_walker,
+								 check_parallel_safety_walker,
 								 context, 0);
 	}
 	return expression_tree_walker(node,
-								  contain_parallel_unsafe_walker,
+								  check_parallel_safety_walker,
 								  context);
 }
 
+static bool
+parallel_too_dangerous(char proparallel, check_parallel_safety_arg * context)
+{
+	if (context->allow_restricted)
+		return proparallel == PROPARALLEL_UNSAFE;
+	else
+		return proparallel != PROPARALLEL_SAFE;
+}
+
+/*
+ * contain_subplans_or_initplans
+ *	  Recursively search for initplan or subplan nodes within a clause.
+ *
+ * A special purpose function for prohibiting subplan or initplan clauses
+ * in parallel query constructs.
+ *
+ * If we see any form of SubPlan node, we will return TRUE.  For InitPlan's,
+ * we return true when we see the Param node, apart from that InitPlan
+ * can contain a simple NULL constant for MULTIEXPR subquery (see comments
+ * in make_subplan), however it is okay not to care about the same as that
+ * is only possible for Update statement which is anyway prohibited.
+ *
+ * Returns true if any subplan or initplan is found.
+ */
+bool
+contain_subplans_or_initplans(Node *clause)
+{
+	return contain_subplans_or_initplans_walker(clause, NULL);
+}
+
+static bool
+contain_subplans_or_initplans_walker(Node *node, void *context)
+{
+	if (node == NULL)
+		return false;
+	if (IsA(node, SubPlan) ||
+		IsA(node, AlternativeSubPlan) ||
+		IsA(node, SubLink))
+		return true;			/* abort the tree traversal and return true */
+	else if (IsA(node, Param))
+	{
+		Param	   *paramval = (Param *) node;
+
+		if (paramval->paramkind == PARAM_EXEC)
+			return true;
+	}
+	return expression_tree_walker(node, contain_subplans_or_initplans_walker, context);
+}
+
 /*****************************************************************************
  *		Check clauses for nonstrict functions
  *****************************************************************************/
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 1895a68..2fd7ae5 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -712,6 +712,28 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 }
 
 /*
+ * create_partialseqscan_path
+ *	  Creates a path corresponding to a partial sequential scan, returning the
+ *	  pathnode.
+ */
+Path *
+create_partialseqscan_path(PlannerInfo *root, RelOptInfo *rel,
+						   Relids required_outer, int nworkers)
+{
+	Path	   *pathnode = makeNode(Path);
+
+	pathnode->pathtype = T_PartialSeqScan;
+	pathnode->parent = rel;
+	pathnode->param_info = get_baserel_parampathinfo(root, rel,
+													 required_outer);
+	pathnode->pathkeys = NIL;	/* partialseqscan has unordered result */
+
+	cost_partialseqscan(pathnode, root, rel, pathnode->param_info, nworkers);
+
+	return pathnode;
+}
+
+/*
  * create_samplescan_path
  *	  Creates a path node for a sampled table scan.
  */
diff --git a/src/include/executor/nodePartialSeqscan.h b/src/include/executor/nodePartialSeqscan.h
new file mode 100644
index 0000000..77e5311
--- /dev/null
+++ b/src/include/executor/nodePartialSeqscan.h
@@ -0,0 +1,31 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodePartialSeqscan.h
+ *		prototypes for nodePartialSeqscan.c
+ *
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/executor/nodePartialSeqscan.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef NODEPARTIALSEQSCAN_H
+#define NODEPARTIALSEQSCAN_H
+
+#include "nodes/execnodes.h"
+
+extern void ExecPartialSeqScanEstimate(PartialSeqScanState *node,
+						   ParallelContext *pcxt);
+extern void ExecPartialSeqScanInitializeDSM(PartialSeqScanState *node,
+								ParallelContext *pcxt);
+extern void ExecPartialSeqScanInitParallelScanDesc(PartialSeqScanState *node,
+									   shm_toc *toc);
+extern PartialSeqScanState *ExecInitPartialSeqScan(PartialSeqScan *node,
+					   EState *estate, int eflags);
+extern TupleTableSlot *ExecPartialSeqScan(PartialSeqScanState *node);
+extern void ExecEndPartialSeqScan(PartialSeqScanState *node);
+extern void ExecReScanPartialSeqScan(PartialSeqScanState *node);
+
+#endif   /* NODEPARTIALSEQSCAN_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index b6895f9..05ca049 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -16,6 +16,7 @@
 
 #include "access/genam.h"
 #include "access/heapam.h"
+#include "access/parallel.h"
 #include "executor/instrument.h"
 #include "lib/pairingheap.h"
 #include "nodes/params.h"
@@ -1254,6 +1255,20 @@ typedef struct ScanState
  */
 typedef ScanState SeqScanState;
 
+/*
+ * PartialSeqScanState extends ScanState by storing additional information
+ * related to scan.
+ */
+typedef struct PartialSeqScanState
+{
+	ScanState	ss;				/* its first field is NodeTag */
+	bool		scan_initialized;		/* used to determine if the scan is
+										 * initialized */
+	ParallelHeapScanDesc	pscan;	/* parallel heap scan descriptor
+									 * for partial scan */
+	Size		pscan_len;		/* size of parallel heap scan descriptor */
+} PartialSeqScanState;
+
 /* ----------------
  *	 SampleScanState information
  * ----------------
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 94bdb7c..71496b9 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -51,6 +51,7 @@ typedef enum NodeTag
 	T_BitmapOr,
 	T_Scan,
 	T_SeqScan,
+	T_PartialSeqScan,
 	T_SampleScan,
 	T_IndexScan,
 	T_IndexOnlyScan,
@@ -99,6 +100,7 @@ typedef enum NodeTag
 	T_BitmapOrState,
 	T_ScanState,
 	T_SeqScanState,
+	T_PartialSeqScanState,
 	T_SampleScanState,
 	T_IndexScanState,
 	T_IndexOnlyScanState,
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 1f9213c..a65cd22 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -72,7 +72,7 @@ typedef struct PlannedStmt
 
 	bool		hasRowSecurity; /* row security applied? */
 
-	bool		parallelModeNeeded; /* parallel mode required to execute? */
+	bool		parallelModeNeeded;		/* parallel mode required to execute? */
 } PlannedStmt;
 
 /* macro for fetching the Plan associated with a SubPlan node */
@@ -287,6 +287,12 @@ typedef struct Scan
 typedef Scan SeqScan;
 
 /* ----------------
+ *		partial sequential scan node
+ * ----------------
+ */
+typedef SeqScan PartialSeqScan;
+
+/* ----------------
  *		table sample scan node
  * ----------------
  */
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 5ac79b1..747b05b 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -62,7 +62,8 @@ extern bool contain_subplans(Node *clause);
 extern bool contain_mutable_functions(Node *clause);
 extern bool contain_volatile_functions(Node *clause);
 extern bool contain_volatile_functions_not_nextval(Node *clause);
-extern bool contain_parallel_unsafe(Node *node);
+extern bool check_parallel_safety(Node *node, bool allow_restricted);
+extern bool contain_subplans_or_initplans(Node *clause);
 extern bool contain_nonstrict_functions(Node *clause);
 extern bool contain_leaked_vars(Node *clause);
 
diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h
index 25a7303..8640567 100644
--- a/src/include/optimizer/cost.h
+++ b/src/include/optimizer/cost.h
@@ -73,6 +73,9 @@ extern double index_pages_fetched(double tuples_fetched, BlockNumber pages,
 					double index_pages, PlannerInfo *root);
 extern void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
 			 ParamPathInfo *param_info);
+extern void cost_partialseqscan(Path *path, PlannerInfo *root,
+					RelOptInfo *baserel, ParamPathInfo *param_info,
+					int nworkers);
 extern void cost_samplescan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
 				ParamPathInfo *param_info);
 extern void cost_index(IndexPath *path, PlannerInfo *root,
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 7a4940c..3b97b73 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -32,6 +32,8 @@ extern bool add_path_precheck(RelOptInfo *parent_rel,
 
 extern Path *create_seqscan_path(PlannerInfo *root, RelOptInfo *rel,
 					Relids required_outer);
+extern Path *create_partialseqscan_path(PlannerInfo *root, RelOptInfo *rel,
+						   Relids required_outer, int nworkers);
 extern Path *create_samplescan_path(PlannerInfo *root, RelOptInfo *rel,
 					   Relids required_outer);
 extern IndexPath *create_index_path(PlannerInfo *root,
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 87123a5..6cd4479 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -55,6 +55,15 @@ extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel);
 #endif
 
 /*
+ * parallelpath.c
+ *	  routines to generate parallel scan paths
+ */
+
+extern void create_parallelscan_paths(PlannerInfo *root, RelOptInfo *rel,
+						  Relids required_outer);
+extern bool expr_is_parallel_safe(Node *node);
+
+/*
  * indxpath.c
  *	  routines to generate index paths
  */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index feb821b..5492ba0 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1199,6 +1199,8 @@ OverrideStackEntry
 PACE_HEADER
 PACL
 ParallelExecutorInfo
+PartialSeqScan
+PartialSeqScanState
 PATH
 PBOOL
 PCtxtHandle
