>From e3f764239f6494616137c2c23f8246bec9c52cd4 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Wed, 8 Jul 2015 17:39:47 +0900
Subject: [PATCH 2/5] Change all tuple-returning execution nodes to maintain
 run-state appropriately.

This doesn't change any behavior but maintain run-state to be
consistent with whether returning tuple is null or not at
ExecProcNode.
---
 src/backend/executor/nodeAgg.c             |  6 ++++++
 src/backend/executor/nodeAppend.c          |  7 +++++++
 src/backend/executor/nodeBitmapAnd.c       |  6 ++++++
 src/backend/executor/nodeBitmapHeapscan.c  | 13 ++++++++++++-
 src/backend/executor/nodeBitmapIndexscan.c |  6 ++++++
 src/backend/executor/nodeBitmapOr.c        |  6 ++++++
 src/backend/executor/nodeCtescan.c         | 13 ++++++++++++-
 src/backend/executor/nodeCustom.c          | 15 ++++++++++++++-
 src/backend/executor/nodeForeignscan.c     | 12 +++++++++++-
 src/backend/executor/nodeFunctionscan.c    | 13 ++++++++++++-
 src/backend/executor/nodeGather.c          |  9 +++++++--
 src/backend/executor/nodeGroup.c           |  4 ++--
 src/backend/executor/nodeHash.c            |  6 ++++++
 src/backend/executor/nodeHashjoin.c        | 11 +++++++++++
 src/backend/executor/nodeIndexonlyscan.c   | 16 +++++++++++++++-
 src/backend/executor/nodeIndexscan.c       | 18 ++++++++++++++++--
 src/backend/executor/nodeLimit.c           | 22 ++++++++++++++++++++++
 src/backend/executor/nodeLockRows.c        |  7 +++++++
 src/backend/executor/nodeMaterial.c        |  9 +++++++++
 src/backend/executor/nodeMergeAppend.c     |  5 +++++
 src/backend/executor/nodeMergejoin.c       | 12 +++++++++++-
 src/backend/executor/nodeNestloop.c        |  5 +++++
 src/backend/executor/nodeRecursiveunion.c  |  5 +++++
 src/backend/executor/nodeResult.c          | 12 ++++++++++++
 src/backend/executor/nodeSamplescan.c      | 10 +++++++++-
 src/backend/executor/nodeSeqscan.c         | 11 ++++++++++-
 src/backend/executor/nodeSetOp.c           |  3 +--
 src/backend/executor/nodeSort.c            | 11 +++++++++++
 src/backend/executor/nodeSubqueryscan.c    | 11 ++++++++++-
 src/backend/executor/nodeTidscan.c         | 12 +++++++++++-
 src/backend/executor/nodeUnique.c          |  5 +++++
 src/backend/executor/nodeValuesscan.c      | 12 +++++++++++-
 src/backend/executor/nodeWindowAgg.c       |  3 +--
 src/backend/executor/nodeWorktablescan.c   | 12 +++++++++++-
 src/include/nodes/execnodes.h              | 12 +++++++-----
 35 files changed, 312 insertions(+), 28 deletions(-)

diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 2ef3bdf..ed29e3a 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -1522,6 +1522,8 @@ ExecAgg(AggState *node)
 {
 	TupleTableSlot *result;
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * Check to see if we're still projecting out tuples from a previous agg
 	 * tuple (because there is a function-returning-set in the projection
@@ -1562,6 +1564,7 @@ ExecAgg(AggState *node)
 			return result;
 	}
 
+	SetNodeRunState(node, Done);
 	return NULL;
 }
 
@@ -2961,6 +2964,9 @@ ExecReScanAgg(AggState *node)
 	int			numGroupingSets = Max(node->maxsets, 1);
 	int			setno;
 
