From 1c8d3fa278824ba83043aa106d35419f6824ab3f Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Fri, 6 May 2016 13:01:48 -0400
Subject: [PATCH 2/3] Modify PlanState to have result/result_ready fields.
 Modify executor to use them instead of returning tuples directly.

---
 src/backend/executor/execProcnode.c       | 75 ++++++++++++++++++-------------
 src/backend/executor/execScan.c           | 26 +++++++----
 src/backend/executor/nodeAgg.c            | 13 +++---
 src/backend/executor/nodeAppend.c         | 11 +++--
 src/backend/executor/nodeBitmapHeapscan.c |  2 +-
 src/backend/executor/nodeCtescan.c        |  2 +-
 src/backend/executor/nodeCustom.c         |  4 +-
 src/backend/executor/nodeForeignscan.c    |  2 +-
 src/backend/executor/nodeFunctionscan.c   |  2 +-
 src/backend/executor/nodeGather.c         | 17 ++++---
 src/backend/executor/nodeGroup.c          | 24 +++++++---
 src/backend/executor/nodeHash.c           |  3 +-
 src/backend/executor/nodeHashjoin.c       | 29 ++++++++----
 src/backend/executor/nodeIndexonlyscan.c  |  2 +-
 src/backend/executor/nodeIndexscan.c      |  2 +-
 src/backend/executor/nodeLimit.c          | 42 ++++++++++++-----
 src/backend/executor/nodeLockRows.c       |  9 ++--
 src/backend/executor/nodeMaterial.c       | 21 ++++++---
 src/backend/executor/nodeMergeAppend.c    |  4 +-
 src/backend/executor/nodeMergejoin.c      | 74 ++++++++++++++++++++++--------
 src/backend/executor/nodeModifyTable.c    | 15 ++++---
 src/backend/executor/nodeNestloop.c       | 16 ++++---
 src/backend/executor/nodeRecursiveunion.c | 10 +++--
 src/backend/executor/nodeResult.c         | 20 ++++++---
 src/backend/executor/nodeSamplescan.c     |  2 +-
 src/backend/executor/nodeSeqscan.c        |  2 +-
 src/backend/executor/nodeSetOp.c          | 14 +++---
 src/backend/executor/nodeSort.c           |  4 +-
 src/backend/executor/nodeSubqueryscan.c   |  2 +-
 src/backend/executor/nodeTidscan.c        |  2 +-
 src/backend/executor/nodeUnique.c         |  8 ++--
 src/backend/executor/nodeValuesscan.c     |  2 +-
 src/backend/executor/nodeWindowAgg.c      | 17 ++++---
 src/backend/executor/nodeWorktablescan.c  |  2 +-
 src/include/executor/executor.h           | 11 ++++-
 src/include/executor/nodeAgg.h            |  2 +-
 src/include/executor/nodeAppend.h         |  2 +-
 src/include/executor/nodeBitmapHeapscan.h |  2 +-
 src/include/executor/nodeCtescan.h        |  2 +-
 src/include/executor/nodeCustom.h         |  2 +-
 src/include/executor/nodeForeignscan.h    |  2 +-
 src/include/executor/nodeFunctionscan.h   |  2 +-
 src/include/executor/nodeGather.h         |  2 +-
 src/include/executor/nodeGroup.h          |  2 +-
 src/include/executor/nodeHash.h           |  2 +-
 src/include/executor/nodeHashjoin.h       |  2 +-
 src/include/executor/nodeIndexonlyscan.h  |  2 +-
 src/include/executor/nodeIndexscan.h      |  2 +-
 src/include/executor/nodeLimit.h          |  2 +-
 src/include/executor/nodeLockRows.h       |  2 +-
 src/include/executor/nodeMaterial.h       |  2 +-
 src/include/executor/nodeMergeAppend.h    |  2 +-
 src/include/executor/nodeMergejoin.h      |  2 +-
 src/include/executor/nodeModifyTable.h    |  2 +-
 src/include/executor/nodeNestloop.h       |  2 +-
 src/include/executor/nodeRecursiveunion.h |  2 +-
 src/include/executor/nodeResult.h         |  2 +-
 src/include/executor/nodeSamplescan.h     |  2 +-
 src/include/executor/nodeSeqscan.h        |  2 +-
 src/include/executor/nodeSetOp.h          |  2 +-
 src/include/executor/nodeSort.h           |  2 +-
 src/include/executor/nodeSubqueryscan.h   |  2 +-
 src/include/executor/nodeTidscan.h        |  2 +-
 src/include/executor/nodeUnique.h         |  2 +-
 src/include/executor/nodeValuesscan.h     |  2 +-
 src/include/executor/nodeWindowAgg.h      |  2 +-
 src/include/executor/nodeWorktablescan.h  |  2 +-
 src/include/nodes/execnodes.h             |  2 +
 68 files changed, 360 insertions(+), 197 deletions(-)

diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 680ca4b..3f2ebff 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -380,6 +380,9 @@ ExecProcNode(PlanState *node)
 
 	CHECK_FOR_INTERRUPTS();
 
+	/* mark any previous result as having been consumed */
+	node->result_ready = false;
+
 	if (node->chgParam != NULL) /* something changed */
 		ExecReScan(node);		/* let ReScan handle this */
 
@@ -392,23 +395,23 @@ ExecProcNode(PlanState *node)
 			 * control nodes
 			 */
 		case T_ResultState:
-			result = ExecResult((ResultState *) node);
+			ExecResult((ResultState *) node);
 			break;
 
 		case T_ModifyTableState:
-			result = ExecModifyTable((ModifyTableState *) node);
+			ExecModifyTable((ModifyTableState *) node);
 			break;
 
 		case T_AppendState:
-			result = ExecAppend((AppendState *) node);
+			ExecAppend((AppendState *) node);
 			break;
 
 		case T_MergeAppendState:
-			result = ExecMergeAppend((MergeAppendState *) node);
+			ExecMergeAppend((MergeAppendState *) node);
 			break;
 
 		case T_RecursiveUnionState:
-			result = ExecRecursiveUnion((RecursiveUnionState *) node);
+			ExecRecursiveUnion((RecursiveUnionState *) node);
 			break;
 
 			/* BitmapAndState does not yield tuples */
@@ -419,119 +422,119 @@ ExecProcNode(PlanState *node)
 			 * scan nodes
 			 */
 		case T_SeqScanState:
-			result = ExecSeqScan((SeqScanState *) node);
+			ExecSeqScan((SeqScanState *) node);
 			break;
 
 		case T_SampleScanState:
-			result = ExecSampleScan((SampleScanState *) node);
+			ExecSampleScan((SampleScanState *) node);
 			break;
 
 		case T_IndexScanState:
-			result = ExecIndexScan((IndexScanState *) node);
+			ExecIndexScan((IndexScanState *) node);
 			break;
 
 		case T_IndexOnlyScanState:
-			result = ExecIndexOnlyScan((IndexOnlyScanState *) node);
+			ExecIndexOnlyScan((IndexOnlyScanState *) node);
 			break;
 
 			/* BitmapIndexScanState does not yield tuples */
 
 		case T_BitmapHeapScanState:
-			result = ExecBitmapHeapScan((BitmapHeapScanState *) node);
+			ExecBitmapHeapScan((BitmapHeapScanState *) node);
 			break;
 
 		case T_TidScanState:
-			result = ExecTidScan((TidScanState *) node);
+			ExecTidScan((TidScanState *) node);
 			break;
 
 		case T_SubqueryScanState:
-			result = ExecSubqueryScan((SubqueryScanState *) node);
+			ExecSubqueryScan((SubqueryScanState *) node);
 			break;
 
 		case T_FunctionScanState:
-			result = ExecFunctionScan((FunctionScanState *) node);
+			ExecFunctionScan((FunctionScanState *) node);
 			break;
 
 		case T_ValuesScanState:
-			result = ExecValuesScan((ValuesScanState *) node);
+			ExecValuesScan((ValuesScanState *) node);
 			break;
 
 		case T_CteScanState:
-			result = ExecCteScan((CteScanState *) node);
+			ExecCteScan((CteScanState *) node);
 			break;
 
 		case T_WorkTableScanState:
-			result = ExecWorkTableScan((WorkTableScanState *) node);
+			ExecWorkTableScan((WorkTableScanState *) node);
 			break;
 
 		case T_ForeignScanState:
-			result = ExecForeignScan((ForeignScanState *) node);
+			ExecForeignScan((ForeignScanState *) node);
 			break;
 
 		case T_CustomScanState:
-			result = ExecCustomScan((CustomScanState *) node);
+			ExecCustomScan((CustomScanState *) node);
 			break;
 
 			/*
 			 * join nodes
 			 */
 		case T_NestLoopState:
-			result = ExecNestLoop((NestLoopState *) node);
+			ExecNestLoop((NestLoopState *) node);
 			break;
 
 		case T_MergeJoinState:
-			result = ExecMergeJoin((MergeJoinState *) node);
+			ExecMergeJoin((MergeJoinState *) node);
 			break;
 
 		case T_HashJoinState:
-			result = ExecHashJoin((HashJoinState *) node);
+			ExecHashJoin((HashJoinState *) node);
 			break;
 
 			/*
 			 * materialization nodes
 			 */
 		case T_MaterialState:
-			result = ExecMaterial((MaterialState *) node);
+			ExecMaterial((MaterialState *) node);
 			break;
 
 		case T_SortState:
-			result = ExecSort((SortState *) node);
+			ExecSort((SortState *) node);
 			break;
 
 		case T_GroupState:
-			result = ExecGroup((GroupState *) node);
+			ExecGroup((GroupState *) node);
 			break;
 
 		case T_AggState:
-			result = ExecAgg((AggState *) node);
+			ExecAgg((AggState *) node);
 			break;
 
 		case T_WindowAggState:
-			result = ExecWindowAgg((WindowAggState *) node);
+			ExecWindowAgg((WindowAggState *) node);
 			break;
 
 		case T_UniqueState:
-			result = ExecUnique((UniqueState *) node);
+			ExecUnique((UniqueState *) node);
 			break;
 
 		case T_GatherState:
-			result = ExecGather((GatherState *) node);
+			ExecGather((GatherState *) node);
 			break;
 
 		case T_HashState:
-			result = ExecHash((HashState *) node);
+			ExecHash((HashState *) node);
 			break;
 
 		case T_SetOpState:
-			result = ExecSetOp((SetOpState *) node);
+			ExecSetOp((SetOpState *) node);
 			break;
 
 		case T_LockRowsState:
-			result = ExecLockRows((LockRowsState *) node);
+			ExecLockRows((LockRowsState *) node);
 			break;
 
 		case T_LimitState:
-			result = ExecLimit((LimitState *) node);
+			ExecLimit((LimitState *) node);
 			break;
 
 		default:
@@ -540,6 +543,14 @@ ExecProcNode(PlanState *node)
 			break;
 	}
 
+	/* We don't support asynchronous execution yet. */
+	Assert(node->result_ready);
+
+	/* Result should be a TupleTableSlot, unless it's NULL. */
+	Assert(node->result == NULL || IsA(node->result, TupleTableSlot));
+
+	result = (TupleTableSlot *) node->result;
+
 	if (node->instrument)
 		InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
 
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index fb0013d..095d40b 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -99,7 +99,7 @@ ExecScanFetch(ScanState *node,
  *		ExecScan
  *
  *		Scans the relation using the 'access method' indicated and
- *		returns the next qualifying tuple in the direction specified
+ *		produces the next qualifying tuple in the direction specified
  *		in the global variable ExecDirection.
  *		The access method returns the next tuple and ExecScan() is
  *		responsible for checking the tuple returned against the qual-clause.
@@ -117,7 +117,7 @@ ExecScanFetch(ScanState *node,
  *			 "cursor" is positioned before the first qualifying tuple.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecScan(ScanState *node,
 		 ExecScanAccessMtd accessMtd,	/* function returning a tuple */
 		 ExecScanRecheckMtd recheckMtd)
@@ -137,12 +137,14 @@ ExecScan(ScanState *node,
 
 	/*
 	 * If we have neither a qual to check nor a projection to do, just skip
-	 * all the overhead and return the raw scan tuple.
+	 * all the overhead and produce the raw scan tuple.
 	 */
 	if (!qual && !projInfo)
 	{
 		ResetExprContext(econtext);
-		return ExecScanFetch(node, accessMtd, recheckMtd);
+		ExecReturnTuple(&node->ps,
+						ExecScanFetch(node, accessMtd, recheckMtd));
+		return;
 	}
 
 	/*
@@ -155,7 +157,10 @@ ExecScan(ScanState *node,
 		Assert(projInfo);		/* can't get here if not projecting */
 		resultSlot = ExecProject(projInfo, &isDone);
 		if (isDone == ExprMultipleResult)
-			return resultSlot;
+		{
+			ExecReturnTuple(&node->ps, resultSlot);
+			return;
+		}
 		/* Done with that source tuple... */
 		node->ps.ps_TupFromTlist = false;
 	}
@@ -188,9 +193,10 @@ ExecScan(ScanState *node,
 		if (TupIsNull(slot))
 		{
 			if (projInfo)
-				return ExecClearTuple(projInfo->pi_slot);
+				ExecReturnTuple(&node->ps, ExecClearTuple(projInfo->pi_slot));
 			else
-				return slot;
+				ExecReturnTuple(&node->ps, slot);
+			return;
 		}
 
 		/*
@@ -221,7 +227,8 @@ ExecScan(ScanState *node,
 				if (isDone != ExprEndResult)
 				{
 					node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-					return resultSlot;
+					ExecReturnTuple(&node->ps, resultSlot);
+					return;
 				}
 			}
 			else
@@ -229,7 +236,8 @@ ExecScan(ScanState *node,
 				/*
 				 * Here, we aren't projecting, so just return scan tuple.
 				 */
-				return slot;
+				ExecReturnTuple(&node->ps, slot);
+				return;
 			}
 		}
 		else
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index e37551e..b23065d 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -1816,7 +1816,7 @@ lookup_hash_entry(AggState *aggstate, TupleTableSlot *inputslot)
  *	  stored in the expression context to be used when ExecProject evaluates
  *	  the result tuple.
  */
-TupleTableSlot *
+void
 ExecAgg(AggState *node)
 {
 	TupleTableSlot *result;
@@ -1832,7 +1832,10 @@ ExecAgg(AggState *node)
 
 		result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
 		if (isDone == ExprMultipleResult)
-			return result;
+		{
+			ExecReturnTuple(&node->ss.ps, result);
+			return;
+		}
 		/* Done with that source tuple... */
 		node->ss.ps.ps_TupFromTlist = false;
 	}
@@ -1842,6 +1845,7 @@ ExecAgg(AggState *node)
 	 * agg_done gets set before we emit the final aggregate tuple, and we have
 	 * to finish running SRFs for it.)
 	 */
+	result = NULL;
 	if (!node->agg_done)
 	{
 		/* Dispatch based on strategy */
@@ -1856,12 +1860,9 @@ ExecAgg(AggState *node)
 				result = agg_retrieve_direct(node);
 				break;
 		}
-
-		if (!TupIsNull(result))
-			return result;
 	}
 
-	return NULL;
+	ExecReturnTuple(&node->ss.ps, result);
 }
 
 /*
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index beb4ab8..e0ce8c6 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -191,7 +191,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
  *		Handles iteration over multiple subplans.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecAppend(AppendState *node)
 {
 	for (;;)
@@ -216,7 +216,8 @@ ExecAppend(AppendState *node)
 			 * NOT make use of the result slot that was set up in
 			 * ExecInitAppend; there's no need for it.
 			 */
