From: Andres Freund 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 --gc4vl4obf6kp2jah Content-Type: text/x-patch; charset=us-ascii Content-Disposition: attachment; filename="0002-Move-ExecProcNode-from-dispatch-to-function-pointer-.patch"