+
+	SetNodeRunState(node, Inited);
+
 	node->agg_done = false;
 
 	node->ss.ps.ps_TupFromTlist = false;
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 4718c0f..03b3b66 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -194,6 +194,8 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
 TupleTableSlot *
 ExecAppend(AppendState *node)
 {
+	SetNodeRunState(node, Running);
+
 	for (;;)
 	{
 		PlanState  *subnode;
@@ -229,7 +231,10 @@ ExecAppend(AppendState *node)
 		else
 			node->as_whichplan--;
 		if (!exec_append_initialize_next(node))
+		{
+			SetNodeRunState(node, Done);
 			return ExecClearTuple(node->ps.ps_ResultTupleSlot);
+		}
 
 		/* Else loop back and try to get a tuple from the new subplan */
 	}
@@ -268,6 +273,8 @@ ExecReScanAppend(AppendState *node)
 {
 	int			i;
 
+	SetNodeRunState(node, Inited);
+
 	for (i = 0; i < node->as_nplans; i++)
 	{
 		PlanState  *subnode = node->appendplans[i];
diff --git a/src/backend/executor/nodeBitmapAnd.c b/src/backend/executor/nodeBitmapAnd.c
index 8bc5bbe..64f202e 100644
--- a/src/backend/executor/nodeBitmapAnd.c
+++ b/src/backend/executor/nodeBitmapAnd.c
@@ -105,6 +105,8 @@ MultiExecBitmapAnd(BitmapAndState *node)
 	if (node->ps.instrument)
 		InstrStartNode(node->ps.instrument);
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * get information from the node
 	 */
@@ -146,6 +148,8 @@ MultiExecBitmapAnd(BitmapAndState *node)
 	if (result == NULL)
 		elog(ERROR, "BitmapAnd doesn't support zero inputs");
 
+	SetNodeRunState(node, Done);
+
 	/* must provide our own instrumentation support */
 	if (node->ps.instrument)
 		InstrStopNode(node->ps.instrument, 0 /* XXX */ );
@@ -189,6 +193,8 @@ ExecReScanBitmapAnd(BitmapAndState *node)
 {
 	int			i;
 
+	SetNodeRunState(node, Inited);
+
 	for (i = 0; i < node->nplans; i++)
 	{
 		PlanState  *subnode = node->bitmapplans[i];
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 04ce35a..0dc61ba 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -437,9 +437,18 @@ BitmapHeapRecheck(BitmapHeapScanState *node, TupleTableSlot *slot)
 TupleTableSlot *
 ExecBitmapHeapScan(BitmapHeapScanState *node)
 {
-	return ExecScan(&node->ss,
+	TupleTableSlot *slot;
+
+	SetNodeRunState(node, Running);
+
+	slot = ExecScan(&node->ss,
 					(ExecScanAccessMtd) BitmapHeapNext,
 					(ExecScanRecheckMtd) BitmapHeapRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 /* ----------------------------------------------------------------
@@ -451,6 +460,8 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
 {
 	PlanState  *outerPlan = outerPlanState(node);
 
+	SetNodeRunState(node, Inited);
+
 	/* rescan to release any page pin */
 	heap_rescan(node->ss.ss_currentScanDesc, NULL);
 
diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c
index 613054f..acfce3d 100644
--- a/src/backend/executor/nodeBitmapIndexscan.c
+++ b/src/backend/executor/nodeBitmapIndexscan.c
@@ -44,6 +44,8 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
 	if (node->ss.ps.instrument)
 		InstrStartNode(node->ss.ps.instrument);
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * extract necessary information from index scan node
 	 */
@@ -98,6 +100,8 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
 						 NULL, 0);
 	}
 
+	SetNodeRunState(node, Done);
+
 	/* must provide our own instrumentation support */
 	if (node->ss.ps.instrument)
 		InstrStopNode(node->ss.ps.instrument, nTuples);
@@ -117,6 +121,8 @@ ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
 {
 	ExprContext *econtext = node->biss_RuntimeContext;
 
+	SetNodeRunState(node, Inited);
+
 	/*
 	 * Reset the runtime-key context so we don't leak memory as each outer
 	 * tuple is scanned.  Note this assumes that we will recalculate *all*
diff --git a/src/backend/executor/nodeBitmapOr.c b/src/backend/executor/nodeBitmapOr.c
index fcdaeaf..7a5bcf5 100644
--- a/src/backend/executor/nodeBitmapOr.c
+++ b/src/backend/executor/nodeBitmapOr.c
@@ -106,6 +106,8 @@ MultiExecBitmapOr(BitmapOrState *node)
 	if (node->ps.instrument)
 		InstrStartNode(node->ps.instrument);
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * get information from the node
 	 */
@@ -162,6 +164,8 @@ MultiExecBitmapOr(BitmapOrState *node)
 	if (result == NULL)
 		elog(ERROR, "BitmapOr doesn't support zero inputs");
 
+	SetNodeRunState(node, Done);
+
 	/* must provide our own instrumentation support */
 	if (node->ps.instrument)
 		InstrStopNode(node->ps.instrument, 0 /* XXX */ );
@@ -205,6 +209,8 @@ ExecReScanBitmapOr(BitmapOrState *node)
 {
 	int			i;
 
+	SetNodeRunState(node, Inited);
+
 	for (i = 0; i < node->nplans; i++)
 	{
 		PlanState  *subnode = node->bitmapplans[i];
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index 666ef91..d237370 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -152,9 +152,18 @@ CteScanRecheck(CteScanState *node, TupleTableSlot *slot)
 TupleTableSlot *
 ExecCteScan(CteScanState *node)
 {
-	return ExecScan(&node->ss,
+	TupleTableSlot *slot;
+
+	SetNodeRunState(node, Running);
+
+	slot = ExecScan(&node->ss,
 					(ExecScanAccessMtd) CteScanNext,
 					(ExecScanRecheckMtd) CteScanRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 
@@ -312,6 +321,8 @@ ExecReScanCteScan(CteScanState *node)
 {
 	Tuplestorestate *tuplestorestate = node->leader->cte_table;
 
+	SetNodeRunState(node, Inited);
+
 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
 	ExecScanReScan(&node->ss);
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index e7e3b17..9f85fd7 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -110,8 +110,16 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
 TupleTableSlot *
 ExecCustomScan(CustomScanState *node)
 {
+	TupleTableSlot *slot;
+
 	Assert(node->methods->ExecCustomScan != NULL);
-	return node->methods->ExecCustomScan(node);
+	SetNodeRunState(node, Running);
+	slot = node->methods->ExecCustomScan(node);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 void
@@ -136,6 +144,7 @@ void
 ExecReScanCustomScan(CustomScanState *node)
 {
 	Assert(node->methods->ReScanCustomScan != NULL);
+	SetNodeRunState(node, Inited);
 	node->methods->ReScanCustomScan(node);
 }
 
@@ -158,5 +167,9 @@ ExecCustomRestrPos(CustomScanState *node)
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("custom-scan \"%s\" does not support MarkPos",
 						node->methods->CustomName)));
+
 	node->methods->RestrPosCustomScan(node);
+
+	/* Restoring position in turn restores run state */
+	SetNodeRunState(node, Running);
 }
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 90483e4..895af86 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -100,9 +100,17 @@ ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
 TupleTableSlot *
 ExecForeignScan(ForeignScanState *node)
 {
-	return ExecScan((ScanState *) node,
+	TupleTableSlot * slot;
+
+	SetNodeRunState(node, Running);
+	slot = ExecScan((ScanState *) node,
 					(ExecScanAccessMtd) ForeignNext,
 					(ExecScanRecheckMtd) ForeignRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 
@@ -247,6 +255,8 @@ ExecEndForeignScan(ForeignScanState *node)
 void
 ExecReScanForeignScan(ForeignScanState *node)
 {
+	SetNodeRunState(node, Inited);
+
 	node->fdwroutine->ReScanForeignScan(node);
 
 	ExecScanReScan(&node->ss);
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 849b54f..08f9bbf 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -265,9 +265,18 @@ FunctionRecheck(FunctionScanState *node, TupleTableSlot *slot)
 TupleTableSlot *
 ExecFunctionScan(FunctionScanState *node)
 {
-	return ExecScan(&node->ss,
+	TupleTableSlot *slot;
+
+	SetNodeRunState(node, Running);
+
+	slot = ExecScan(&node->ss,
 					(ExecScanAccessMtd) FunctionNext,
 					(ExecScanRecheckMtd) FunctionRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 /* ----------------------------------------------------------------
@@ -569,6 +578,8 @@ ExecReScanFunctionScan(FunctionScanState *node)
 	int			i;
 	Bitmapset  *chgparam = node->ss.ps.chgParam;
 
+	SetNodeRunState(node, Inited);
+
 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 	for (i = 0; i < node->nfuncs; i++)
 	{
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index 0e71dfc..aceb358 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -135,13 +135,15 @@ ExecGather(GatherState *node)
 	ExprDoneCond isDone;
 	ExprContext *econtext;
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * Initialize the parallel context and workers on first execution. We do
 	 * this on first execution rather than during node initialization, as it
 	 * needs to allocate large dynamic segement, so it is better to do if it
 	 * is really needed.
 	 */
-	if (!ExecNode_is_running(node))
+	if (ExecNode_is_inited(node))
 	{
 		EState	   *estate = node->ps.state;
 		Gather	   *gather = (Gather *) node->ps.plan;
@@ -232,7 +234,10 @@ ExecGather(GatherState *node)
 		 */
 		slot = gather_getnext(node);
 		if (TupIsNull(slot))
+		{
+			SetNodeRunState(node, Done);
 			return NULL;
+		}
 
 		/*
 		 * form the result tuple using ExecProject(), and return it --- unless
@@ -461,6 +466,6 @@ ExecReScanGather(GatherState *node)
 		ExecParallelReinitialize(node->pei);
 
 	SetNodeRunState(node, Inited);
-	
+
 	ExecReScan(node->ps.lefttree);
 }
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index 1a8f669..a593d9f 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -285,6 +285,8 @@ ExecReScanGroup(GroupState *node)
 {
 	PlanState  *outerPlan = outerPlanState(node);
 
+	SetNodeRunState(node, Inited);
+
 	node->ss.ps.ps_TupFromTlist = false;
 	/* must clear first tuple */
 	ExecClearTuple(node->ss.ss_ScanTupleSlot);
@@ -295,6 +297,4 @@ ExecReScanGroup(GroupState *node)
 	 */
 	if (outerPlan->chgParam == NULL)
 		ExecReScan(outerPlan);
-
-	SetNodeRunState(node, Inited);
 }
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index fcbc44e..5a71fe3 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -84,6 +84,8 @@ MultiExecHash(HashState *node)
 	if (node->ps.instrument)
 		InstrStartNode(node->ps.instrument);
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * get state info from node
 	 */
@@ -138,6 +140,8 @@ MultiExecHash(HashState *node)
 	if (hashtable->spaceUsed > hashtable->spacePeak)
 		hashtable->spacePeak = hashtable->spaceUsed;
 
+	SetNodeRunState(node, Done);
+
 	/* must provide our own instrumentation support */
 	if (node->ps.instrument)
 		InstrStopNode(node->ps.instrument, hashtable->totalTuples);
@@ -1270,6 +1274,8 @@ ExecHashTableResetMatchFlags(HashJoinTable hashtable)
 void
 ExecReScanHash(HashState *node)
 {
+	SetNodeRunState(node, Inited);
+
 	/*
 	 * if chgParam of subnode is not null then plan will be re-scanned by
 	 * first ExecProcNode.
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 064421e..dbaabc4 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -72,6 +72,8 @@ ExecHashJoin(HashJoinState *node)
 	uint32		hashvalue;
 	int			batchno;
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * get information from HashJoin node
 	 */
@@ -155,6 +157,7 @@ ExecHashJoin(HashJoinState *node)
 					if (TupIsNull(node->hj_FirstOuterTupleSlot))
 					{
 						node->hj_OuterNotEmpty = false;
+						SetNodeRunState(node, Done);
 						return NULL;
 					}
 					else
@@ -183,7 +186,10 @@ ExecHashJoin(HashJoinState *node)
 				 * outer relation.
 				 */
 				if (hashtable->totalTuples == 0 && !HJ_FILL_OUTER(node))
+				{
+					SetNodeRunState(node, Done);
 					return NULL;
+				}
 
 				/*
 				 * need to remember whether nbatch has increased since we
@@ -414,7 +420,10 @@ ExecHashJoin(HashJoinState *node)
 				 * Try to advance to next batch.  Done if there are no more.
 				 */
 				if (!ExecHashJoinNewBatch(node))
+				{
+					SetNodeRunState(node, Done);
 					return NULL;	/* end of join */
+				}
 				node->hj_JoinState = HJ_NEED_NEW_OUTER;
 				break;
 
@@ -944,6 +953,8 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
 void
 ExecReScanHashJoin(HashJoinState *node)
 {
+	SetNodeRunState(node, Inited);
+
 	/*
 	 * In a multi-batch join, we currently have to do rescans the hard way,
 	 * primarily because batch temp files may have already been released. But
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 0e84314..b3676c9 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -252,15 +252,24 @@ IndexOnlyRecheck(IndexOnlyScanState *node, TupleTableSlot *slot)
 TupleTableSlot *
 ExecIndexOnlyScan(IndexOnlyScanState *node)
 {
+	TupleTableSlot *slot;
+
 	/*
 	 * If we have runtime keys and they've not already been set up, do it now.
 	 */
 	if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
 		ExecReScan((PlanState *) node);
 
-	return ExecScan(&node->ss,
+	SetNodeRunState(node, Running);
+
+	slot = ExecScan(&node->ss,
 					(ExecScanAccessMtd) IndexOnlyNext,
 					(ExecScanRecheckMtd) IndexOnlyRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 /* ----------------------------------------------------------------
@@ -277,6 +286,8 @@ ExecIndexOnlyScan(IndexOnlyScanState *node)
 void
 ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 {
+	SetNodeRunState(node, Inited);
+
 	/*
 	 * If we are doing runtime key calculations (ie, any of the index key
 	 * values weren't simple Consts), compute the new key values.  But first,
@@ -376,6 +387,9 @@ void
 ExecIndexOnlyRestrPos(IndexOnlyScanState *node)
 {
 	index_restrpos(node->ioss_ScanDesc);
+
+	/* Restoring position in turn restores run state */
+	SetNodeRunState(node, Running);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 534d2f4..a343c5c 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -484,20 +484,29 @@ reorderqueue_pop(IndexScanState *node)
 TupleTableSlot *
 ExecIndexScan(IndexScanState *node)
 {
+	TupleTableSlot *slot;
+
 	/*
 	 * If we have runtime keys and they've not already been set up, do it now.
 	 */
 	if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
 		ExecReScan((PlanState *) node);
 
+	SetNodeRunState(node, Running);
+
 	if (node->iss_NumOrderByKeys > 0)
-		return ExecScan(&node->ss,
+		slot = ExecScan(&node->ss,
 						(ExecScanAccessMtd) IndexNextWithReorder,
 						(ExecScanRecheckMtd) IndexRecheck);
 	else
-		return ExecScan(&node->ss,
+		slot = ExecScan(&node->ss,
 						(ExecScanAccessMtd) IndexNext,
 						(ExecScanRecheckMtd) IndexRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 /* ----------------------------------------------------------------
@@ -514,6 +523,8 @@ ExecIndexScan(IndexScanState *node)
 void
 ExecReScanIndexScan(IndexScanState *node)
 {
+	SetNodeRunState(node, Inited);
+
 	/*
 	 * If we are doing runtime key calculations (ie, any of the index key
 	 * values weren't simple Consts), compute the new key values.  But first,
@@ -802,6 +813,9 @@ void
 ExecIndexRestrPos(IndexScanState *node)
 {
 	index_restrpos(node->iss_ScanDesc);
+
+	/* Restoring position in turn restores run state */
+	SetNodeRunState(node, Running);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index 1b675d4..e59d71f 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -43,6 +43,8 @@ ExecLimit(LimitState *node)
 	TupleTableSlot *slot;
 	PlanState  *outerPlan;
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * get information from the node
 	 */
@@ -72,7 +74,10 @@ ExecLimit(LimitState *node)
 			 * If backwards scan, just return NULL without changing state.
 			 */
 			if (!ScanDirectionIsForward(direction))
+			{
+				SetNodeRunState(node, Done);
 				return NULL;
+			}
 
 			/*
 			 * Check for empty window; if so, treat like empty subplan.
@@ -80,6 +85,7 @@ ExecLimit(LimitState *node)
 			if (node->count <= 0 && !node->noCount)
 			{
 				node->lstate = LIMIT_EMPTY;
+				SetNodeRunState(node, Done);
 				return NULL;
 			}
 
@@ -96,6 +102,7 @@ ExecLimit(LimitState *node)
 					 * any output at all.
 					 */
 					node->lstate = LIMIT_EMPTY;
+					SetNodeRunState(node, Done);
 					return NULL;
 				}
 				node->subSlot = slot;
@@ -115,6 +122,7 @@ ExecLimit(LimitState *node)
 			 * The subplan is known to return no tuples (or not more than
 			 * OFFSET tuples, in general).  So we return no tuples.
 			 */
+			SetNodeRunState(node, Done);
 			return NULL;
 
 		case LIMIT_INWINDOW:
@@ -130,6 +138,7 @@ ExecLimit(LimitState *node)
 					node->position - node->offset >= node->count)
 				{
 					node->lstate = LIMIT_WINDOWEND;
+					SetNodeRunState(node, Done);
 					return NULL;
 				}
 
@@ -140,6 +149,7 @@ ExecLimit(LimitState *node)
 				if (TupIsNull(slot))
 				{
 					node->lstate = LIMIT_SUBPLANEOF;
+					SetNodeRunState(node, Done);
 					return NULL;
 				}
 				node->subSlot = slot;
@@ -154,6 +164,7 @@ ExecLimit(LimitState *node)
 				if (node->position <= node->offset + 1)
 				{
 					node->lstate = LIMIT_WINDOWSTART;
+					SetNodeRunState(node, Done);
 					return NULL;
 				}
 
@@ -170,7 +181,10 @@ ExecLimit(LimitState *node)
 
 		case LIMIT_SUBPLANEOF:
 			if (ScanDirectionIsForward(direction))
+			{
+				SetNodeRunState(node, Done);
 				return NULL;
+			}
 
 			/*
 			 * Backing up from subplan EOF, so re-fetch previous tuple; there
@@ -186,7 +200,10 @@ ExecLimit(LimitState *node)
 
 		case LIMIT_WINDOWEND:
 			if (ScanDirectionIsForward(direction))
+			{
+				SetNodeRunState(node, Done);
 				return NULL;
+			}
 
 			/*
 			 * Backing up from window end: simply re-return the last tuple
@@ -199,7 +216,10 @@ ExecLimit(LimitState *node)
 
 		case LIMIT_WINDOWSTART:
 			if (!ScanDirectionIsForward(direction))
+			{
+				SetNodeRunState(node, Done);
 				return NULL;
+			}
 
 			/*
 			 * Advancing after having backed off window start: simply
@@ -443,6 +463,8 @@ ExecEndLimit(LimitState *node)
 void
 ExecReScanLimit(LimitState *node)
 {
+	SetNodeRunState(node, Inited);
+
 	/*
 	 * Recompute limit/offset in case parameters changed, and reset the state
 	 * machine.  We must do this before rescanning our child node, in case
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index eeeca0b..2ccf05d 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -44,6 +44,8 @@ ExecLockRows(LockRowsState *node)
 	bool		epq_needed;
 	ListCell   *lc;
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * get information from the node
 	 */
@@ -57,7 +59,10 @@ lnext:
 	slot = ExecProcNode(outerPlan);
 
 	if (TupIsNull(slot))
+	{
+		SetNodeRunState(node, Done);
 		return NULL;
+	}
 
 	/* We don't need EvalPlanQual unless we get updated tuple version(s) */
 	epq_needed = false;
@@ -460,6 +465,8 @@ ExecEndLockRows(LockRowsState *node)
 void
 ExecReScanLockRows(LockRowsState *node)
 {
+	SetNodeRunState(node, Inited);
+
 	/*
 	 * if chgParam of subnode is not null then plan will be re-scanned by
 	 * first ExecProcNode.
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index d9a67f4..981398a 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -45,6 +45,8 @@ ExecMaterial(MaterialState *node)
 	bool		eof_tuplestore;
 	TupleTableSlot *slot;
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * get state info from node
 	 */
@@ -132,6 +134,7 @@ ExecMaterial(MaterialState *node)
 		if (TupIsNull(outerslot))
 		{
 			node->eof_underlying = true;
+			SetNodeRunState(node, Done);
 			return NULL;
 		}
 
@@ -152,6 +155,7 @@ ExecMaterial(MaterialState *node)
 	/*
 	 * Nothing left ...
 	 */
+	SetNodeRunState(node, Done);
 	return ExecClearTuple(slot);
 }
 
@@ -307,6 +311,9 @@ ExecMaterialRestrPos(MaterialState *node)
 	 * copy the mark to the active read pointer.
 	 */
 	tuplestore_copy_read_pointer(node->tuplestorestate, 1, 0);
+
+	/* Restoring position in turn restores run state */
+	SetNodeRunState(node, Running);
 }
 
 /* ----------------------------------------------------------------
@@ -320,6 +327,8 @@ ExecReScanMaterial(MaterialState *node)
 {
 	PlanState  *outerPlan = outerPlanState(node);
 
+	SetNodeRunState(node, Inited);
+
 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
 	if (node->eflags != 0)
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index 3901255..4678d7c 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -170,6 +170,8 @@ ExecMergeAppend(MergeAppendState *node)
 	TupleTableSlot *result;
 	SlotNumber	i;
 
+	SetNodeRunState(node, Running);
+
 	if (!node->ms_initialized)
 	{
 		/*
@@ -207,6 +209,7 @@ ExecMergeAppend(MergeAppendState *node)
 	{
 		/* All the subplans are exhausted, and so is the heap */
 		result = ExecClearTuple(node->ps.ps_ResultTupleSlot);
+		SetNodeRunState(node, Done);
 	}
 	else
 	{
@@ -289,6 +292,8 @@ ExecReScanMergeAppend(MergeAppendState *node)
 {
 	int			i;
 
+	SetNodeRunState(node, Inited);
+
 	for (i = 0; i < node->ms_nplans; i++)
 	{
 		PlanState  *subnode = node->mergeplans[i];
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 9970db1..74ceaa2 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -630,6 +630,8 @@ ExecMergeJoin(MergeJoinState *node)
 	bool		doFillOuter;
 	bool		doFillInner;
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * get information from node
 	 */
@@ -728,6 +730,7 @@ ExecMergeJoin(MergeJoinState *node)
 							break;
 						}
 						/* Otherwise we're done. */
+						SetNodeRunState(node, Done);
 						return NULL;
 				}
 				break;
@@ -785,6 +788,7 @@ ExecMergeJoin(MergeJoinState *node)
 							break;
 						}
 						/* Otherwise we're done. */
+						SetNodeRunState(node, Done);
 						return NULL;
 				}
 				break;
@@ -1039,6 +1043,7 @@ ExecMergeJoin(MergeJoinState *node)
 							break;
 						}
 						/* Otherwise we're done. */
+						SetNodeRunState(node, Done);
 						return NULL;
 				}
 				break;
@@ -1174,6 +1179,7 @@ ExecMergeJoin(MergeJoinState *node)
 								break;
 							}
 							/* Otherwise we're done. */
+							SetNodeRunState(node, Done);
 							return NULL;
 					}
 				}
@@ -1292,6 +1298,7 @@ ExecMergeJoin(MergeJoinState *node)
 							break;
 						}
 						/* Otherwise we're done. */
+						SetNodeRunState(node, Done);
 						return NULL;
 				}
 				break;
@@ -1362,6 +1369,7 @@ ExecMergeJoin(MergeJoinState *node)
 							break;
 						}
 						/* Otherwise we're done. */
+						SetNodeRunState(node, Done);
 						return NULL;
 				}
 				break;
@@ -1406,6 +1414,7 @@ ExecMergeJoin(MergeJoinState *node)
 				if (TupIsNull(innerTupleSlot))
 				{
 					MJ_printf("ExecMergeJoin: end of inner subplan\n");
+					SetNodeRunState(node, Done);
 					return NULL;
 				}
 
@@ -1448,6 +1457,7 @@ ExecMergeJoin(MergeJoinState *node)
 				if (TupIsNull(outerTupleSlot))
 				{
 					MJ_printf("ExecMergeJoin: end of outer subplan\n");
+					SetNodeRunState(node, Done);
 					return NULL;
 				}
 
@@ -1682,6 +1692,7 @@ ExecEndMergeJoin(MergeJoinState *node)
 void
 ExecReScanMergeJoin(MergeJoinState *node)
 {
+	SetNodeRunState(node, Inited);
 	ExecClearTuple(node->mj_MarkedTupleSlot);
 
 	node->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER;
@@ -1699,5 +1710,4 @@ ExecReScanMergeJoin(MergeJoinState *node)
 		ExecReScan(node->js.ps.lefttree);
 	if (node->js.ps.righttree->chgParam == NULL)
 		ExecReScan(node->js.ps.righttree);
-
 }
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index b4c2f26..ae69176 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -69,6 +69,8 @@ ExecNestLoop(NestLoopState *node)
 	ExprContext *econtext;
 	ListCell   *lc;
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * get information from the node
 	 */
@@ -128,6 +130,7 @@ ExecNestLoop(NestLoopState *node)
 			if (TupIsNull(outerTupleSlot))
 			{
 				ENL1_printf("no outer tuple, ending join");
+				SetNodeRunState(node, Done);
 				return NULL;
 			}
 
@@ -429,6 +432,8 @@ ExecReScanNestLoop(NestLoopState *node)
 {
 	PlanState  *outerPlan = outerPlanState(node);
 
+	SetNodeRunState(node, Inited);
+
 	/*
 	 * If outerPlan->chgParam is not null then plan will be automatically
 	 * re-scanned by first ExecProcNode.
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index 118496e..27a86d3 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -81,6 +81,8 @@ ExecRecursiveUnion(RecursiveUnionState *node)
 	TupleTableSlot *slot;
 	bool		isnew;
 
+	SetNodeRunState(node, Running);
+
 	/* 1. Evaluate non-recursive term */
 	if (!node->recursing)
 	{
@@ -154,6 +156,7 @@ ExecRecursiveUnion(RecursiveUnionState *node)
 		return slot;
 	}
 
+	SetNodeRunState(node, Done);
 	return NULL;
 }
 
@@ -309,6 +312,8 @@ ExecReScanRecursiveUnion(RecursiveUnionState *node)
 	PlanState  *innerPlan = innerPlanState(node);
 	RecursiveUnion *plan = (RecursiveUnion *) node->ps.plan;
 
+	SetNodeRunState(node, Inited);
+
 	/*
 	 * Set recursive term's chgParam to tell it that we'll modify the working
 	 * table and therefore it has to rescan.
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index b4ee402..ec81eda 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -72,6 +72,7 @@ ExecResult(ResultState *node)
 	ExprContext *econtext;
 	ExprDoneCond isDone;
 
+	SetNodeRunState(node, Running);
 	econtext = node->ps.ps_ExprContext;
 
 	/*
@@ -87,6 +88,7 @@ ExecResult(ResultState *node)
 		if (!qualResult)
 		{
 			node->rs_done = true;
+			SetNodeRunState(node, Done);
 			return NULL;
 		}
 	}
@@ -130,7 +132,10 @@ ExecResult(ResultState *node)
 			outerTupleSlot = ExecProcNode(outerPlan);
 
 			if (TupIsNull(outerTupleSlot))
+			{
+				SetNodeRunState(node, Done);
 				return NULL;
+			}
 
 			/*
 			 * prepare to compute projection expressions, which will expect to
@@ -161,6 +166,7 @@ ExecResult(ResultState *node)
 		}
 	}
 
+	SetNodeRunState(node, Done);
 	return NULL;
 }
 
@@ -189,7 +195,12 @@ ExecResultRestrPos(ResultState *node)
 	PlanState  *outerPlan = outerPlanState(node);
 
 	if (outerPlan != NULL)
+	{
 		ExecRestrPos(outerPlan);
+
+		/* Restoring position in turn restores run state */
+		SetNodeRunState(node, Running);
+	}
 	else
 		elog(ERROR, "Result nodes do not support mark/restore");
 }
@@ -295,6 +306,7 @@ ExecEndResult(ResultState *node)
 void
 ExecReScanResult(ResultState *node)
 {
+	SetNodeRunState(node, Inited);
 	node->rs_done = false;
 	node->ps.ps_TupFromTlist = false;
 	node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 0f75110..f46569e 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -98,9 +98,17 @@ SampleRecheck(SampleScanState *node, TupleTableSlot *slot)
 TupleTableSlot *
 ExecSampleScan(SampleScanState *node)
 {
-	return ExecScan((ScanState *) node,
+	TupleTableSlot *slot;
+
+	SetNodeRunState(node, Running);
+	slot = ExecScan((ScanState *) node,
 					(ExecScanAccessMtd) SampleNext,
 					(ExecScanRecheckMtd) SampleRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 0ee33ed..d443c09 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -124,9 +124,17 @@ SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
 TupleTableSlot *
 ExecSeqScan(SeqScanState *node)
 {
-	return ExecScan((ScanState *) node,
+	TupleTableSlot *slot;
+
+	SetNodeRunState(node, Running);
+	slot = ExecScan((ScanState *) node,
 					(ExecScanAccessMtd) SeqNext,
 					(ExecScanRecheckMtd) SeqRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 /* ----------------------------------------------------------------
@@ -275,6 +283,7 @@ ExecReScanSeqScan(SeqScanState *node)
 {
 	HeapScanDesc scan;
 
+	SetNodeRunState(node, Inited);
 	scan = node->ss.ss_currentScanDesc;
 
 	if (scan != NULL)
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 123d051..c248ff3 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -603,6 +603,7 @@ ExecEndSetOp(SetOpState *node)
 void
 ExecReScanSetOp(SetOpState *node)
 {
+	SetNodeRunState(node, Inited);
 	ExecClearTuple(node->ps.ps_ResultTupleSlot);
 	node->numOutput = 0;
 
@@ -653,6 +654,4 @@ ExecReScanSetOp(SetOpState *node)
 	 */
 	if (node->ps.lefttree->chgParam == NULL)
 		ExecReScan(node->ps.lefttree);
-
-	SetNodeRunState(node, Inited);
 }
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index 3ae5b89..a2abec7 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -49,6 +49,8 @@ ExecSort(SortState *node)
 	SO1_printf("ExecSort: %s\n",
 			   "entering routine");
 
+	SetNodeRunState(node, Running);
+
 	estate = node->ss.ps.state;
 	dir = estate->es_direction;
 	tuplesortstate = (Tuplesortstate *) node->tuplesortstate;
@@ -138,6 +140,10 @@ ExecSort(SortState *node)
 	(void) tuplesort_gettupleslot(tuplesortstate,
 								  ScanDirectionIsForward(dir),
 								  slot);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
 	return slot;
 }
 
@@ -282,6 +288,9 @@ ExecSortRestrPos(SortState *node)
 	if (!node->sort_Done)
 		return;
 
+	/* Restoring position in turn restores run state */
+	SetNodeRunState(node, Running);
+
 	/*
 	 * restore the scan to the previously marked position
 	 */
@@ -293,6 +302,8 @@ ExecReScanSort(SortState *node)
 {
 	PlanState  *outerPlan = outerPlanState(node);
 
+	SetNodeRunState(node, Inited);
+
 	/*
 	 * If we haven't sorted yet, just return. If outerplan's chgParam is not
 	 * NULL then it will be re-scanned by ExecProcNode, else no reason to
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index 497d6df..d8799d1 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -90,9 +90,17 @@ SubqueryRecheck(SubqueryScanState *node, TupleTableSlot *slot)
 TupleTableSlot *
 ExecSubqueryScan(SubqueryScanState *node)
 {
-	return ExecScan(&node->ss,
+	TupleTableSlot *slot;
+
+	SetNodeRunState(node, Running);
+	slot = ExecScan(&node->ss,
 					(ExecScanAccessMtd) SubqueryNext,
 					(ExecScanRecheckMtd) SubqueryRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 /* ----------------------------------------------------------------
@@ -199,6 +207,7 @@ ExecEndSubqueryScan(SubqueryScanState *node)
 void
 ExecReScanSubqueryScan(SubqueryScanState *node)
 {
+	SetNodeRunState(node, Inited);
 	ExecScanReScan(&node->ss);
 
 	/*
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index f19e735..724016d 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -390,9 +390,17 @@ TidRecheck(TidScanState *node, TupleTableSlot *slot)
 TupleTableSlot *
 ExecTidScan(TidScanState *node)
 {
-	return ExecScan(&node->ss,
+	TupleTableSlot *slot;
+
+	SetNodeRunState(node, Running);
+	slot = ExecScan(&node->ss,
 					(ExecScanAccessMtd) TidNext,
 					(ExecScanRecheckMtd) TidRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 /* ----------------------------------------------------------------
@@ -402,6 +410,8 @@ ExecTidScan(TidScanState *node)
 void
 ExecReScanTidScan(TidScanState *node)
 {
+	SetNodeRunState(node, Inited);
+
 	if (node->tss_TidList)
 		pfree(node->tss_TidList);
 	node->tss_TidList = NULL;
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index f259f32..1f7ca10 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -50,6 +50,8 @@ ExecUnique(UniqueState *node)
 	TupleTableSlot *slot;
 	PlanState  *outerPlan;
 
+	SetNodeRunState(node, Running);
+
 	/*
 	 * get information from the node
 	 */
@@ -71,6 +73,7 @@ ExecUnique(UniqueState *node)
 		{
 			/* end of subplan, so we're done */
 			ExecClearTuple(resultTupleSlot);
+			SetNodeRunState(node, Done);
 			return NULL;
 		}
 
@@ -187,6 +190,8 @@ ExecEndUnique(UniqueState *node)
 void
 ExecReScanUnique(UniqueState *node)
 {
+	SetNodeRunState(node, Inited);
+
 	/* must clear result tuple so first input tuple is returned */
 	ExecClearTuple(node->ps.ps_ResultTupleSlot);
 
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index c56199c..48d1ad8 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -175,9 +175,18 @@ ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
 TupleTableSlot *
 ExecValuesScan(ValuesScanState *node)
 {
-	return ExecScan(&node->ss,
+	TupleTableSlot *slot;
+
+	/* Advance the state to running if just after initialized */
+	SetNodeRunState(node, Running);
+	slot = ExecScan(&node->ss,
 					(ExecScanAccessMtd) ValuesNext,
 					(ExecScanRecheckMtd) ValuesRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 /* ----------------------------------------------------------------
@@ -302,6 +311,7 @@ ExecEndValuesScan(ValuesScanState *node)
 void
 ExecReScanValuesScan(ValuesScanState *node)
 {
+	SetNodeRunState(node, Inited);
 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
 	ExecScanReScan(&node->ss);
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 8734e8e..0d127b4 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -2064,6 +2064,7 @@ ExecReScanWindowAgg(WindowAggState *node)
 	PlanState  *outerPlan = outerPlanState(node);
 	ExprContext *econtext = node->ss.ps.ps_ExprContext;
 
+	SetNodeRunState(node, Inited);
 	node->ss.ps.ps_TupFromTlist = false;
 	node->all_first = true;
 
@@ -2087,8 +2088,6 @@ ExecReScanWindowAgg(WindowAggState *node)
 	 */
 	if (outerPlan->chgParam == NULL)
 		ExecReScan(outerPlan);
-
-	SetNodeRunState(node, Inited);
 }
 
 /*
diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c
index 799e96b..46350ab 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -80,6 +80,10 @@ WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
 TupleTableSlot *
 ExecWorkTableScan(WorkTableScanState *node)
 {
+	TupleTableSlot *slot;
+
+	SetNodeRunState(node, Running);
+
 	/*
 	 * On the first call, find the ancestor RecursiveUnion's state via the
 	 * Param slot reserved for it.  (We can't do this during node init because
@@ -114,9 +118,14 @@ ExecWorkTableScan(WorkTableScanState *node)
 		ExecAssignScanProjectionInfo(&node->ss);
 	}
 
-	return ExecScan(&node->ss,
+	slot = ExecScan(&node->ss,
 					(ExecScanAccessMtd) WorkTableScanNext,
 					(ExecScanRecheckMtd) WorkTableScanRecheck);
+
+	if (TupIsNull(slot))
+		SetNodeRunState(node, Done);
+
+	return slot;
 }
 
 
@@ -210,6 +219,7 @@ ExecEndWorkTableScan(WorkTableScanState *node)
 void
 ExecReScanWorkTableScan(WorkTableScanState *node)
 {
+	SetNodeRunState(node, Inited);
 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
 	ExecScanReScan(&node->ss);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 4527a98..ee706fc 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -355,14 +355,16 @@ typedef enum ExecNodeRunState
 	ERunState_Done			/* No tuple to return  */
 } ExecNodeRunState;
 
-#define SetNodeRunState(nd,st) (((PlanState*)nd)->runstate = (ERunState_##st))
+#define SetNodeRunState(nd,st) (((PlanState*)(nd))->runstate = (ERunState_##st))
+#define ExecNode_is(nd,st) (((PlanState*)(nd))->runstate == (ERunState_##st))
+#define ExecNode_is_inited(nd)	(ExecNode_is((nd),Inited))
+#define ExecNode_is_running(nd)	(ExecNode_is((nd),Running))
+#define ExecNode_is_done(nd) (ExecNode_is((nd),Done))
 #define AdvanceNodeRunStateTo(nd,st) \
 	do {\
-		if (((PlanState*)nd)->runstate < (ERunState_##st))\
-			((PlanState*)nd)->runstate = (ERunState_##st);\
+		if (((PlanState*)(nd))->runstate < (ERunState_##st))\
+			((PlanState*)(nd))->runstate = (ERunState_##st);\
 	} while(0);
-#define ExecNode_is_running(nd)	(((PlanState*)nd)->runstate == ERunState_Running)
-#define ExecNode_is_done(nd)	(((PlanState*)nd)->runstate == ERunState_Done)
 
 /* ----------------
  *	  EState information
-- 
1.8.3.1