-			return result;
+			ExecReturnTuple(&node->ps, result);
+			return;
 		}
 
 		/*
@@ -229,7 +230,11 @@ ExecAppend(AppendState *node)
 		else
 			node->as_whichplan--;
 		if (!exec_append_initialize_next(node))
-			return ExecClearTuple(node->ps.ps_ResultTupleSlot);
+		{
+			ExecReturnTuple(&node->ps,
+							ExecClearTuple(node->ps.ps_ResultTupleSlot));
+			return;
+		}
 
 		/* Else loop back and try to get a tuple from the new subplan */
 	}
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 2ba5cd0..31133ff 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -434,7 +434,7 @@ BitmapHeapRecheck(BitmapHeapScanState *node, TupleTableSlot *slot)
  *		ExecBitmapHeapScan(node)
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecBitmapHeapScan(BitmapHeapScanState *node)
 {
 	return ExecScan(&node->ss,
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index 3c2f684..1f1fdf5 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -149,7 +149,7 @@ CteScanRecheck(CteScanState *node, TupleTableSlot *slot)
  *		access method functions.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecCteScan(CteScanState *node)
 {
 	return ExecScan(&node->ss,
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index 322abca..7162348 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -107,11 +107,11 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
 	return css;
 }
 
-TupleTableSlot *
+void
 ExecCustomScan(CustomScanState *node)
 {
 	Assert(node->methods->ExecCustomScan != NULL);
-	return node->methods->ExecCustomScan(node);
+	ExecReturnTuple(&node->ss.ps, node->methods->ExecCustomScan(node));
 }
 
 void
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 8418c5a..13f0c3a 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -113,7 +113,7 @@ ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
  *		access method functions.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecForeignScan(ForeignScanState *node)
 {
 	return ExecScan((ScanState *) node,
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index a03f6e7..3cccd8f 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -262,7 +262,7 @@ FunctionRecheck(FunctionScanState *node, TupleTableSlot *slot)
  *		access method functions.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecFunctionScan(FunctionScanState *node)
 {
 	return ExecScan(&node->ss,
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index 2ac0c8d..a4d3a16 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -126,7 +126,7 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
  *		the next qualifying tuple.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecGather(GatherState *node)
 {
 	TupleTableSlot *fslot = node->funnel_slot;
@@ -207,7 +207,10 @@ ExecGather(GatherState *node)
 	{
 		resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
 		if (isDone == ExprMultipleResult)
-			return resultSlot;
+		{
+			ExecReturnTuple(&node->ps, resultSlot);
+			return;
+		}
 		/* Done with that source tuple... */
 		node->ps.ps_TupFromTlist = false;
 	}
@@ -229,7 +232,10 @@ ExecGather(GatherState *node)
 		 */
 		slot = gather_getnext(node);
 		if (TupIsNull(slot))
-			return NULL;
+		{
+			ExecReturnTuple(&node->ps, NULL);
+			return;
+		}
 
 		/*
 		 * form the result tuple using ExecProject(), and return it --- unless
@@ -242,11 +248,12 @@ ExecGather(GatherState *node)
 		if (isDone != ExprEndResult)
 		{
 			node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-			return resultSlot;
+			ExecReturnTuple(&node->ps, resultSlot);
+			return;
 		}
 	}
 
-	return slot;
+	ExecReturnTuple(&node->ps, slot);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index 3c066fc..f33a316 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -31,7 +31,7 @@
  *
  *		Return one tuple for each group of matching input tuples.
  */
-TupleTableSlot *
+void
 ExecGroup(GroupState *node)
 {
 	ExprContext *econtext;
@@ -44,7 +44,10 @@ ExecGroup(GroupState *node)
 	 * get state info from node
 	 */
 	if (node->grp_done)
-		return NULL;
+	{
+		ExecReturnTuple(&node->ss.ps, NULL);
+		return;
+	}
 	econtext = node->ss.ps.ps_ExprContext;
 	numCols = ((Group *) node->ss.ps.plan)->numCols;
 	grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
@@ -61,7 +64,10 @@ ExecGroup(GroupState *node)
 
 		result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
 		if (isDone == ExprMultipleResult)
-			return result;
+		{
+			ExecReturnTuple(&node->ss.ps, result);
+			return;
+		}
 		/* Done with that source tuple... */
 		node->ss.ps.ps_TupFromTlist = false;
 	}
@@ -87,7 +93,8 @@ ExecGroup(GroupState *node)
 		{
 			/* empty input, so return nothing */
 			node->grp_done = TRUE;
-			return NULL;
+			ExecReturnTuple(&node->ss.ps, NULL);
+			return;
 		}
 		/* Copy tuple into firsttupleslot */
 		ExecCopySlot(firsttupleslot, outerslot);
@@ -115,7 +122,8 @@ ExecGroup(GroupState *node)
 			if (isDone != ExprEndResult)
 			{
 				node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-				return result;
+				ExecReturnTuple(&node->ss.ps, result);
+				return;
 			}
 		}
 		else
@@ -139,7 +147,8 @@ ExecGroup(GroupState *node)
 			{
 				/* no more groups, so we're done */
 				node->grp_done = TRUE;
-				return NULL;
+				ExecReturnTuple(&node->ss.ps, NULL);
+				return;
 			}
 
 			/*
@@ -178,7 +187,8 @@ ExecGroup(GroupState *node)
 			if (isDone != ExprEndResult)
 			{
 				node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-				return result;
+				ExecReturnTuple(&node->ss.ps, result);
+				return;
 			}
 		}
 		else
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 5e78de0..905eb30 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -56,11 +56,10 @@ static void *dense_alloc(HashJoinTable hashtable, Size size);
  *		stub for pro forma compliance
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecHash(HashState *node)
 {
 	elog(ERROR, "Hash node does not support ExecProcNode call convention");
-	return NULL;
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index a7a908a..cc92fc3 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -58,7 +58,7 @@ static bool ExecHashJoinNewBatch(HashJoinState *hjstate);
  *			  the other one is "outer".
  * ----------------------------------------------------------------
  */
-TupleTableSlot *				/* return: a tuple or NULL */
+void
 ExecHashJoin(HashJoinState *node)
 {
 	PlanState  *outerNode;
@@ -93,7 +93,10 @@ ExecHashJoin(HashJoinState *node)
 
 		result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
 		if (isDone == ExprMultipleResult)
-			return result;
+		{
+			ExecReturnTuple(&node->js.ps, result);
+			return;
+		}
 		/* Done with that source tuple... */
 		node->js.ps.ps_TupFromTlist = false;
 	}
@@ -155,7 +158,8 @@ ExecHashJoin(HashJoinState *node)
 					if (TupIsNull(node->hj_FirstOuterTupleSlot))
 					{
 						node->hj_OuterNotEmpty = false;
-						return NULL;
+						ExecReturnTuple(&node->js.ps, NULL);
+						return;
 					}
 					else
 						node->hj_OuterNotEmpty = true;
@@ -183,7 +187,10 @@ ExecHashJoin(HashJoinState *node)
 				 * outer relation.
 				 */
 				if (hashtable->totalTuples == 0 && !HJ_FILL_OUTER(node))
-					return NULL;
+				{
+					ExecReturnTuple(&node->js.ps, NULL);
+					return;
+				}
 
 				/*
 				 * need to remember whether nbatch has increased since we
@@ -323,7 +330,8 @@ ExecHashJoin(HashJoinState *node)
 						{
 							node->js.ps.ps_TupFromTlist =
 								(isDone == ExprMultipleResult);
-							return result;
+							ExecReturnTuple(&node->js.ps, result);
+							return;
 						}
 					}
 					else
@@ -362,7 +370,8 @@ ExecHashJoin(HashJoinState *node)
 						{
 							node->js.ps.ps_TupFromTlist =
 								(isDone == ExprMultipleResult);
-							return result;
+							ExecReturnTuple(&node->js.ps, result);
+							return;
 						}
 					}
 					else
@@ -401,7 +410,8 @@ ExecHashJoin(HashJoinState *node)
 					{
 						node->js.ps.ps_TupFromTlist =
 							(isDone == ExprMultipleResult);
-						return result;
+						ExecReturnTuple(&node->js.ps, result);
+						return;
 					}
 				}
 				else
@@ -414,7 +424,10 @@ ExecHashJoin(HashJoinState *node)
 				 * Try to advance to next batch.  Done if there are no more.
 				 */
 				if (!ExecHashJoinNewBatch(node))
-					return NULL;	/* end of join */
+				{
+					ExecReturnTuple(&node->js.ps, NULL); /* end of join */
+					return;
+				}
 				node->hj_JoinState = HJ_NEED_NEW_OUTER;
 				break;
 
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 4f6f91c..47285a1 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -249,7 +249,7 @@ IndexOnlyRecheck(IndexOnlyScanState *node, TupleTableSlot *slot)
  *		ExecIndexOnlyScan(node)
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecIndexOnlyScan(IndexOnlyScanState *node)
 {
 	/*
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index bf16cb1..b08e1b2 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -482,7 +482,7 @@ reorderqueue_pop(IndexScanState *node)
  *		ExecIndexScan(node)
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecIndexScan(IndexScanState *node)
 {
 	/*
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index 97267c5..4e70183 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -36,7 +36,7 @@ static void pass_down_bound(LimitState *node, PlanState *child_node);
  *		filtering on the stream of tuples returned by a subplan.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *				/* return: a tuple or NULL */
+void
 ExecLimit(LimitState *node)
 {
 	ScanDirection direction;
@@ -72,7 +72,10 @@ ExecLimit(LimitState *node)
 			 * If backwards scan, just return NULL without changing state.
 			 */
 			if (!ScanDirectionIsForward(direction))
-				return NULL;
+			{
+				ExecReturnTuple(&node->ps, NULL);
+				return;
+			}
 
 			/*
 			 * Check for empty window; if so, treat like empty subplan.
@@ -80,7 +83,8 @@ ExecLimit(LimitState *node)
 			if (node->count <= 0 && !node->noCount)
 			{
 				node->lstate = LIMIT_EMPTY;
-				return NULL;
+				ExecReturnTuple(&node->ps, NULL);
+				return;
 			}
 
 			/*
@@ -96,7 +100,8 @@ ExecLimit(LimitState *node)
 					 * any output at all.
 					 */
 					node->lstate = LIMIT_EMPTY;
-					return NULL;
+					ExecReturnTuple(&node->ps, NULL);
+					return;
 				}
 				node->subSlot = slot;
 				if (++node->position > node->offset)
@@ -115,7 +120,8 @@ ExecLimit(LimitState *node)
 			 * The subplan is known to return no tuples (or not more than
 			 * OFFSET tuples, in general).  So we return no tuples.
 			 */
-			return NULL;
+			ExecReturnTuple(&node->ps, NULL);
+			return;
 
 		case LIMIT_INWINDOW:
 			if (ScanDirectionIsForward(direction))
@@ -130,7 +136,8 @@ ExecLimit(LimitState *node)
 					node->position - node->offset >= node->count)
 				{
 					node->lstate = LIMIT_WINDOWEND;
-					return NULL;
+					ExecReturnTuple(&node->ps, NULL);
+					return;
 				}
 
 				/*
@@ -140,7 +147,8 @@ ExecLimit(LimitState *node)
 				if (TupIsNull(slot))
 				{
 					node->lstate = LIMIT_SUBPLANEOF;
-					return NULL;
+					ExecReturnTuple(&node->ps, NULL);
+					return;
 				}
 				node->subSlot = slot;
 				node->position++;
@@ -154,7 +162,8 @@ ExecLimit(LimitState *node)
 				if (node->position <= node->offset + 1)
 				{
 					node->lstate = LIMIT_WINDOWSTART;
-					return NULL;
+					ExecReturnTuple(&node->ps, NULL);
+					return;
 				}
 
 				/*
@@ -170,7 +179,10 @@ ExecLimit(LimitState *node)
 
 		case LIMIT_SUBPLANEOF:
 			if (ScanDirectionIsForward(direction))
-				return NULL;
+			{
+				ExecReturnTuple(&node->ps, NULL);
+				return;
+			}
 
 			/*
 			 * Backing up from subplan EOF, so re-fetch previous tuple; there
@@ -186,7 +198,10 @@ ExecLimit(LimitState *node)
 
 		case LIMIT_WINDOWEND:
 			if (ScanDirectionIsForward(direction))
-				return NULL;
+			{
+				ExecReturnTuple(&node->ps, NULL);
+				return;
+			}
 
 			/*
 			 * Backing up from window end: simply re-return the last tuple
@@ -199,7 +214,10 @@ ExecLimit(LimitState *node)
 
 		case LIMIT_WINDOWSTART:
 			if (!ScanDirectionIsForward(direction))
-				return NULL;
+			{
+				ExecReturnTuple(&node->ps, NULL);
+				return;
+			}
 
 			/*
 			 * Advancing after having backed off window start: simply
@@ -220,7 +238,7 @@ ExecLimit(LimitState *node)
 	/* Return the current tuple */
 	Assert(!TupIsNull(slot));
 
-	return slot;
+	ExecReturnTuple(&node->ps, slot);
 }
 
 /*
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index c4b5333..8daa203 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -35,7 +35,7 @@
  *		ExecLockRows
  * ----------------------------------------------------------------
  */
-TupleTableSlot *				/* return: a tuple or NULL */
+void
 ExecLockRows(LockRowsState *node)
 {
 	TupleTableSlot *slot;
@@ -57,7 +57,10 @@ lnext:
 	slot = ExecProcNode(outerPlan);
 
 	if (TupIsNull(slot))
-		return NULL;
+	{
+		ExecReturnTuple(&node->ps, NULL);
+		return;
+	}
 
 	/* We don't need EvalPlanQual unless we get updated tuple version(s) */
 	epq_needed = false;
@@ -334,7 +337,7 @@ lnext:
 	}
 
 	/* Got all locks, so return the current tuple */
-	return slot;
+	ExecReturnTuple(&node->ps, slot);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 82e31c1..fd3b013 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -35,7 +35,7 @@
  *
  * ----------------------------------------------------------------
  */
-TupleTableSlot *				/* result tuple from subplan */
+void
 ExecMaterial(MaterialState *node)
 {
 	EState	   *estate;
@@ -93,7 +93,11 @@ ExecMaterial(MaterialState *node)
 			 * fetch.
 			 */
 			if (!tuplestore_advance(tuplestorestate, forward))
-				return NULL;	/* the tuplestore must be empty */
+			{
+				/* the tuplestore must be empty */
+				ExecReturnTuple(&node->ss.ps, NULL);
+				return;
+			}
 		}
 		eof_tuplestore = false;
 	}
@@ -105,7 +109,10 @@ ExecMaterial(MaterialState *node)
 	if (!eof_tuplestore)
 	{
 		if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))
-			return slot;
+		{
+			ExecReturnTuple(&node->ss.ps, slot);
+			return;
+		}
 		if (forward)
 			eof_tuplestore = true;
 	}
@@ -132,7 +139,8 @@ ExecMaterial(MaterialState *node)
 		if (TupIsNull(outerslot))
 		{
 			node->eof_underlying = true;
-			return NULL;
+			ExecReturnTuple(&node->ss.ps, NULL);
+			return;
 		}
 
 		/*
@@ -146,13 +154,14 @@ ExecMaterial(MaterialState *node)
 		/*
 		 * We can just return the subplan's returned tuple, without copying.
 		 */
-		return outerslot;
+		ExecReturnTuple(&node->ss.ps, outerslot);
+		return;
 	}
 
 	/*
 	 * Nothing left ...
 	 */
-	return ExecClearTuple(slot);
+	ExecReturnTuple(&node->ss.ps, ExecClearTuple(slot));
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index ae0e8dc..3ef8120 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -164,7 +164,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
  *		Handles iteration over multiple subplans.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecMergeAppend(MergeAppendState *node)
 {
 	TupleTableSlot *result;
@@ -214,7 +214,7 @@ ExecMergeAppend(MergeAppendState *node)
 		result = node->ms_slots[i];
 	}
 
-	return result;
+	ExecReturnTuple(&node->ps, result);
 }
 
 /*
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index cd8d6c6..d73d9f4 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -615,7 +615,7 @@ ExecMergeTupleDump(MergeJoinState *mergestate)
  *		ExecMergeJoin
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecMergeJoin(MergeJoinState *node)
 {
 	List	   *joinqual;
@@ -653,7 +653,10 @@ ExecMergeJoin(MergeJoinState *node)
 
 		result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
 		if (isDone == ExprMultipleResult)
-			return result;
+		{
+			ExecReturnTuple(&node->js.ps, result);
+			return;
+		}
 		/* Done with that source tuple... */
 		node->js.ps.ps_TupFromTlist = false;
 	}
