From c70603ac35665ba78f0a83d0abbd080b05a9442d Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Tue, 25 Jul 2017 17:37:17 -0700
Subject: [PATCH 1/2] Move interrupt checking from ExecProcNode() to callers.

---
 contrib/postgres_fdw/postgres_fdw.c       |  2 ++
 src/backend/executor/execMain.c           |  2 ++
 src/backend/executor/execProcnode.c       |  2 --
 src/backend/executor/nodeAgg.c            |  2 ++
 src/backend/executor/nodeAppend.c         |  3 +++
 src/backend/executor/nodeCtescan.c        |  2 ++
 src/backend/executor/nodeCustom.c         |  3 +++
 src/backend/executor/nodeForeignscan.c    |  3 +++
 src/backend/executor/nodeGather.c         |  2 ++
 src/backend/executor/nodeGatherMerge.c    |  2 ++
 src/backend/executor/nodeGroup.c          |  6 +++++
 src/backend/executor/nodeHash.c           |  4 +++
 src/backend/executor/nodeHashjoin.c       | 21 +++++----------
 src/backend/executor/nodeLimit.c          |  4 +++
 src/backend/executor/nodeLockRows.c       |  2 ++
 src/backend/executor/nodeMaterial.c       |  2 ++
 src/backend/executor/nodeMergeAppend.c    |  6 ++++-
 src/backend/executor/nodeMergejoin.c      |  3 +++
 src/backend/executor/nodeModifyTable.c    |  2 ++
 src/backend/executor/nodeNestloop.c       |  3 +++
 src/backend/executor/nodeProjectSet.c     |  5 ++++
 src/backend/executor/nodeRecursiveunion.c |  2 ++
 src/backend/executor/nodeResult.c         |  3 +++
 src/backend/executor/nodeSetOp.c          |  9 +++++++
 src/backend/executor/nodeSort.c           |  4 +++
 src/backend/executor/nodeSubplan.c        | 44 +++++++++++++++++++++++--------
 src/backend/executor/nodeSubqueryscan.c   |  3 +++
 src/backend/executor/nodeUnique.c         |  3 +++
 src/backend/executor/nodeWindowAgg.c      |  8 +++++-
 29 files changed, 128 insertions(+), 29 deletions(-)

diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index d77c2a70e4..0b2093f34b 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -2079,6 +2079,8 @@ postgresRecheckForeignScan(ForeignScanState *node, TupleTableSlot *slot)
 
 	Assert(outerPlan != NULL);
 