@@ -710,7 +713,10 @@ ExecMergeJoin(MergeJoinState *node)
 
 							result = MJFillOuter(node);
 							if (result)
-								return result;
+							{
+								ExecReturnTuple(&node->js.ps, result);
+								return;
+							}
 						}
 						break;
 					case MJEVAL_ENDOFJOIN:
@@ -728,7 +734,8 @@ ExecMergeJoin(MergeJoinState *node)
 							break;
 						}
 						/* Otherwise we're done. */
-						return NULL;
+						ExecReturnTuple(&node->js.ps, NULL);
+						return;
 				}
 				break;
 
@@ -765,7 +772,10 @@ ExecMergeJoin(MergeJoinState *node)
 
 							result = MJFillInner(node);
 							if (result)
-								return result;
+							{
+								ExecReturnTuple(&node->js.ps, result);
+								return;
+							}
 						}
 						break;
 					case MJEVAL_ENDOFJOIN:
@@ -785,7 +795,8 @@ ExecMergeJoin(MergeJoinState *node)
 							break;
 						}
 						/* Otherwise we're done. */
-						return NULL;
+						ExecReturnTuple(&node->js.ps, NULL);
+						return;
 				}
 				break;
 
@@ -868,7 +879,8 @@ ExecMergeJoin(MergeJoinState *node)
 						{
 							node->js.ps.ps_TupFromTlist =
 								(isDone == ExprMultipleResult);
-							return result;
+							ExecReturnTuple(&node->js.ps, result);
+							return;
 						}
 					}
 					else