+	CHECK_FOR_INTERRUPTS();
+
 	/* Execute a local join execution plan */
 	result = ExecProcNode(outerPlan);
 	if (TupIsNull(result))
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 78cbcd1a32..a58a70e3f5 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1542,6 +1542,8 @@ ExecPostprocessPlan(EState *estate)
 		{
 			TupleTableSlot *slot;
 
+			CHECK_FOR_INTERRUPTS();
+
 			/* Reset the per-output-tuple exprcontext each time */
 			ResetPerTupleExprContext(estate);
 
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 294ad2cff9..20fd9f822e 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -399,8 +399,6 @@ ExecProcNode(PlanState *node)
 {
 	TupleTableSlot *result;
 
-	CHECK_FOR_INTERRUPTS();
-
 	if (node->chgParam != NULL) /* something changed */
 		ExecReScan(node);		/* let ReScan handle this */
 
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index de9a18e71c..f9073e79aa 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -675,6 +675,8 @@ fetch_input_tuple(AggState *aggstate)
 {
 	TupleTableSlot *slot;
 
+	CHECK_FOR_INTERRUPTS();
+
 	if (aggstate->sort_in)
 	{
 		if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index aae5e3fa63..58045e05e5 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -59,6 +59,7 @@
 
 #include "executor/execdebug.h"
 #include "executor/nodeAppend.h"
+#include "miscadmin.h"
 
 static bool exec_append_initialize_next(AppendState *appendstate);
 
@@ -204,6 +205,8 @@ ExecAppend(AppendState *node)
 		PlanState  *subnode;
 		TupleTableSlot *result;
 
+		CHECK_FOR_INTERRUPTS();
+
 		/*
 		 * figure out which subplan we are currently processing
 		 */
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index bed7949c5a..e7d3c69c4b 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -37,6 +37,8 @@ CteScanNext(CteScanState *node)
 	bool		eof_tuplestore;
 	TupleTableSlot *slot;
 
+	CHECK_FOR_INTERRUPTS();
+
 	/*
 	 * get state info from node
 	 */
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index 69e27047f1..e28e41df59 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -15,6 +15,7 @@
 #include "executor/nodeCustom.h"
 #include "nodes/execnodes.h"
 #include "nodes/plannodes.h"
+#include "miscadmin.h"
 #include "parser/parsetree.h"
 #include "utils/hsearch.h"
 #include "utils/memutils.h"
@@ -105,6 +106,8 @@ TupleTableSlot *
 ExecCustomScan(CustomScanState *node)
 {
 	Assert(node->methods->ExecCustomScan != NULL);
+	CHECK_FOR_INTERRUPTS();
+
 	return node->methods->ExecCustomScan(node);
 }
 
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 9cde112554..2873f24e36 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -25,6 +25,7 @@
 #include "executor/executor.h"
 #include "executor/nodeForeignscan.h"
 #include "foreign/fdwapi.h"
+#include "miscadmin.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
@@ -46,6 +47,8 @@ ForeignNext(ForeignScanState *node)
 	ExprContext *econtext = node->ss.ps.ps_ExprContext;
 	MemoryContext oldcontext;
 
+	CHECK_FOR_INTERRUPTS();
+
 	/* Call the Iterate function in short-lived context */
 	oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
 	if (plan->operation != CMD_SELECT)
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index f83cd584d7..7f12b526ba 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -247,6 +247,8 @@ gather_getnext(GatherState *gatherstate)
 
 	while (gatherstate->reader != NULL || gatherstate->need_to_scan_locally)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		if (gatherstate->reader != NULL)
 		{
 			MemoryContext oldContext;
diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c
index 80ee1fc89b..a7065b4519 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -533,6 +533,8 @@ gather_merge_readnext(GatherMergeState *gm_state, int reader, bool nowait)
 	GMReaderTupleBuffer *tuple_buffer;
 	HeapTuple	tup = NULL;
 
+	CHECK_FOR_INTERRUPTS();
+
 	/*
 	 * If we're being asked to generate a tuple from the leader, then we just
 	 * call ExecProcNode as normal to produce one.
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index af9ba4905e..a83d88efd8 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -24,6 +24,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeGroup.h"
+#include "miscadmin.h"
 
 
 /*
@@ -45,6 +46,9 @@ ExecGroup(GroupState *node)
 	 */
 	if (node->grp_done)
 		return NULL;
+
+	CHECK_FOR_INTERRUPTS();
+
 	econtext = node->ss.ps.ps_ExprContext;
 	numCols = ((Group *) node->ss.ps.plan)->numCols;
 	grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
@@ -108,6 +112,8 @@ ExecGroup(GroupState *node)
 		 */
 		for (;;)
 		{
+			CHECK_FOR_INTERRUPTS();
+
 			outerslot = ExecProcNode(outerPlanState(node));
 			if (TupIsNull(outerslot))
 			{
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 075f4ed11c..1ba4366d75 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -101,6 +101,8 @@ MultiExecHash(HashState *node)
 	 */
 	for (;;)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		slot = ExecProcNode(outerNode);
 		if (TupIsNull(slot))
 			break;
@@ -1145,6 +1147,8 @@ ExecScanHashTableForUnmatched(HashJoinState *hjstate, ExprContext *econtext)
 
 	for (;;)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		/*
 		 * hj_CurTuple is the address of the tuple last returned from the
 		 * current bucket, or NULL if it's time to start scanning a new
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 668ed871e1..0a9595948c 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -92,6 +92,8 @@ ExecHashJoin(HashJoinState *node)
 	 */
 	for (;;)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		switch (node->hj_JoinState)
 		{
 			case HJ_BUILD_HASHTABLE:
@@ -246,13 +248,6 @@ ExecHashJoin(HashJoinState *node)
 
 			case HJ_SCAN_BUCKET:
 
-				/*
-				 * We check for interrupts here because this corresponds to
-				 * where we'd fetch a row from a child plan node in other join
-				 * types.
-				 */
-				CHECK_FOR_INTERRUPTS();
-
 				/*
 				 * Scan the selected hash bucket for matches to current outer
 				 */
@@ -596,6 +591,8 @@ ExecHashJoinOuterGetTuple(PlanState *outerNode,
 	int			curbatch = hashtable->curbatch;
 	TupleTableSlot *slot;
 
+	CHECK_FOR_INTERRUPTS();
+
 	if (curbatch == 0)			/* if it is the first pass */
 	{
 		/*
@@ -632,6 +629,7 @@ ExecHashJoinOuterGetTuple(PlanState *outerNode,
 			 * That tuple couldn't match because of a NULL, so discard it and
 			 * continue with the next one.
 			 */
+			CHECK_FOR_INTERRUPTS();
 			slot = ExecProcNode(outerNode);
 		}
 	}
@@ -771,6 +769,8 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
 												 &hashvalue,
 												 hjstate->hj_HashTupleSlot)))
 		{
+			CHECK_FOR_INTERRUPTS();
+
 			/*
 			 * NOTE: some tuples may be sent to future batches.  Also, it is
 			 * possible for hashtable->nbatch to be increased here!
@@ -855,13 +855,6 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
 	size_t		nread;
 	MinimalTuple tuple;
 
-	/*
-	 * We check for interrupts here because this is typically taken as an
-	 * alternative code path to an ExecProcNode() call, which would include
-	 * such a check.
-	 */
-	CHECK_FOR_INTERRUPTS();
-
 	/*
 	 * Since both the hash value and the MinimalTuple length word are uint32,
 	 * we can read them both in one BufFileRead() call without any type
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index abd060d75f..c6aaa5bdd4 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -23,6 +23,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeLimit.h"
+#include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 
 static void recompute_limits(LimitState *node);
@@ -43,6 +44,8 @@ ExecLimit(LimitState *node)
 	TupleTableSlot *slot;
 	PlanState  *outerPlan;
 
+	CHECK_FOR_INTERRUPTS();
+
 	/*
 	 * get information from the node
 	 */
@@ -88,6 +91,7 @@ ExecLimit(LimitState *node)
 			 */
 			for (;;)
 			{
+				CHECK_FOR_INTERRUPTS();
 				slot = ExecProcNode(outerPlan);
 				if (TupIsNull(slot))
 				{
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index f519794cf3..424fd0593d 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -26,6 +26,7 @@
 #include "executor/executor.h"
 #include "executor/nodeLockRows.h"
 #include "foreign/fdwapi.h"
+#include "miscadmin.h"
 #include "storage/bufmgr.h"
 #include "utils/rel.h"
 #include "utils/tqual.h"
@@ -54,6 +55,7 @@ ExecLockRows(LockRowsState *node)
 	 * Get next tuple from subplan, if any.
 	 */
 lnext:
+	CHECK_FOR_INTERRUPTS();
 	slot = ExecProcNode(outerPlan);
 
 	if (TupIsNull(slot))
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 32b7269cda..3342949590 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;
 
+	CHECK_FOR_INTERRUPTS();
+
 	/*
 	 * get state info from node
 	 */
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index fef83dbdbd..8e0ce1ef3f 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -40,8 +40,8 @@
 
 #include "executor/execdebug.h"
 #include "executor/nodeMergeAppend.h"
-
 #include "lib/binaryheap.h"
+#include "miscadmin.h"
 
 /*
  * We have one slot for each item in the heap array.  We use SlotNumber
@@ -183,6 +183,8 @@ ExecMergeAppend(MergeAppendState *node)
 		 */
 		for (i = 0; i < node->ms_nplans; i++)
 		{
+			CHECK_FOR_INTERRUPTS();
+
 			node->ms_slots[i] = ExecProcNode(node->mergeplans[i]);
 			if (!TupIsNull(node->ms_slots[i]))
 				binaryheap_add_unordered(node->ms_heap, Int32GetDatum(i));
@@ -192,6 +194,8 @@ ExecMergeAppend(MergeAppendState *node)
 	}
 	else
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		/*
 		 * Otherwise, pull the next tuple from whichever subplan we returned
 		 * from last time, and reinsert the subplan index into the heap,
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 6a145ee33a..657af4692f 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -95,6 +95,7 @@
 #include "access/nbtree.h"
 #include "executor/execdebug.h"
 #include "executor/nodeMergejoin.h"
+#include "miscadmin.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 
@@ -634,6 +635,8 @@ ExecMergeJoin(MergeJoinState *node)
 	{
 		MJ_dump(node);
 
+		CHECK_FOR_INTERRUPTS();
+
 		/*
 		 * get the current state of the join and do things accordingly.
 		 */
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 77ba15dd90..11cb207b34 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1603,6 +1603,8 @@ ExecModifyTable(ModifyTableState *node)
 	 */
 	for (;;)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		/*
 		 * Reset the per-output-tuple exprcontext.  This is needed because
 		 * triggers expect to use that context as workspace.  It's a bit ugly
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 0065fe601e..ec8862653e 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -23,6 +23,7 @@
 
 #include "executor/execdebug.h"
 #include "executor/nodeNestloop.h"
+#include "miscadmin.h"
 #include "utils/memutils.h"
 
 
@@ -95,6 +96,8 @@ ExecNestLoop(NestLoopState *node)
 
 	for (;;)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		/*
 		 * If we don't have an outer tuple, get the next one and reset the
 		 * inner scan.
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c
index 01048cc826..fbce3e09c5 100644
--- a/src/backend/executor/nodeProjectSet.c
+++ b/src/backend/executor/nodeProjectSet.c
@@ -24,6 +24,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeProjectSet.h"
+#include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/memutils.h"
 
@@ -55,6 +56,8 @@ ExecProjectSet(ProjectSetState *node)
 	 */
 	if (node->pending_srf_tuples)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		resultSlot = ExecProjectSRF(node, true);
 
 		if (resultSlot != NULL)
@@ -76,6 +79,8 @@ ExecProjectSet(ProjectSetState *node)
 		/*
 		 * Retrieve tuples from the outer plan until there are no more.
 		 */
+		CHECK_FOR_INTERRUPTS();
+
 		outerPlan = outerPlanState(node);
 		outerTupleSlot = ExecProcNode(outerPlan);
 
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index fc1c00d68f..7b5f5a972c 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -80,6 +80,7 @@ ExecRecursiveUnion(RecursiveUnionState *node)
 	{
 		for (;;)
 		{
+			CHECK_FOR_INTERRUPTS();
 			slot = ExecProcNode(outerPlan);
 			if (TupIsNull(slot))
 				break;
@@ -104,6 +105,7 @@ ExecRecursiveUnion(RecursiveUnionState *node)
 	/* 2. Execute recursive term */
 	for (;;)
 	{
+		CHECK_FOR_INTERRUPTS();
 		slot = ExecProcNode(innerPlan);
 		if (TupIsNull(slot))
 		{
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index a753a53419..eec3048245 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -47,6 +47,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeResult.h"
+#include "miscadmin.h"
 #include "utils/memutils.h"
 
 
@@ -101,6 +102,8 @@ ExecResult(ResultState *node)
 	 */
 	while (!node->rs_done)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		outerPlan = outerPlanState(node);
 
 		if (outerPlan != NULL)
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 9c7812e519..0e8f1b2a72 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -47,6 +47,7 @@
 #include "access/htup_details.h"
 #include "executor/executor.h"
 #include "executor/nodeSetOp.h"
+#include "miscadmin.h"
 #include "utils/memutils.h"
 
 
@@ -234,6 +235,8 @@ setop_retrieve_direct(SetOpState *setopstate)
 	 */
 	while (!setopstate->setop_done)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		/*
 		 * If we don't already have the first tuple of the new group, fetch it
 		 * from the outer plan.
@@ -277,6 +280,8 @@ setop_retrieve_direct(SetOpState *setopstate)
 		 */
 		for (;;)
 		{
+			CHECK_FOR_INTERRUPTS();
+
 			outerslot = ExecProcNode(outerPlan);
 			if (TupIsNull(outerslot))
 			{
@@ -358,6 +363,8 @@ setop_fill_hash_table(SetOpState *setopstate)
 		TupleHashEntryData *entry;
 		bool		isnew;
 
+		CHECK_FOR_INTERRUPTS();
+
 		outerslot = ExecProcNode(outerPlan);
 		if (TupIsNull(outerslot))
 			break;
@@ -428,6 +435,8 @@ setop_retrieve_hash_table(SetOpState *setopstate)
 	 */
 	while (!setopstate->setop_done)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		/*
 		 * Find the next entry in the hash table
 		 */
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index 924b458df8..e74fa48124 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -43,6 +43,8 @@ ExecSort(SortState *node)
 	Tuplesortstate *tuplesortstate;
 	TupleTableSlot *slot;
 
+	CHECK_FOR_INTERRUPTS();
+
 	/*
 	 * get state info from node
 	 */
@@ -100,6 +102,8 @@ ExecSort(SortState *node)
 
 		for (;;)
 		{
+			CHECK_FOR_INTERRUPTS();
+
 			slot = ExecProcNode(outerNode);
 
 			if (TupIsNull(slot))
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index e8fa4c8547..cbd790c9e4 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -33,6 +33,7 @@
 #include "executor/executor.h"
 #include "executor/nodeSubplan.h"
 #include "nodes/makefuncs.h"
+#include "miscadmin.h"
 #include "optimizer/clauses.h"
 #include "utils/array.h"
 #include "utils/lsyscache.h"
@@ -307,16 +308,23 @@ ExecScanSubPlan(SubPlanState *node,
 	result = BoolGetDatum(subLinkType == ALL_SUBLINK);
 	*isNull = false;
 
-	for (slot = ExecProcNode(planstate);
-		 !TupIsNull(slot);
-		 slot = ExecProcNode(planstate))
+	for (;;)
 	{
-		TupleDesc	tdesc = slot->tts_tupleDescriptor;
+		TupleDesc	tdesc;
 		Datum		rowresult;
 		bool		rownull;
 		int			col;
 		ListCell   *plst;
 
+		CHECK_FOR_INTERRUPTS();
+
+		slot = ExecProcNode(planstate);
+
+		if (TupIsNull(slot))
+			break;
+
+		tdesc = slot->tts_tupleDescriptor;
+
 		if (subLinkType == EXISTS_SUBLINK)
 		{
 			found = true;
@@ -537,14 +545,19 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
 	 * Scan the subplan and load the hash table(s).  Note that when there are
 	 * duplicate rows coming out of the sub-select, only one copy is stored.
 	 */
-	for (slot = ExecProcNode(planstate);
-		 !TupIsNull(slot);
-		 slot = ExecProcNode(planstate))
+	for (;;)
 	{
 		int			col = 1;
 		ListCell   *plst;
 		bool		isnew;
 
+		CHECK_FOR_INTERRUPTS();
+
+		slot = ExecProcNode(planstate);
+
+		if (TupIsNull(slot))
+			break;
+
 		/*
 		 * Load up the Params representing the raw sub-select outputs, then
 		 * form the projection tuple to store in the hashtable.
@@ -618,6 +631,8 @@ findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
 	InitTupleHashIterator(hashtable, &hashiter);
 	while ((entry = ScanTupleHashTable(hashtable, &hashiter)) != NULL)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
 		if (!execTuplesUnequal(slot, hashtable->tableslot,
 							   numCols, keyColIdx,
@@ -960,13 +975,20 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 	 * Run the plan.  (If it needs to be rescanned, the first ExecProcNode
 	 * call will take care of that.)
 	 */
-	for (slot = ExecProcNode(planstate);
-		 !TupIsNull(slot);
-		 slot = ExecProcNode(planstate))
+	for (;;)
 	{
-		TupleDesc	tdesc = slot->tts_tupleDescriptor;
+		TupleDesc	tdesc;
 		int			i = 1;
 
+		CHECK_FOR_INTERRUPTS();
+
+		slot = ExecProcNode(planstate);
+
+		if (TupIsNull(slot))
+			break;
+
+		tdesc = slot->tts_tupleDescriptor;
+
 		if (subLinkType == EXISTS_SUBLINK)
 		{
 			/* There can be only one setParam... */
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index ae184700a6..83b1b2b085 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -29,6 +29,7 @@
 
 #include "executor/execdebug.h"
 #include "executor/nodeSubqueryscan.h"
+#include "miscadmin.h"
 
 static TupleTableSlot *SubqueryNext(SubqueryScanState *node);
 
@@ -47,6 +48,8 @@ SubqueryNext(SubqueryScanState *node)
 {
 	TupleTableSlot *slot;
 
+	CHECK_FOR_INTERRUPTS();
+
 	/*
 	 * Get the next tuple from the sub-query.
 	 */
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 28cc1e90f8..9f101375ef 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -35,6 +35,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeUnique.h"
+#include "miscadmin.h"
 #include "utils/memutils.h"
 
 
@@ -63,6 +64,8 @@ ExecUnique(UniqueState *node)
 	 */
 	for (;;)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		/*
 		 * fetch a tuple from the outer subplan
 		 */
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 8f13fe0c73..838d3458d5 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1079,7 +1079,11 @@ begin_partition(WindowAggState *winstate)
 	 */
 	if (TupIsNull(winstate->first_part_slot))
 	{
-		TupleTableSlot *outerslot = ExecProcNode(outerPlan);
+		TupleTableSlot *outerslot;
+
+		CHECK_FOR_INTERRUPTS();
+
+		outerslot = ExecProcNode(outerPlan);
 
 		if (!TupIsNull(outerslot))
 			ExecCopySlot(winstate->first_part_slot, outerslot);
@@ -1191,6 +1195,8 @@ spool_tuples(WindowAggState *winstate, int64 pos)
 
 	while (winstate->spooled_rows <= pos || pos == -1)
 	{
+		CHECK_FOR_INTERRUPTS();
+
 		outerslot = ExecProcNode(outerPlan);
 		if (TupIsNull(outerslot))
 		{
-- 
2.13.1.392.g8d1b10321b.dirty