@@ -901,7 +913,10 @@ ExecMergeJoin(MergeJoinState *node)
 
 					result = MJFillInner(node);
 					if (result)
-						return result;
+					{
+						ExecReturnTuple(&node->js.ps, result);
+						return;
+					}
 				}
 
 				/*
@@ -1003,7 +1018,10 @@ ExecMergeJoin(MergeJoinState *node)
 
 					result = MJFillOuter(node);
 					if (result)
-						return result;
+					{
+						ExecReturnTuple(&node->js.ps, result);
+						return;
+					}
 				}
 
 				/*
@@ -1039,7 +1057,8 @@ ExecMergeJoin(MergeJoinState *node)
 							break;
 						}
 						/* Otherwise we're done. */
-						return NULL;
+						ExecReturnTuple(&node->js.ps, NULL);
+						return;
 				}
 				break;
 
@@ -1174,7 +1193,8 @@ ExecMergeJoin(MergeJoinState *node)
 								break;
 							}
 							/* Otherwise we're done. */
-							return NULL;
+							ExecReturnTuple(&node->js.ps, NULL);
+							return;
 					}
 				}
 				break;
@@ -1256,7 +1276,10 @@ ExecMergeJoin(MergeJoinState *node)
 
 					result = MJFillOuter(node);
 					if (result)
-						return result;
+					{
+						ExecReturnTuple(&node->js.ps, result);
+						return;
+					}
 				}
 
 				/*
@@ -1292,7 +1315,8 @@ ExecMergeJoin(MergeJoinState *node)
 							break;
 						}
 						/* Otherwise we're done. */
-						return NULL;
+						ExecReturnTuple(&node->js.ps, NULL);
+						return;
 				}
 				break;
 
@@ -1318,7 +1342,10 @@ ExecMergeJoin(MergeJoinState *node)
 
 					result = MJFillInner(node);
 					if (result)
-						return result;
+					{
+						ExecReturnTuple(&node->js.ps, result);
+						return;
+					}
 				}
 
 				/* Mark before advancing, if wanted */
@@ -1362,7 +1389,8 @@ ExecMergeJoin(MergeJoinState *node)
 							break;
 						}
 						/* Otherwise we're done. */
-						return NULL;
+						ExecReturnTuple(&node->js.ps, NULL);
+						return;
 				}
 				break;
 
@@ -1388,7 +1416,10 @@ ExecMergeJoin(MergeJoinState *node)
 
 					result = MJFillInner(node);
 					if (result)
-						return result;
+					{
+						ExecReturnTuple(&node->js.ps, result);
+						return;
+					}
 				}
 
 				/* Mark before advancing, if wanted */
@@ -1406,7 +1437,8 @@ ExecMergeJoin(MergeJoinState *node)
 				if (TupIsNull(innerTupleSlot))
 				{
 					MJ_printf("ExecMergeJoin: end of inner subplan\n");
-					return NULL;
+					ExecReturnTuple(&node->js.ps, NULL);
+					return;
 				}
 
 				/* Else remain in ENDOUTER state and process next tuple. */
@@ -1434,7 +1466,10 @@ ExecMergeJoin(MergeJoinState *node)
 
 					result = MJFillOuter(node);
 					if (result)
-						return result;
+					{
+						ExecReturnTuple(&node->js.ps, result);
+						return;
+					}
 				}
 
 				/*
@@ -1448,7 +1483,8 @@ ExecMergeJoin(MergeJoinState *node)
 				if (TupIsNull(outerTupleSlot))
 				{
 					MJ_printf("ExecMergeJoin: end of outer subplan\n");
-					return NULL;
+					ExecReturnTuple(&node->js.ps, NULL);
+					return;
 				}
 
 				/* Else remain in ENDINNER state and process next tuple. */
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 7bb318a..90107bd 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1298,7 +1298,7 @@ fireASTriggers(ModifyTableState *node)
  *		if needed.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecModifyTable(ModifyTableState *node)
 {
 	EState	   *estate = node->ps.state;
@@ -1333,7 +1333,10 @@ ExecModifyTable(ModifyTableState *node)
 	 * extra times.
 	 */
 	if (node->mt_done)
-		return NULL;
+	{
+		ExecReturnTuple(&node->ps, NULL);
+		return;
+	}
 
 	/*
 	 * On first call, fire BEFORE STATEMENT triggers before proceeding.
@@ -1411,7 +1414,8 @@ ExecModifyTable(ModifyTableState *node)
 			slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
 
 			estate->es_result_relation_info = saved_resultRelInfo;
-			return slot;
+			ExecReturnTuple(&node->ps, slot);
+			return;
 		}
 
 		EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
@@ -1517,7 +1521,8 @@ ExecModifyTable(ModifyTableState *node)
 		if (slot)
 		{
 			estate->es_result_relation_info = saved_resultRelInfo;
-			return slot;
+			ExecReturnTuple(&node->ps, slot);
+			return;
 		}
 	}
 
@@ -1531,7 +1536,7 @@ ExecModifyTable(ModifyTableState *node)
 
 	node->mt_done = true;
 
-	return NULL;
+	ExecReturnTuple(&node->ps, NULL);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 1895b60..54eff56 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -56,7 +56,7 @@
  *			   are prepared to return the first tuple.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecNestLoop(NestLoopState *node)
 {
 	NestLoop   *nl;
@@ -93,7 +93,10 @@ ExecNestLoop(NestLoopState *node)
 
 		result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
 		if (isDone == ExprMultipleResult)
-			return result;
+		{
+			ExecReturnTuple(&node->js.ps, result);
+			return;
+		}
 		/* Done with that source tuple... */
 		node->js.ps.ps_TupFromTlist = false;
 	}
@@ -128,7 +131,8 @@ ExecNestLoop(NestLoopState *node)
 			if (TupIsNull(outerTupleSlot))
 			{
 				ENL1_printf("no outer tuple, ending join");
-				return NULL;
+				ExecReturnTuple(&node->js.ps, NULL);
+				return;
 			}
 
 			ENL1_printf("saving new outer tuple information");
@@ -212,7 +216,8 @@ ExecNestLoop(NestLoopState *node)
 					{
 						node->js.ps.ps_TupFromTlist =
 							(isDone == ExprMultipleResult);
-						return result;
+						ExecReturnTuple(&node->js.ps, result);
+						return;
 					}
 				}
 				else
@@ -270,7 +275,8 @@ ExecNestLoop(NestLoopState *node)
 				{
 					node->js.ps.ps_TupFromTlist =
 						(isDone == ExprMultipleResult);
-					return result;
+					ExecReturnTuple(&node->js.ps, result);
+					return;
 				}
 			}
 			else
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index 2328ef3..6e78eb2 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -72,7 +72,7 @@ build_hash_table(RecursiveUnionState *rustate)
  * 2.6 go back to 2.2
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecRecursiveUnion(RecursiveUnionState *node)
 {
 	PlanState  *outerPlan = outerPlanState(node);
@@ -102,7 +102,8 @@ ExecRecursiveUnion(RecursiveUnionState *node)
 			/* Each non-duplicate tuple goes to the working table ... */
 			tuplestore_puttupleslot(node->working_table, slot);
 			/* ... and to the caller */
-			return slot;
+			ExecReturnTuple(&node->ps, slot);
+			return;
 		}
 		node->recursing = true;
 	}
@@ -151,10 +152,11 @@ ExecRecursiveUnion(RecursiveUnionState *node)
 		node->intermediate_empty = false;
 		tuplestore_puttupleslot(node->intermediate_table, slot);
 		/* ... and return it */
-		return slot;
+		ExecReturnTuple(&node->ps, slot);
+		return;
 	}
 
-	return NULL;
+	ExecReturnTuple(&node->ps, NULL);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index 0d2de14..a830ffd 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -63,7 +63,7 @@
  *		'nil' if the constant qualification is not satisfied.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecResult(ResultState *node)
 {
 	TupleTableSlot *outerTupleSlot;
@@ -87,7 +87,8 @@ ExecResult(ResultState *node)
 		if (!qualResult)
 		{
 			node->rs_done = true;
-			return NULL;
+			ExecReturnTuple(&node->ps, NULL);
+			return;
 		}
 	}
 
@@ -100,7 +101,10 @@ ExecResult(ResultState *node)
 	{
 		resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
 		if (isDone == ExprMultipleResult)
-			return resultSlot;
+		{
+			ExecReturnTuple(&node->ps, resultSlot);
+			return;
+		}
 		/* Done with that source tuple... */
 		node->ps.ps_TupFromTlist = false;
 	}
@@ -130,7 +134,10 @@ ExecResult(ResultState *node)
 			outerTupleSlot = ExecProcNode(outerPlan);
 
 			if (TupIsNull(outerTupleSlot))
-				return NULL;
+			{
+				ExecReturnTuple(&node->ps, NULL);
+				return;
+			}
 
 			/*
 			 * prepare to compute projection expressions, which will expect to
@@ -157,11 +164,12 @@ ExecResult(ResultState *node)
 		if (isDone != ExprEndResult)
 		{
 			node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-			return resultSlot;
+			ExecReturnTuple(&node->ps, resultSlot);
+			return;
 		}
 	}
 
-	return NULL;
+	ExecReturnTuple(&node->ps, NULL);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 9ce7c02..89cce0e 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -95,7 +95,7 @@ SampleRecheck(SampleScanState *node, TupleTableSlot *slot)
  *		access method functions.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecSampleScan(SampleScanState *node)
 {
 	return ExecScan((ScanState *) node,
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index f12921d..1c12e27 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -121,7 +121,7 @@ SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
  *		access method functions.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecSeqScan(SeqScanState *node)
 {
 	return ExecScan((ScanState *) node,
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 7a3b67c..b7a593f 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -191,7 +191,7 @@ set_output_count(SetOpState *setopstate, SetOpStatePerGroup pergroup)
  *		ExecSetOp
  * ----------------------------------------------------------------
  */
-TupleTableSlot *				/* return: a tuple or NULL */
+void
 ExecSetOp(SetOpState *node)
 {
 	SetOp	   *plannode = (SetOp *) node->ps.plan;
@@ -204,22 +204,26 @@ ExecSetOp(SetOpState *node)
 	if (node->numOutput > 0)
 	{
 		node->numOutput--;
-		return resultTupleSlot;
+		ExecReturnTuple(&node->ps, resultTupleSlot);
+		return;
 	}
 
 	/* Otherwise, we're done if we are out of groups */
 	if (node->setop_done)
-		return NULL;
+	{
+		ExecReturnTuple(&node->ps, NULL);
+		return;
+	}
 
 	/* Fetch the next tuple group according to the correct strategy */
 	if (plannode->strategy == SETOP_HASHED)
 	{
 		if (!node->table_filled)
 			setop_fill_hash_table(node);
-		return setop_retrieve_hash_table(node);
+		ExecReturnTuple(&node->ps, setop_retrieve_hash_table(node));
 	}
 	else
-		return setop_retrieve_direct(node);
+		ExecReturnTuple(&node->ps, setop_retrieve_direct(node));
 }
 
 /*
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index 0286a7f..13f721a 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -35,7 +35,7 @@
  *		  -- the outer child is prepared to return the first tuple.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecSort(SortState *node)
 {
 	EState	   *estate;
@@ -138,7 +138,7 @@ ExecSort(SortState *node)
 	(void) tuplesort_gettupleslot(tuplesortstate,
 								  ScanDirectionIsForward(dir),
 								  slot, NULL);
-	return slot;
+	ExecReturnTuple(&node->ss.ps, slot);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index 75a28fd..5fae5c5 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -87,7 +87,7 @@ SubqueryRecheck(SubqueryScanState *node, TupleTableSlot *slot)
  *		access method functions.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecSubqueryScan(SubqueryScanState *node)
 {
 	return ExecScan(&node->ss,
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 2604103..e2a0479 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -387,7 +387,7 @@ TidRecheck(TidScanState *node, TupleTableSlot *slot)
  *		  -- tidPtr is -1.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecTidScan(TidScanState *node)
 {
 	return ExecScan(&node->ss,
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 5d13a89..2daa001 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -42,7 +42,7 @@
  *		ExecUnique
  * ----------------------------------------------------------------
  */
-TupleTableSlot *				/* return: a tuple or NULL */
+void
 ExecUnique(UniqueState *node)
 {
 	Unique	   *plannode = (Unique *) node->ps.plan;
@@ -70,8 +70,8 @@ ExecUnique(UniqueState *node)
 		if (TupIsNull(slot))
 		{
 			/* end of subplan, so we're done */
-			ExecClearTuple(resultTupleSlot);
-			return NULL;
+			ExecReturnTuple(&node->ps, ExecClearTuple(resultTupleSlot));
+			return;
 		}
 
 		/*
@@ -98,7 +98,7 @@ ExecUnique(UniqueState *node)
 	 * won't guarantee that this source tuple is still accessible after
 	 * fetching the next source tuple.
 	 */
-	return ExecCopySlot(resultTupleSlot, slot);
+	ExecReturnTuple(&node->ps, ExecCopySlot(resultTupleSlot, slot));
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index 2c4bd9c..6a7dadf 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -172,7 +172,7 @@ ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
  *		access method functions.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecValuesScan(ValuesScanState *node)
 {
 	return ExecScan(&node->ss,
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 3dc6757..67f9574 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1555,7 +1555,7 @@ update_frametailpos(WindowObject winobj, TupleTableSlot *slot)
  *	(ignoring the case of SRFs in the targetlist, that is).
  * -----------------
  */
-TupleTableSlot *
+void
 ExecWindowAgg(WindowAggState *winstate)
 {
 	TupleTableSlot *result;
@@ -1565,7 +1565,10 @@ ExecWindowAgg(WindowAggState *winstate)
 	int			numfuncs;
 
 	if (winstate->all_done)
-		return NULL;
+	{
+		ExecReturnTuple(&winstate->ss.ps, NULL);
+		return;
+	}
 
 	/*
 	 * Check to see if we're still projecting out tuples from a previous
@@ -1579,7 +1582,10 @@ ExecWindowAgg(WindowAggState *winstate)
 
 		result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone);
 		if (isDone == ExprMultipleResult)
-			return result;
+		{
+			ExecReturnTuple(&winstate->ss.ps, result);
+			return;
+		}
 		/* Done with that source tuple... */
 		winstate->ss.ps.ps_TupFromTlist = false;
 	}
@@ -1687,7 +1693,8 @@ restart:
 		else
 		{
 			winstate->all_done = true;
-			return NULL;
+			ExecReturnTuple(&winstate->ss.ps, NULL);
+			return;
 		}
 	}
 
@@ -1753,7 +1760,7 @@ restart:
 
 	winstate->ss.ps.ps_TupFromTlist =
 		(isDone == ExprMultipleResult);
-	return result;
+	ExecReturnTuple(&winstate->ss.ps, result);
 }
 
 /* -----------------
diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c
index cfed6e6..c3615b2 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -77,7 +77,7 @@ WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
  *		access method functions.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
+void
 ExecWorkTableScan(WorkTableScanState *node)
 {
 	/*
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index f1be8fa..087735a 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -228,6 +228,15 @@ extern Node *MultiExecProcNode(PlanState *node);
 extern void ExecEndNode(PlanState *node);
 extern bool ExecShutdownNode(PlanState *node);
 
+/* Convenience function to set a node's result to a TupleTableSlot. */
+static inline void
+ExecReturnTuple(PlanState *node, TupleTableSlot *slot)
+{
+	Assert(!node->result_ready);
+	node->result = (Node *) slot;
+	node->result_ready = true;
+}
+
 /*
  * prototypes from functions in execQual.c
  */
@@ -256,7 +265,7 @@ extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo,
 typedef TupleTableSlot *(*ExecScanAccessMtd) (ScanState *node);
 typedef bool (*ExecScanRecheckMtd) (ScanState *node, TupleTableSlot *slot);
 
-extern TupleTableSlot *ExecScan(ScanState *node, ExecScanAccessMtd accessMtd,
+extern void ExecScan(ScanState *node, ExecScanAccessMtd accessMtd,
 		 ExecScanRecheckMtd recheckMtd);
 extern void ExecAssignScanProjectionInfo(ScanState *node);
 extern void ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno);
diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h
index 54c75e8..b86ec6a 100644
--- a/src/include/executor/nodeAgg.h
+++ b/src/include/executor/nodeAgg.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern AggState *ExecInitAgg(Agg *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecAgg(AggState *node);
+extern void ExecAgg(AggState *node);
 extern void ExecEndAgg(AggState *node);
 extern void ExecReScanAgg(AggState *node);
 
diff --git a/src/include/executor/nodeAppend.h b/src/include/executor/nodeAppend.h
index 51c381e..70a6b62 100644
--- a/src/include/executor/nodeAppend.h
+++ b/src/include/executor/nodeAppend.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern AppendState *ExecInitAppend(Append *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecAppend(AppendState *node);
+extern void ExecAppend(AppendState *node);
 extern void ExecEndAppend(AppendState *node);
 extern void ExecReScanAppend(AppendState *node);
 
diff --git a/src/include/executor/nodeBitmapHeapscan.h b/src/include/executor/nodeBitmapHeapscan.h
index 0ed9c78..069dbc7 100644
--- a/src/include/executor/nodeBitmapHeapscan.h
+++ b/src/include/executor/nodeBitmapHeapscan.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern BitmapHeapScanState *ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecBitmapHeapScan(BitmapHeapScanState *node);
+extern void ExecBitmapHeapScan(BitmapHeapScanState *node);
 extern void ExecEndBitmapHeapScan(BitmapHeapScanState *node);
 extern void ExecReScanBitmapHeapScan(BitmapHeapScanState *node);
 
diff --git a/src/include/executor/nodeCtescan.h b/src/include/executor/nodeCtescan.h
index ef5c2bc..8411fa1 100644
--- a/src/include/executor/nodeCtescan.h
+++ b/src/include/executor/nodeCtescan.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern CteScanState *ExecInitCteScan(CteScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecCteScan(CteScanState *node);
+extern void ExecCteScan(CteScanState *node);
 extern void ExecEndCteScan(CteScanState *node);
 extern void ExecReScanCteScan(CteScanState *node);
 
diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h
index 9d0b393..f6de3ab 100644
--- a/src/include/executor/nodeCustom.h
+++ b/src/include/executor/nodeCustom.h
@@ -21,7 +21,7 @@
  */
 extern CustomScanState *ExecInitCustomScan(CustomScan *custom_scan,
 				   EState *estate, int eflags);
-extern TupleTableSlot *ExecCustomScan(CustomScanState *node);
+extern void ExecCustomScan(CustomScanState *node);
 extern void ExecEndCustomScan(CustomScanState *node);
 
 extern void ExecReScanCustomScan(CustomScanState *node);
diff --git a/src/include/executor/nodeForeignscan.h b/src/include/executor/nodeForeignscan.h
index c255329..c34a3d6 100644
--- a/src/include/executor/nodeForeignscan.h
+++ b/src/include/executor/nodeForeignscan.h
@@ -18,7 +18,7 @@
 #include "nodes/execnodes.h"
 
 extern ForeignScanState *ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecForeignScan(ForeignScanState *node);
+extern void ExecForeignScan(ForeignScanState *node);
 extern void ExecEndForeignScan(ForeignScanState *node);
 extern void ExecReScanForeignScan(ForeignScanState *node);
 
diff --git a/src/include/executor/nodeFunctionscan.h b/src/include/executor/nodeFunctionscan.h
index d6e7a61..15beb13 100644
--- a/src/include/executor/nodeFunctionscan.h
+++ b/src/include/executor/nodeFunctionscan.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecFunctionScan(FunctionScanState *node);
+extern void ExecFunctionScan(FunctionScanState *node);
 extern void ExecEndFunctionScan(FunctionScanState *node);
 extern void ExecReScanFunctionScan(FunctionScanState *node);
 
diff --git a/src/include/executor/nodeGather.h b/src/include/executor/nodeGather.h
index f76d9be..100a827 100644
--- a/src/include/executor/nodeGather.h
+++ b/src/include/executor/nodeGather.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern GatherState *ExecInitGather(Gather *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecGather(GatherState *node);
+extern void ExecGather(GatherState *node);
 extern void ExecEndGather(GatherState *node);
 extern void ExecShutdownGather(GatherState *node);
 extern void ExecReScanGather(GatherState *node);
diff --git a/src/include/executor/nodeGroup.h b/src/include/executor/nodeGroup.h
index 92639f5..446ded5 100644
--- a/src/include/executor/nodeGroup.h
+++ b/src/include/executor/nodeGroup.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern GroupState *ExecInitGroup(Group *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecGroup(GroupState *node);
+extern void ExecGroup(GroupState *node);
 extern void ExecEndGroup(GroupState *node);
 extern void ExecReScanGroup(GroupState *node);
 
diff --git a/src/include/executor/nodeHash.h b/src/include/executor/nodeHash.h
index 8cf6d15..b395fd9 100644
--- a/src/include/executor/nodeHash.h
+++ b/src/include/executor/nodeHash.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern HashState *ExecInitHash(Hash *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecHash(HashState *node);
+extern void ExecHash(HashState *node);
 extern Node *MultiExecHash(HashState *node);
 extern void ExecEndHash(HashState *node);
 extern void ExecReScanHash(HashState *node);
diff --git a/src/include/executor/nodeHashjoin.h b/src/include/executor/nodeHashjoin.h
index f24127a..072c610 100644
--- a/src/include/executor/nodeHashjoin.h
+++ b/src/include/executor/nodeHashjoin.h
@@ -18,7 +18,7 @@
 #include "storage/buffile.h"
 
 extern HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecHashJoin(HashJoinState *node);
+extern void ExecHashJoin(HashJoinState *node);
 extern void ExecEndHashJoin(HashJoinState *node);
 extern void ExecReScanHashJoin(HashJoinState *node);
 
diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h
index d63d194..0fbcf80 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecIndexOnlyScan(IndexOnlyScanState *node);
+extern void ExecIndexOnlyScan(IndexOnlyScanState *node);
 extern void ExecEndIndexOnlyScan(IndexOnlyScanState *node);
 extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
 extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
diff --git a/src/include/executor/nodeIndexscan.h b/src/include/executor/nodeIndexscan.h
index 194fadb..341dab3 100644
--- a/src/include/executor/nodeIndexscan.h
+++ b/src/include/executor/nodeIndexscan.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern IndexScanState *ExecInitIndexScan(IndexScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecIndexScan(IndexScanState *node);
+extern void ExecIndexScan(IndexScanState *node);
 extern void ExecEndIndexScan(IndexScanState *node);
 extern void ExecIndexMarkPos(IndexScanState *node);
 extern void ExecIndexRestrPos(IndexScanState *node);
diff --git a/src/include/executor/nodeLimit.h b/src/include/executor/nodeLimit.h
index 96166b4..03dde30 100644
--- a/src/include/executor/nodeLimit.h
+++ b/src/include/executor/nodeLimit.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern LimitState *ExecInitLimit(Limit *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecLimit(LimitState *node);
+extern void ExecLimit(LimitState *node);
 extern void ExecEndLimit(LimitState *node);
 extern void ExecReScanLimit(LimitState *node);
 
diff --git a/src/include/executor/nodeLockRows.h b/src/include/executor/nodeLockRows.h
index e828e9c..eda3cbec 100644
--- a/src/include/executor/nodeLockRows.h
+++ b/src/include/executor/nodeLockRows.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern LockRowsState *ExecInitLockRows(LockRows *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecLockRows(LockRowsState *node);
+extern void ExecLockRows(LockRowsState *node);
 extern void ExecEndLockRows(LockRowsState *node);
 extern void ExecReScanLockRows(LockRowsState *node);
 
diff --git a/src/include/executor/nodeMaterial.h b/src/include/executor/nodeMaterial.h
index 2b8cae1..20bc7f6 100644
--- a/src/include/executor/nodeMaterial.h
+++ b/src/include/executor/nodeMaterial.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern MaterialState *ExecInitMaterial(Material *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecMaterial(MaterialState *node);
+extern void ExecMaterial(MaterialState *node);
 extern void ExecEndMaterial(MaterialState *node);
 extern void ExecMaterialMarkPos(MaterialState *node);
 extern void ExecMaterialRestrPos(MaterialState *node);
diff --git a/src/include/executor/nodeMergeAppend.h b/src/include/executor/nodeMergeAppend.h
index 0efc489..e43b5e6 100644
--- a/src/include/executor/nodeMergeAppend.h
+++ b/src/include/executor/nodeMergeAppend.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern MergeAppendState *ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecMergeAppend(MergeAppendState *node);
+extern void ExecMergeAppend(MergeAppendState *node);
 extern void ExecEndMergeAppend(MergeAppendState *node);
 extern void ExecReScanMergeAppend(MergeAppendState *node);
 
diff --git a/src/include/executor/nodeMergejoin.h b/src/include/executor/nodeMergejoin.h
index 74d691c..dfdbc1b 100644
--- a/src/include/executor/nodeMergejoin.h
+++ b/src/include/executor/nodeMergejoin.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecMergeJoin(MergeJoinState *node);
+extern void ExecMergeJoin(MergeJoinState *node);
 extern void ExecEndMergeJoin(MergeJoinState *node);
 extern void ExecReScanMergeJoin(MergeJoinState *node);
 
diff --git a/src/include/executor/nodeModifyTable.h b/src/include/executor/nodeModifyTable.h
index 6b66353..fe67248 100644
--- a/src/include/executor/nodeModifyTable.h
+++ b/src/include/executor/nodeModifyTable.h
@@ -16,7 +16,7 @@
 #include "nodes/execnodes.h"
 
 extern ModifyTableState *ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecModifyTable(ModifyTableState *node);
+extern void ExecModifyTable(ModifyTableState *node);
 extern void ExecEndModifyTable(ModifyTableState *node);
 extern void ExecReScanModifyTable(ModifyTableState *node);
 
diff --git a/src/include/executor/nodeNestloop.h b/src/include/executor/nodeNestloop.h
index eeb42d6..cab1885 100644
--- a/src/include/executor/nodeNestloop.h
+++ b/src/include/executor/nodeNestloop.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecNestLoop(NestLoopState *node);
+extern void ExecNestLoop(NestLoopState *node);
 extern void ExecEndNestLoop(NestLoopState *node);
 extern void ExecReScanNestLoop(NestLoopState *node);
 
diff --git a/src/include/executor/nodeRecursiveunion.h b/src/include/executor/nodeRecursiveunion.h
index 1c08790..fb11eca 100644
--- a/src/include/executor/nodeRecursiveunion.h
+++ b/src/include/executor/nodeRecursiveunion.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern RecursiveUnionState *ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecRecursiveUnion(RecursiveUnionState *node);
+extern void ExecRecursiveUnion(RecursiveUnionState *node);
 extern void ExecEndRecursiveUnion(RecursiveUnionState *node);
 extern void ExecReScanRecursiveUnion(RecursiveUnionState *node);
 
diff --git a/src/include/executor/nodeResult.h b/src/include/executor/nodeResult.h
index 356027f..951fae6 100644
--- a/src/include/executor/nodeResult.h
+++ b/src/include/executor/nodeResult.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern ResultState *ExecInitResult(Result *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecResult(ResultState *node);
+extern void ExecResult(ResultState *node);
 extern void ExecEndResult(ResultState *node);
 extern void ExecResultMarkPos(ResultState *node);
 extern void ExecResultRestrPos(ResultState *node);
diff --git a/src/include/executor/nodeSamplescan.h b/src/include/executor/nodeSamplescan.h
index c8f03d8..4ab6e5a 100644
--- a/src/include/executor/nodeSamplescan.h
+++ b/src/include/executor/nodeSamplescan.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern SampleScanState *ExecInitSampleScan(SampleScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSampleScan(SampleScanState *node);
+extern void ExecSampleScan(SampleScanState *node);
 extern void ExecEndSampleScan(SampleScanState *node);
 extern void ExecReScanSampleScan(SampleScanState *node);
 
diff --git a/src/include/executor/nodeSeqscan.h b/src/include/executor/nodeSeqscan.h
index f2e61ff..816d1a5 100644
--- a/src/include/executor/nodeSeqscan.h
+++ b/src/include/executor/nodeSeqscan.h
@@ -18,7 +18,7 @@
 #include "nodes/execnodes.h"
 
 extern SeqScanState *ExecInitSeqScan(SeqScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSeqScan(SeqScanState *node);
+extern void ExecSeqScan(SeqScanState *node);
 extern void ExecEndSeqScan(SeqScanState *node);
 extern void ExecReScanSeqScan(SeqScanState *node);
 
diff --git a/src/include/executor/nodeSetOp.h b/src/include/executor/nodeSetOp.h
index c6e9603..dd88afb 100644
--- a/src/include/executor/nodeSetOp.h
+++ b/src/include/executor/nodeSetOp.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSetOp(SetOpState *node);
+extern void ExecSetOp(SetOpState *node);
 extern void ExecEndSetOp(SetOpState *node);
 extern void ExecReScanSetOp(SetOpState *node);
 
diff --git a/src/include/executor/nodeSort.h b/src/include/executor/nodeSort.h
index 481065f..f65037d 100644
--- a/src/include/executor/nodeSort.h
+++ b/src/include/executor/nodeSort.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern SortState *ExecInitSort(Sort *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSort(SortState *node);
+extern void ExecSort(SortState *node);
 extern void ExecEndSort(SortState *node);
 extern void ExecSortMarkPos(SortState *node);
 extern void ExecSortRestrPos(SortState *node);
diff --git a/src/include/executor/nodeSubqueryscan.h b/src/include/executor/nodeSubqueryscan.h
index 427699b..a3962c7 100644
--- a/src/include/executor/nodeSubqueryscan.h
+++ b/src/include/executor/nodeSubqueryscan.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern SubqueryScanState *ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSubqueryScan(SubqueryScanState *node);
+extern void ExecSubqueryScan(SubqueryScanState *node);
 extern void ExecEndSubqueryScan(SubqueryScanState *node);
 extern void ExecReScanSubqueryScan(SubqueryScanState *node);
 
diff --git a/src/include/executor/nodeTidscan.h b/src/include/executor/nodeTidscan.h
index 76c2a9f..5b7bbfd 100644
--- a/src/include/executor/nodeTidscan.h
+++ b/src/include/executor/nodeTidscan.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern TidScanState *ExecInitTidScan(TidScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecTidScan(TidScanState *node);
+extern void ExecTidScan(TidScanState *node);
 extern void ExecEndTidScan(TidScanState *node);
 extern void ExecReScanTidScan(TidScanState *node);
 
diff --git a/src/include/executor/nodeUnique.h b/src/include/executor/nodeUnique.h
index aa8491d..b53a553 100644
--- a/src/include/executor/nodeUnique.h
+++ b/src/include/executor/nodeUnique.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern UniqueState *ExecInitUnique(Unique *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecUnique(UniqueState *node);
+extern void ExecUnique(UniqueState *node);
 extern void ExecEndUnique(UniqueState *node);
 extern void ExecReScanUnique(UniqueState *node);
 
diff --git a/src/include/executor/nodeValuesscan.h b/src/include/executor/nodeValuesscan.h
index 026f261..90288fc 100644
--- a/src/include/executor/nodeValuesscan.h
+++ b/src/include/executor/nodeValuesscan.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern ValuesScanState *ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecValuesScan(ValuesScanState *node);
+extern void ExecValuesScan(ValuesScanState *node);
 extern void ExecEndValuesScan(ValuesScanState *node);
 extern void ExecReScanValuesScan(ValuesScanState *node);
 
diff --git a/src/include/executor/nodeWindowAgg.h b/src/include/executor/nodeWindowAgg.h
index 94ed037..f5e2c98 100644
--- a/src/include/executor/nodeWindowAgg.h
+++ b/src/include/executor/nodeWindowAgg.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern WindowAggState *ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecWindowAgg(WindowAggState *node);
+extern void ExecWindowAgg(WindowAggState *node);
 extern void ExecEndWindowAgg(WindowAggState *node);
 extern void ExecReScanWindowAgg(WindowAggState *node);
 
diff --git a/src/include/executor/nodeWorktablescan.h b/src/include/executor/nodeWorktablescan.h
index 217208a..7b1eecb 100644
--- a/src/include/executor/nodeWorktablescan.h
+++ b/src/include/executor/nodeWorktablescan.h
@@ -17,7 +17,7 @@
 #include "nodes/execnodes.h"
 
 extern WorkTableScanState *ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecWorkTableScan(WorkTableScanState *node);
+extern void ExecWorkTableScan(WorkTableScanState *node);
 extern void ExecEndWorkTableScan(WorkTableScanState *node);
 extern void ExecReScanWorkTableScan(WorkTableScanState *node);
 
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 7d33b6d..a0bc8af 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1031,6 +1031,8 @@ typedef struct PlanState
 								 * top-level plan */
 
 	struct PlanState *parent;	/* node which will receive tuples from us */
+	bool		result_ready;	/* true if result is ready */
+	Node	   *result;			/* result, most often TupleTableSlot */
 
 	Instrumentation *instrument;	/* Optional runtime stats for this node */
 	WorkerInstrumentation *worker_instrument; /* per-worker instrumentation */
-- 
2.5.4 (Apple Git-61)

