segfault in HEAD when too many nested functions call
Hello,
Since b8d7f053c5c2bf2a7e8734fe3327f6a8bc711755 (Andres in Cc), if you
write queries which result in infinite recursion (or just too many
nested function calls), execution ends with segfault instead of intended
exhausted max_stack_depth:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000df851e in DirectFunctionCall1Coll (
func=<error reading variable: Cannot access memory at address
0x7ffef5972f98>,
collation=<error reading variable: Cannot access memory at address
0x7ffef5972f94>,
arg1=<error reading variable: Cannot access memory at address
0x7ffef5972f88>) at fmgr.c:708
Please find attached a trivial patch to fix this. I'm not sure
ExecMakeTableFunctionResult() is the best or only place that needs to
check the stack depth.
I also attached a simple sql file to reproduce the issue if needed.
Should I add a regression test based on it?
--
Julien Rouhaud
http://dalibo.com - http://dalibo.org
Attachments:
fix_segfault_recursion.difftext/x-patch; name=fix_segfault_recursion.diffDownload
diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c
index 138e86ac67..9d257d4d88 100644
--- a/src/backend/executor/execSRF.c
+++ b/src/backend/executor/execSRF.c
@@ -117,6 +117,9 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
MemoryContext oldcontext;
bool first_time = true;
+ /* Guard against stack overflow due to overly nested functions call */
+ check_stack_depth();
+
callerContext = CurrentMemoryContext;
funcrettype = exprType((Node *) setexpr->expr);
Julien Rouhaud <julien.rouhaud@dalibo.com> writes:
Since b8d7f053c5c2bf2a7e8734fe3327f6a8bc711755 (Andres in Cc), if you
write queries which result in infinite recursion (or just too many
nested function calls), execution ends with segfault instead of intended
exhausted max_stack_depth:
Yes. We discussed this before the patch went in [1]/messages/by-id/22833.1490390175@sss.pgh.pa.us. I wanted to put
a stack depth check in ExecProcNode(), and still do. Andres demurred,
claiming that that was too much overhead, but didn't really provide a
credible alternative. The thread drifted off without any resolution,
but clearly we need to do something before 10.0 final.
Please find attached a trivial patch to fix this. I'm not sure
ExecMakeTableFunctionResult() is the best or only place that needs to
check the stack depth.
I don't think that that's adequate at all.
I experimented with a variant that doesn't go through
ExecMakeTableFunctionResult:
CREATE OR REPLACE FUNCTION so()
RETURNS int
LANGUAGE plpgsql
AS $$
DECLARE
rec RECORD;
BEGIN
FOR rec IN SELECT so() as x
LOOP
RETURN rec.x;
END LOOP;
RETURN NULL;
END;
$$;
SELECT so();
This manages not to crash, but I think the reason it does not is purely
accidental: "SELECT so()" has a nontrivial targetlist so we end up running
ExecBuildProjectionInfo on that, meaning that a fresh expression
compilation happens at every nesting depth, and there are
check_stack_depth calls in expression compilation. Surely that's
something we'd try to improve someday. Or it could accidentally get
broken by unrelated changes in the way plpgsql sets up queries to be
executed.
I still think that we really need to add a check in ExecProcNode().
Even if there's an argument to be made that every recursion would
somewhere go through ExecMakeTableFunctionResult, very large/complex
queries could result in substantial stack getting chewed up before
we get to that --- and we don't have an infinite amount of stack slop.
regards, tom lane
[1]: /messages/by-id/22833.1490390175@sss.pgh.pa.us
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
I wrote:
I still think that we really need to add a check in ExecProcNode().
Actually ... to what extent could a check in ExecInitNode() substitute
for that? Or do we need both? How about ExecEndNode() and ExecReScan()?
You could argue that the latter two tree traversals are unlikely either to
consume more stack than ExecInitNode() or to be called from a more deeply
nested point. So maybe they're okay. But I'm not sure I believe that
initialization stack needs always exceed execution stack needs, though
sometimes they might.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 15/07/2017 17:22, Tom Lane wrote:
Julien Rouhaud <julien.rouhaud@dalibo.com> writes:
Since b8d7f053c5c2bf2a7e8734fe3327f6a8bc711755 (Andres in Cc), if you
write queries which result in infinite recursion (or just too many
nested function calls), execution ends with segfault instead of intended
exhausted max_stack_depth:Yes. We discussed this before the patch went in [1].
Ah, I totally forgot about it, sorry.
I wanted to put
a stack depth check in ExecProcNode(), and still do. Andres demurred,
claiming that that was too much overhead, but didn't really provide a
credible alternative. The thread drifted off without any resolution,
but clearly we need to do something before 10.0 final.
I wanted to add an open item but I see you already did, thanks!
Please find attached a trivial patch to fix this. I'm not sure
ExecMakeTableFunctionResult() is the best or only place that needs to
check the stack depth.I don't think that that's adequate at all.
I experimented with a variant that doesn't go through
ExecMakeTableFunctionResult:[...]
This manages not to crash, but I think the reason it does not is purely
accidental: "SELECT so()" has a nontrivial targetlist so we end up running
ExecBuildProjectionInfo on that, meaning that a fresh expression
compilation happens at every nesting depth, and there are
check_stack_depth calls in expression compilation. Surely that's
something we'd try to improve someday. Or it could accidentally get
broken by unrelated changes in the way plpgsql sets up queries to be
executed.I still think that we really need to add a check in ExecProcNode().
Even if there's an argument to be made that every recursion would
somewhere go through ExecMakeTableFunctionResult, very large/complex
queries could result in substantial stack getting chewed up before
we get to that --- and we don't have an infinite amount of stack slop.
I was pretty sceptical about checking depth in
ExecMakeTableFunctionResult() only vs ExecProcNode(), and this has
finished convincing me so I definitely agree.
--
Julien Rouhaud
http://dalibo.com - http://dalibo.org
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sat, Jul 15, 2017 at 11:22:37AM -0400, Tom Lane wrote:
Julien Rouhaud <julien.rouhaud@dalibo.com> writes:
Since b8d7f053c5c2bf2a7e8734fe3327f6a8bc711755 (Andres in Cc), if you
write queries which result in infinite recursion (or just too many
nested function calls), execution ends with segfault instead of intended
exhausted max_stack_depth:Yes. We discussed this before the patch went in [1]. I wanted to put
a stack depth check in ExecProcNode(), and still do. Andres demurred,
claiming that that was too much overhead, but didn't really provide a
credible alternative. The thread drifted off without any resolution,
but clearly we need to do something before 10.0 final.
[Action required within three days. This is a generic notification.]
The above-described topic is currently a PostgreSQL 10 open item. Andres,
since you committed the patch believed to have created it, you own this open
item. If some other commit is more relevant or if this does not belong as a
v10 open item, please let us know. Otherwise, please observe the policy on
open item ownership[1]/messages/by-id/20170404140717.GA2675809@tornado.leadboat.com and send a status update within three calendar days of
this message. Include a date for your subsequent status update. Testers may
discover new open items at any time, and I want to plan to get them all fixed
well in advance of shipping v10. Consequently, I will appreciate your efforts
toward speedy resolution. Thanks.
[1]: /messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi,
On 2017-07-15 11:22:37 -0400, Tom Lane wrote:
The thread drifted off without any resolution, but clearly we need to
do something before 10.0 final.
We need to do something, I'm less convinced that it's really v10
specific :/
"SELECT so()" has a nontrivial targetlist so we end up running
ExecBuildProjectionInfo on that, meaning that a fresh expression
compilation happens at every nesting depth, and there are
check_stack_depth calls in expression compilation. Surely that's
something we'd try to improve someday. Or it could accidentally get
broken by unrelated changes in the way plpgsql sets up queries to be
executed.
Independent of $subject: What are you thinking of here? You want to
avoid the ExecBuildProjectionInfo() in more cases - I'm unconvinced
that's actually helpful. In my WIP JIT compilation patch the
ExecBuildProjectionInfo() ends up being a good bit faster than paths
avoiding it.
I still think that we really need to add a check in ExecProcNode().
Even if there's an argument to be made that every recursion would
somewhere go through ExecMakeTableFunctionResult, very large/complex
queries could result in substantial stack getting chewed up before
we get to that --- and we don't have an infinite amount of stack slop.
I'm less convinced of that, due to the overhead argument. I think
there's a couple ways around that however:
1) We could move ExecProcNode() to be callback based. The first time a
node is executed a "wrapper" function is called that does the stack
and potentially other checks. That also makes ExecProcNode() small
enough to be inlined, which ends up being good for jump target
prediction. I've done something similar for v11 for expression
evaluation, getting rid of EEOP_*_FIRST duplication etc, and it seems
to work well. The big disadvantage to that is that it's a bit
invasive for v10, and very likely too invasive to backpatch.
2) I think there's some fair argument to be made that ExecInitNode()'s
stack-space needs are similar enough to ExecProcNode()'s allowing us
to put a check_stack_depth() into the former. That seems like it's
required anyway, since in many cases that's going to trigger
stack-depth exhaustion first anyway (unless we hit it in parse
analysis, which also seems quite common).
Greetings,
Andres Freund
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi,
On 2017-07-17 00:26:29 -0700, Andres Freund wrote:
I'm less convinced of that, due to the overhead argument. I think
there's a couple ways around that however:1) We could move ExecProcNode() to be callback based. The first time a
node is executed a "wrapper" function is called that does the stack
and potentially other checks. That also makes ExecProcNode() small
enough to be inlined, which ends up being good for jump target
prediction. I've done something similar for v11 for expression
evaluation, getting rid of EEOP_*_FIRST duplication etc, and it seems
to work well. The big disadvantage to that is that it's a bit
invasive for v10, and very likely too invasive to backpatch.
2) I think there's some fair argument to be made that ExecInitNode()'s
stack-space needs are similar enough to ExecProcNode()'s allowing us
to put a check_stack_depth() into the former. That seems like it's
required anyway, since in many cases that's going to trigger
stack-depth exhaustion first anyway (unless we hit it in parse
analysis, which also seems quite common).
Attached is a trivial patch implementing 1) and a proof-of-concept hack
for 2).
The latter obviously isn't ready, but might make clearer what I'm
thinking about. If we were to go this route we'd have to probably move
the callback assignment into the ExecInit* routines, and possibly
replace the switch in ExecInitNode() with another callback, assigned in
make_*, and implement callbacks for ExecShutdown, MultiExecProcNode etc.
This results in a good speedup in tpc-h btw:
master total min: 46434.897 cb min: 44778.228 [diff -3.70]
- Andres
Attachments:
0001-Check-stack-depth-when-initializing-executor-nodes.patchtext/x-patch; charset=us-asciiDownload
From 06b88ddf63427e1f6aeb49feb48916c3351e3380 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Mon, 17 Jul 2017 00:33:49 -0700
Subject: [PATCH 1/2] Check stack-depth when initializing executor nodes.
Previously we only checked stack-depth during parse-analysis, but
that's not necessarily sufficient. In v10, where targetlist SRF
evaluation now is executor node based, this can indeed cause
problems. It's quite possible that earlier versions are also affected
in a bit different manner, or might become vulnerable due to future
changes.
To shore this up, add a stack-depth check to ExecInitNode(). As that's
called in the same recursive manner as ExecProcNode() /
MultiExecProcNode(), it should have similar stack usage as those,
without incurring noticeable overhead in queries processing many rows.
Author: Andres Freund
Reported-By: Julien Rouhaud
Discussion:
https://postgr.es/m/22833.1490390175@sss.pgh.pa.us
https://postgr.es/m/b0af9eaa-130c-60d0-9e4e-7a135b1e0c76@dalibo.com
Backpatch: 9.2-, issue has existed for a long while
---
src/backend/executor/execProcnode.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 294ad2cff9..360479d081 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -143,6 +143,15 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
List *subps;
ListCell *l;
+ /*
+ * Make sure there's enough stack available. Check that here, rather than
+ * ExecProcNode() / MultiExecProcNode(), to avoid incurring overhead for
+ * every single tuple. The assumption making this valid is that the
+ * difference in stack use between node initialization and execution
+ * should be far less than the safety margin from check_stack_depth().
+ */
+ check_stack_depth();
+
/*
* do nothing when we get to the end of a leaf on tree.
*/
--
2.13.1.392.g8d1b10321b.dirty
0002-WIP-Move-to-callback-based-executor-nodes.patchtext/x-patch; charset=us-asciiDownload
From 2321fb83a8973c970ec934d3c1f121e739a7a20a Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Mon, 17 Jul 2017 07:50:40 -0700
Subject: [PATCH 2/2] WIP: Move to callback based executor nodes.
---
src/backend/executor/execProcnode.c | 436 +++++++-----------------------------
src/include/executor/executor.h | 30 ++-
src/include/nodes/execnodes.h | 13 ++
3 files changed, 118 insertions(+), 361 deletions(-)
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 360479d081..9d8727f41c 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -122,6 +122,15 @@
#include "miscadmin.h"
+
+static TupleTableSlot *ExecProcNodeFirst(PlanState *node);
+static TupleTableSlot *ExecProcNodeInstr(PlanState *node);
+
+#define INIT_CB(node, name) \
+ (node)->ExecProcNode = ExecProcNodeFirst; \
+ (node)->ExecProcNodeReal = (ExecProcNodeCB) Exec##name; \
+ (node)->ExecEndNode = (ExecEndNodeCB) ExecEnd##name
+
/* ------------------------------------------------------------------------
* ExecInitNode
*
@@ -166,41 +175,49 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
case T_Result:
result = (PlanState *) ExecInitResult((Result *) node,
estate, eflags);
+ INIT_CB(result, Result);
break;
case T_ProjectSet:
result = (PlanState *) ExecInitProjectSet((ProjectSet *) node,
estate, eflags);
+ INIT_CB(result, ProjectSet);
break;
case T_ModifyTable:
result = (PlanState *) ExecInitModifyTable((ModifyTable *) node,
estate, eflags);
+ INIT_CB(result, ModifyTable);
break;
case T_Append:
result = (PlanState *) ExecInitAppend((Append *) node,
estate, eflags);
+ INIT_CB(result, Append);
break;
case T_MergeAppend:
result = (PlanState *) ExecInitMergeAppend((MergeAppend *) node,
estate, eflags);
+ INIT_CB(result, MergeAppend);
break;
case T_RecursiveUnion:
result = (PlanState *) ExecInitRecursiveUnion((RecursiveUnion *) node,
estate, eflags);
+ INIT_CB(result, RecursiveUnion);
break;
case T_BitmapAnd:
result = (PlanState *) ExecInitBitmapAnd((BitmapAnd *) node,
estate, eflags);
+ result->ExecEndNode = (ExecEndNodeCB) ExecEndBitmapAnd;
break;
case T_BitmapOr:
result = (PlanState *) ExecInitBitmapOr((BitmapOr *) node,
estate, eflags);
+ result->ExecEndNode = (ExecEndNodeCB) ExecEndBitmapOr;
break;
/*
@@ -209,81 +226,97 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
case T_SeqScan:
result = (PlanState *) ExecInitSeqScan((SeqScan *) node,
estate, eflags);
+ INIT_CB(result, SeqScan);
break;
case T_SampleScan:
result = (PlanState *) ExecInitSampleScan((SampleScan *) node,
estate, eflags);
+ INIT_CB(result, SampleScan);
break;
case T_IndexScan:
result = (PlanState *) ExecInitIndexScan((IndexScan *) node,
estate, eflags);
+ INIT_CB(result, IndexScan);
break;
case T_IndexOnlyScan:
result = (PlanState *) ExecInitIndexOnlyScan((IndexOnlyScan *) node,
estate, eflags);
+ INIT_CB(result, IndexOnlyScan);
break;
case T_BitmapIndexScan:
result = (PlanState *) ExecInitBitmapIndexScan((BitmapIndexScan *) node,
estate, eflags);
+ result->ExecEndNode = (ExecEndNodeCB) ExecEndBitmapIndexScan;
break;
case T_BitmapHeapScan:
result = (PlanState *) ExecInitBitmapHeapScan((BitmapHeapScan *) node,
estate, eflags);
+ INIT_CB(result, BitmapHeapScan);
break;
case T_TidScan:
result = (PlanState *) ExecInitTidScan((TidScan *) node,
estate, eflags);
+ INIT_CB(result, TidScan);
break;
case T_SubqueryScan:
result = (PlanState *) ExecInitSubqueryScan((SubqueryScan *) node,
estate, eflags);
+ INIT_CB(result, SubqueryScan);
break;
case T_FunctionScan:
result = (PlanState *) ExecInitFunctionScan((FunctionScan *) node,
estate, eflags);
+ INIT_CB(result, FunctionScan);
break;
case T_TableFuncScan:
result = (PlanState *) ExecInitTableFuncScan((TableFuncScan *) node,
estate, eflags);
+ INIT_CB(result, TableFuncScan);
break;
case T_ValuesScan:
result = (PlanState *) ExecInitValuesScan((ValuesScan *) node,
estate, eflags);
+ INIT_CB(result, ValuesScan);
break;
case T_CteScan:
result = (PlanState *) ExecInitCteScan((CteScan *) node,
estate, eflags);
+ INIT_CB(result, CteScan);
break;
case T_NamedTuplestoreScan:
result = (PlanState *) ExecInitNamedTuplestoreScan((NamedTuplestoreScan *) node,
estate, eflags);
+ INIT_CB(result, NamedTuplestoreScan);
break;
case T_WorkTableScan:
result = (PlanState *) ExecInitWorkTableScan((WorkTableScan *) node,
estate, eflags);
+ INIT_CB(result, WorkTableScan);
break;
case T_ForeignScan:
result = (PlanState *) ExecInitForeignScan((ForeignScan *) node,
estate, eflags);
+ INIT_CB(result, ForeignScan);
break;
case T_CustomScan:
result = (PlanState *) ExecInitCustomScan((CustomScan *) node,
estate, eflags);
+ INIT_CB(result, CustomScan);
break;
/*
@@ -292,16 +325,19 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
case T_NestLoop:
result = (PlanState *) ExecInitNestLoop((NestLoop *) node,
estate, eflags);
+ INIT_CB(result, NestLoop);
break;
case T_MergeJoin:
result = (PlanState *) ExecInitMergeJoin((MergeJoin *) node,
estate, eflags);
+ INIT_CB(result, MergeJoin);
break;
case T_HashJoin:
result = (PlanState *) ExecInitHashJoin((HashJoin *) node,
estate, eflags);
+ INIT_CB(result, HashJoin);
break;
/*
@@ -310,61 +346,73 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
case T_Material:
result = (PlanState *) ExecInitMaterial((Material *) node,
estate, eflags);
+ INIT_CB(result, Material);
break;
case T_Sort:
result = (PlanState *) ExecInitSort((Sort *) node,
estate, eflags);
+ INIT_CB(result, Sort);
break;
case T_Group:
result = (PlanState *) ExecInitGroup((Group *) node,
estate, eflags);
+ INIT_CB(result, Group);
break;
case T_Agg:
result = (PlanState *) ExecInitAgg((Agg *) node,
estate, eflags);
+ INIT_CB(result, Agg);
break;
case T_WindowAgg:
result = (PlanState *) ExecInitWindowAgg((WindowAgg *) node,
estate, eflags);
+ INIT_CB(result, WindowAgg);
break;
case T_Unique:
result = (PlanState *) ExecInitUnique((Unique *) node,
estate, eflags);
+ INIT_CB(result, Unique);
break;
case T_Gather:
result = (PlanState *) ExecInitGather((Gather *) node,
estate, eflags);
+ INIT_CB(result, Gather);
break;
case T_GatherMerge:
result = (PlanState *) ExecInitGatherMerge((GatherMerge *) node,
estate, eflags);
+ INIT_CB(result, GatherMerge);
break;
case T_Hash:
result = (PlanState *) ExecInitHash((Hash *) node,
estate, eflags);
+ INIT_CB(result, Hash);
break;
case T_SetOp:
result = (PlanState *) ExecInitSetOp((SetOp *) node,
estate, eflags);
+ INIT_CB(result, SetOp);
break;
case T_LockRows:
result = (PlanState *) ExecInitLockRows((LockRows *) node,
estate, eflags);
+ INIT_CB(result, LockRows);
break;
case T_Limit:
result = (PlanState *) ExecInitLimit((Limit *) node,
estate, eflags);
+ INIT_CB(result, Limit);
break;
default:
@@ -397,202 +445,45 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
}
-/* ----------------------------------------------------------------
- * ExecProcNode
- *
- * Execute the given node to return a(nother) tuple.
- * ----------------------------------------------------------------
+/*
+ * ExecProcNode helper that performs some additional checks, before calling
+ * the relevant executor node (possibly via an instrumentation wrapper).
*/
-TupleTableSlot *
-ExecProcNode(PlanState *node)
+static TupleTableSlot *
+ExecProcNodeFirst(PlanState *node)
+{
+ check_stack_depth();
+
+ if (node->instrument)
+ node->ExecProcNode = ExecProcNodeInstr;
+ else
+ node->ExecProcNode = node->ExecProcNodeReal;
+
+ return node->ExecProcNode(node);
+}
+
+
+/*
+ * Wrapper for the proper ExecProcNode invocation that performs
+ * instrumentation. Keeping this in a separate function allows to avoid the
+ * overhead.
+ */
+static TupleTableSlot *
+ExecProcNodeInstr(PlanState *node)
{
TupleTableSlot *result;
- CHECK_FOR_INTERRUPTS();
+ InstrStartNode(node->instrument);
- if (node->chgParam != NULL) /* something changed */
- ExecReScan(node); /* let ReScan handle this */
+ result = node->ExecProcNodeReal(node);
- if (node->instrument)
- InstrStartNode(node->instrument);
-
- switch (nodeTag(node))
- {
- /*
- * control nodes
- */
- case T_ResultState:
- result = ExecResult((ResultState *) node);
- break;
-
- case T_ProjectSetState:
- result = ExecProjectSet((ProjectSetState *) node);
- break;
-
- case T_ModifyTableState:
- result = ExecModifyTable((ModifyTableState *) node);
- break;
-
- case T_AppendState:
- result = ExecAppend((AppendState *) node);
- break;
-
- case T_MergeAppendState:
- result = ExecMergeAppend((MergeAppendState *) node);
- break;
-
- case T_RecursiveUnionState:
- result = ExecRecursiveUnion((RecursiveUnionState *) node);
- break;
-
- /* BitmapAndState does not yield tuples */
-
- /* BitmapOrState does not yield tuples */
-
- /*
- * scan nodes
- */
- case T_SeqScanState:
- result = ExecSeqScan((SeqScanState *) node);
- break;
-
- case T_SampleScanState:
- result = ExecSampleScan((SampleScanState *) node);
- break;
-
- case T_IndexScanState:
- result = ExecIndexScan((IndexScanState *) node);
- break;
-
- case T_IndexOnlyScanState:
- result = ExecIndexOnlyScan((IndexOnlyScanState *) node);
- break;
-
- /* BitmapIndexScanState does not yield tuples */
-
- case T_BitmapHeapScanState:
- result = ExecBitmapHeapScan((BitmapHeapScanState *) node);
- break;
-
- case T_TidScanState:
- result = ExecTidScan((TidScanState *) node);
- break;
-
- case T_SubqueryScanState:
- result = ExecSubqueryScan((SubqueryScanState *) node);
- break;
-
- case T_FunctionScanState:
- result = ExecFunctionScan((FunctionScanState *) node);
- break;
-
- case T_TableFuncScanState:
- result = ExecTableFuncScan((TableFuncScanState *) node);
- break;
-
- case T_ValuesScanState:
- result = ExecValuesScan((ValuesScanState *) node);
- break;
-
- case T_CteScanState:
- result = ExecCteScan((CteScanState *) node);
- break;
-
- case T_NamedTuplestoreScanState:
- result = ExecNamedTuplestoreScan((NamedTuplestoreScanState *) node);
- break;
-
- case T_WorkTableScanState:
- result = ExecWorkTableScan((WorkTableScanState *) node);
- break;
-
- case T_ForeignScanState:
- result = ExecForeignScan((ForeignScanState *) node);
- break;
-
- case T_CustomScanState:
- result = ExecCustomScan((CustomScanState *) node);
- break;
-
- /*
- * join nodes
- */
- case T_NestLoopState:
- result = ExecNestLoop((NestLoopState *) node);
- break;
-
- case T_MergeJoinState:
- result = ExecMergeJoin((MergeJoinState *) node);
- break;
-
- case T_HashJoinState:
- result = ExecHashJoin((HashJoinState *) node);
- break;
-
- /*
- * materialization nodes
- */
- case T_MaterialState:
- result = ExecMaterial((MaterialState *) node);
- break;
-
- case T_SortState:
- result = ExecSort((SortState *) node);
- break;
-
- case T_GroupState:
- result = ExecGroup((GroupState *) node);
- break;
-
- case T_AggState:
- result = ExecAgg((AggState *) node);
- break;
-
- case T_WindowAggState:
- result = ExecWindowAgg((WindowAggState *) node);
- break;
-
- case T_UniqueState:
- result = ExecUnique((UniqueState *) node);
- break;
-
- case T_GatherState:
- result = ExecGather((GatherState *) node);
- break;
-
- case T_GatherMergeState:
- result = ExecGatherMerge((GatherMergeState *) node);
- break;
-
- case T_HashState:
- result = ExecHash((HashState *) node);
- break;
-
- case T_SetOpState:
- result = ExecSetOp((SetOpState *) node);
- break;
-
- case T_LockRowsState:
- result = ExecLockRows((LockRowsState *) node);
- break;
-
- case T_LimitState:
- result = ExecLimit((LimitState *) node);
- break;
-
- default:
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
- result = NULL;
- break;
- }
-
- if (node->instrument)
- InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
+ InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
return result;
}
+
/* ----------------------------------------------------------------
* MultiExecProcNode
*
@@ -674,180 +565,7 @@ ExecEndNode(PlanState *node)
node->chgParam = NULL;
}
- switch (nodeTag(node))
- {
- /*
- * control nodes
- */
- case T_ResultState:
- ExecEndResult((ResultState *) node);
- break;
-
- case T_ProjectSetState:
- ExecEndProjectSet((ProjectSetState *) node);
- break;
-
- case T_ModifyTableState:
- ExecEndModifyTable((ModifyTableState *) node);
- break;
-
- case T_AppendState:
- ExecEndAppend((AppendState *) node);
- break;
-
- case T_MergeAppendState:
- ExecEndMergeAppend((MergeAppendState *) node);
- break;
-
- case T_RecursiveUnionState:
- ExecEndRecursiveUnion((RecursiveUnionState *) node);
- break;
-
- case T_BitmapAndState:
- ExecEndBitmapAnd((BitmapAndState *) node);
- break;
-
- case T_BitmapOrState:
- ExecEndBitmapOr((BitmapOrState *) node);
- break;
-
- /*
- * scan nodes
- */
- case T_SeqScanState:
- ExecEndSeqScan((SeqScanState *) node);
- break;
-
- case T_SampleScanState:
- ExecEndSampleScan((SampleScanState *) node);
- break;
-
- case T_GatherState:
- ExecEndGather((GatherState *) node);
- break;
-
- case T_GatherMergeState:
- ExecEndGatherMerge((GatherMergeState *) node);
- break;
-
- case T_IndexScanState:
- ExecEndIndexScan((IndexScanState *) node);
- break;
-
- case T_IndexOnlyScanState:
- ExecEndIndexOnlyScan((IndexOnlyScanState *) node);
- break;
-
- case T_BitmapIndexScanState:
- ExecEndBitmapIndexScan((BitmapIndexScanState *) node);
- break;
-
- case T_BitmapHeapScanState:
- ExecEndBitmapHeapScan((BitmapHeapScanState *) node);
- break;
-
- case T_TidScanState:
- ExecEndTidScan((TidScanState *) node);
- break;
-
- case T_SubqueryScanState:
- ExecEndSubqueryScan((SubqueryScanState *) node);
- break;
-
- case T_FunctionScanState:
- ExecEndFunctionScan((FunctionScanState *) node);
- break;
-
- case T_TableFuncScanState:
- ExecEndTableFuncScan((TableFuncScanState *) node);
- break;
-
- case T_ValuesScanState:
- ExecEndValuesScan((ValuesScanState *) node);
- break;
-
- case T_CteScanState:
- ExecEndCteScan((CteScanState *) node);
- break;
-
- case T_NamedTuplestoreScanState:
- ExecEndNamedTuplestoreScan((NamedTuplestoreScanState *) node);
- break;
-
- case T_WorkTableScanState:
- ExecEndWorkTableScan((WorkTableScanState *) node);
- break;
-
- case T_ForeignScanState:
- ExecEndForeignScan((ForeignScanState *) node);
- break;
-
- case T_CustomScanState:
- ExecEndCustomScan((CustomScanState *) node);
- break;
-
- /*
- * join nodes
- */
- case T_NestLoopState:
- ExecEndNestLoop((NestLoopState *) node);
- break;
-
- case T_MergeJoinState:
- ExecEndMergeJoin((MergeJoinState *) node);
- break;
-
- case T_HashJoinState:
- ExecEndHashJoin((HashJoinState *) node);
- break;
-
- /*
- * materialization nodes
- */
- case T_MaterialState:
- ExecEndMaterial((MaterialState *) node);
- break;
-
- case T_SortState:
- ExecEndSort((SortState *) node);
- break;
-
- case T_GroupState:
- ExecEndGroup((GroupState *) node);
- break;
-
- case T_AggState:
- ExecEndAgg((AggState *) node);
- break;
-
- case T_WindowAggState:
- ExecEndWindowAgg((WindowAggState *) node);
- break;
-
- case T_UniqueState:
- ExecEndUnique((UniqueState *) node);
- break;
-
- case T_HashState:
- ExecEndHash((HashState *) node);
- break;
-
- case T_SetOpState:
- ExecEndSetOp((SetOpState *) node);
- break;
-
- case T_LockRowsState:
- ExecEndLockRows((LockRowsState *) node);
- break;
-
- case T_LimitState:
- ExecEndLimit((LimitState *) node);
- break;
-
- default:
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
- break;
- }
+ node->ExecEndNode(node);
}
/*
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index e25cfa3aba..b79c8c07d7 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -18,6 +18,9 @@
#include "executor/execdesc.h"
#include "nodes/parsenodes.h"
+/* FIXME: NOT OK */
+#include "miscadmin.h"
+
/*
* The "eflags" argument to ExecutorStart and the various ExecInitNode
@@ -224,14 +227,37 @@ extern void EvalPlanQualBegin(EPQState *epqstate, EState *parentestate);
extern void EvalPlanQualEnd(EPQState *epqstate);
/*
- * prototypes from functions in execProcnode.c
+ * functions in execProcnode.c
*/
extern PlanState *ExecInitNode(Plan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecProcNode(PlanState *node);
extern Node *MultiExecProcNode(PlanState *node);
extern void ExecEndNode(PlanState *node);
extern bool ExecShutdownNode(PlanState *node);
+
+/* ----------------------------------------------------------------
+ * ExecProcNode
+ *
+ * Execute the given node to return a(nother) tuple.
+ * ----------------------------------------------------------------
+ */
+#ifndef FRONTEND
+static inline TupleTableSlot *
+ExecProcNode(PlanState *node)
+{
+ TupleTableSlot *result;
+
+ CHECK_FOR_INTERRUPTS();
+
+ if (node->chgParam != NULL) /* something changed */
+ ExecReScan(node); /* let ReScan handle this */
+
+ result = node->ExecProcNode(node);
+
+ return result;
+}
+#endif
+
/*
* prototypes from functions in execExpr.c
*/
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 85fac8ab91..5b3936f622 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -818,6 +818,12 @@ typedef struct DomainConstraintState
* ----------------------------------------------------------------
*/
+struct PlanState;
+
+typedef TupleTableSlot* (*ExecProcNodeCB) (struct PlanState *node);
+typedef void (*ExecEndNodeCB) (struct PlanState *node);
+
+
/* ----------------
* PlanState node
*
@@ -829,6 +835,13 @@ typedef struct PlanState
{
NodeTag type;
+ /* callback to execute node */
+ ExecProcNodeCB ExecProcNode;
+ /* actual callback, if above is wrapper */
+ ExecProcNodeCB ExecProcNodeReal;
+ /* shutdown node */
+ ExecEndNodeCB ExecEndNode;
+
Plan *plan; /* associated Plan node */
EState *state; /* at execution time, states of individual
--
2.13.1.392.g8d1b10321b.dirty
On 17/07/2017 16:57, Andres Freund wrote:
The latter obviously isn't ready, but might make clearer what I'm
thinking about.
It did for me, and FWIW I like this approach.
If we were to go this route we'd have to probably move
the callback assignment into the ExecInit* routines, and possibly
replace the switch in ExecInitNode() with another callback, assigned in
make_*, and implement callbacks for ExecShutdown, MultiExecProcNode etc.This results in a good speedup in tpc-h btw:
master total min: 46434.897 cb min: 44778.228 [diff -3.70]
Is it v11 material or is there any chance to make it in v10?
--
Julien Rouhaud
http://dalibo.com - http://dalibo.org
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2017-07-17 23:04:43 +0200, Julien Rouhaud wrote:
On 17/07/2017 16:57, Andres Freund wrote:
The latter obviously isn't ready, but might make clearer what I'm
thinking about.It did for me, and FWIW I like this approach.
Cool.
If we were to go this route we'd have to probably move
the callback assignment into the ExecInit* routines, and possibly
replace the switch in ExecInitNode() with another callback, assigned in
make_*, and implement callbacks for ExecShutdown, MultiExecProcNode etc.This results in a good speedup in tpc-h btw:
master total min: 46434.897 cb min: 44778.228 [diff -3.70]Is it v11 material or is there any chance to make it in v10?
I think it'd make sense to apply the first to v10 (and earlier), and the
second to v11. I think this isn't a terribly risky patch, but it's
still a relatively large change for this point in the development
cycle. I'm willing to reconsider, but that's my default.
- Andres
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 18/07/2017 14:04, Andres Freund wrote:
On 2017-07-17 23:04:43 +0200, Julien Rouhaud wrote:
Is it v11 material or is there any chance to make it in v10?
I think it'd make sense to apply the first to v10 (and earlier), and the
second to v11. I think this isn't a terribly risky patch, but it's
still a relatively large change for this point in the development
cycle. I'm willing to reconsider, but that's my default.
Agreed.
--
Julien Rouhaud
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@anarazel.de> writes:
Attached is a trivial patch implementing 1) and a proof-of-concept hack
for 2).
The comment you made previously, as well as the proposed commit message
for 0001, suggest that you've forgotten that pre-v10 execQual.c had
several check_stack_depth() calls. Per its header comment,
* During expression evaluation, we check_stack_depth only in
* ExecMakeFunctionResult (and substitute routines) rather than at every
* single node. This is a compromise that trades off precision of the
* stack limit setting to gain speed.
and there was also a check in the recursive ExecInitExpr routine.
While it doesn't seem to be documented anywhere, I believe that we'd
argued that ExecProcNode and friends didn't need their own stack depth
checks because any nontrivial node would surely do expression evaluation
which would contain a check.
So the basic issue here is that (1) expression eval, per se, no longer
has any check and (2) it's not clear that we can rely on expression
compilation to substitute for that, since at least in principle
recompilation could be skipped during recursive use of a plan node.
I agree that adding a check to ExecInitNode() is really necessary,
but I'm not convinced that it's a sufficient substitute for checking
in ExecProcNode(). The two flaws I see in that argument are
(a) you've provided no hard evidence backing up the argument that node
initialization will take strictly more stack space than node execution;
as far as I can see that's just wishful thinking.
(b) there's also an implicit assumption that ExecutorRun is called from
a point not significantly more deeply nested than the corresponding
call to ExecutorStart. This seems also to depend on nothing much better
than wishful thinking. Certainly, many ExecutorRun calls are right next
to ExecutorStart, but several of them aren't; the portal code and
SQL-function code are both scary in this respect.
The latter obviously isn't ready, but might make clearer what I'm
thinking about. If we were to go this route we'd have to probably move
the callback assignment into the ExecInit* routines, and possibly
replace the switch in ExecInitNode() with another callback, assigned in
make_*, and implement callbacks for ExecShutdown, MultiExecProcNode etc.
While I'm uncomfortable with making such a change post-beta2, I'm one
heck of a lot *more* uncomfortable with shipping v10 with no stack depth
checks in the executor mainline. Fleshing this out and putting it in
v10 might be an acceptable compromise.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2017-07-18 15:45:53 -0400, Tom Lane wrote:
Andres Freund <andres@anarazel.de> writes:
Attached is a trivial patch implementing 1) and a proof-of-concept hack
for 2).The comment you made previously, as well as the proposed commit message
for 0001, suggest that you've forgotten that pre-v10 execQual.c had
several check_stack_depth() calls. Per its header comment,
* During expression evaluation, we check_stack_depth only in
* ExecMakeFunctionResult (and substitute routines) rather than at every
* single node. This is a compromise that trades off precision of the
* stack limit setting to gain speed.
No, I do remember that fact. But
a) unfortunately that's not really that useful because by far not all
function calls go through ExecMakeFunctionResult()
(e.g. ExecEvalDistinct() and a bunch of other FunctionCallInvoke()
containing functions).
b) deeply nested executor nodes - and that's what the commit's about to
a good degree - aren't necessarily guaranteed to actually evaluate
expressions. There's no guarantee there's any expressions (you could
just nest joins without conditions), and a bunch of nodes like
hashjoins invoke functions themselves.
and there was also a check in the recursive ExecInitExpr routine.
Which still is there.
While it doesn't seem to be documented anywhere, I believe that we'd
argued that ExecProcNode and friends didn't need their own stack depth
checks because any nontrivial node would surely do expression evaluation
which would contain a check.
Yea, I don't buy that at all.
I agree that adding a check to ExecInitNode() is really necessary,
but I'm not convinced that it's a sufficient substitute for checking
in ExecProcNode(). The two flaws I see in that argument are(a) you've provided no hard evidence backing up the argument that node
initialization will take strictly more stack space than node execution;
as far as I can see that's just wishful thinking.
I think it's pretty likely to be roughly (within slop) the case in
realistic scenarios, but I do feel fairly uncomfortable about the
assumption. That's why I really want to do something like the what I'm
proposing in the second patch. I just don't think we can realistically
add the check to the back branches, given that it's quite measurable
performancewise.
(b) there's also an implicit assumption that ExecutorRun is called from
a point not significantly more deeply nested than the corresponding
call to ExecutorStart. This seems also to depend on nothing much better
than wishful thinking. Certainly, many ExecutorRun calls are right next
to ExecutorStart, but several of them aren't; the portal code and
SQL-function code are both scary in this respect.
:/
The latter obviously isn't ready, but might make clearer what I'm
thinking about. If we were to go this route we'd have to probably move
the callback assignment into the ExecInit* routines, and possibly
replace the switch in ExecInitNode() with another callback, assigned in
make_*, and implement callbacks for ExecShutdown, MultiExecProcNode etc.While I'm uncomfortable with making such a change post-beta2, I'm one
heck of a lot *more* uncomfortable with shipping v10 with no stack depth
checks in the executor mainline. Fleshing this out and putting it in
v10 might be an acceptable compromise.
Ok, I'll flesh out the patch till Thursday. But I do think we're going
to have to do something about the back branches, too.
Greetings,
Andres Freund
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@anarazel.de> writes:
On 2017-07-18 15:45:53 -0400, Tom Lane wrote:
While I'm uncomfortable with making such a change post-beta2, I'm one
heck of a lot *more* uncomfortable with shipping v10 with no stack depth
checks in the executor mainline. Fleshing this out and putting it in
v10 might be an acceptable compromise.
Ok, I'll flesh out the patch till Thursday. But I do think we're going
to have to do something about the back branches, too.
I'm not worried about the back branches. The stack depth checks have
been in those same places for ten years at least, and there are no field
reports of trouble.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@anarazel.de> writes:
... If we were to go this route we'd have to probably move
the callback assignment into the ExecInit* routines, and possibly
replace the switch in ExecInitNode() with another callback, assigned in
make_*, and implement callbacks for ExecShutdown, MultiExecProcNode etc.
BTW, I don't see why you really need to mess with anything except
ExecProcNode? Surely the other cases such as MultiExecProcNode are
not called often enough to justify changing them away from the
switch technology. Yeah, maybe it would be a bit cleaner if they
all looked alike ... but if you're trying to make a patch that's
as little invasive as possible for v10, I'd suggest converting just
ExecProcNode to this style.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2017-07-18 16:53:43 -0400, Tom Lane wrote:
Andres Freund <andres@anarazel.de> writes:
... If we were to go this route we'd have to probably move
the callback assignment into the ExecInit* routines, and possibly
replace the switch in ExecInitNode() with another callback, assigned in
make_*, and implement callbacks for ExecShutdown, MultiExecProcNode etc.BTW, I don't see why you really need to mess with anything except
ExecProcNode? Surely the other cases such as MultiExecProcNode are
not called often enough to justify changing them away from the
switch technology. Yeah, maybe it would be a bit cleaner if they
all looked alike ... but if you're trying to make a patch that's
as little invasive as possible for v10, I'd suggest converting just
ExecProcNode to this style.
Yea, I was making that statement when not aiming for v10. Attached is a
patch that converts just ExecProcNode. The big change in comparison to
the earlier patch is that the assignment of the callback is now done in
the respective ExecInit* routines. As a consequence the ExecProcNode
callbacks now are static. I think we should do this fully in v11, I
removing dispatch routines like ExecInitNode() is a good idea, both
because it moves concerns more towards the nodes themselves - given the
growth of executor nodes that strikes me as a good idea.
I've also added stack depth checks to ExecEndNode(),
MultiExecProcNode(), ExecShutdownNode(), because it's not guaranteed
that ExecProcNode is called for every node...
I dislike having the miscadmin.h include in executor.h - but I don't
quite see a better alternative.
I want to run this through pgindent before merging, otherwise we'll
presumably end up with a lot of noise.
I still think we should backpatch at least the check_stack_depth() calls
in ExecInitNode(), ExecEndNode().
Greetings,
Andres Freund
Attachments:
0001-Move-ExecProcNode-from-dispatch-to-callback-based-mo.patchtext/x-patch; charset=us-asciiDownload
From 120218e4c6aab1c716aab12495c1a466baa8e37a Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Mon, 17 Jul 2017 00:33:49 -0700
Subject: [PATCH] Move ExecProcNode from dispatch to callback based model.
This allows us to add stack-depth checks the first time an executor
node is called, and skip that overhead on following calls.
Additionally it yields a nice speedup.
We should move towards that model for further routines, but as this is
required for v10, it seems better to only do the necessary (which
already is quite large).
Todo: Expand (scope, need in v10) & link.
Author: Andres Freund
Reported-By: Julien Rouhaud
Discussion:
https://postgr.es/m/22833.1490390175@sss.pgh.pa.us
https://postgr.es/m/b0af9eaa-130c-60d0-9e4e-7a135b1e0c76@dalibo.com
---
src/backend/executor/execProcnode.c | 257 +++++++------------------
src/backend/executor/nodeAgg.c | 6 +-
src/backend/executor/nodeAppend.c | 8 +-
src/backend/executor/nodeBitmapHeapscan.c | 7 +-
src/backend/executor/nodeCtescan.c | 7 +-
src/backend/executor/nodeCustom.c | 8 +-
src/backend/executor/nodeForeignscan.c | 7 +-
src/backend/executor/nodeFunctionscan.c | 7 +-
src/backend/executor/nodeGather.c | 7 +-
src/backend/executor/nodeGatherMerge.c | 7 +-
src/backend/executor/nodeGroup.c | 6 +-
src/backend/executor/nodeHashjoin.c | 6 +-
src/backend/executor/nodeIndexonlyscan.c | 7 +-
src/backend/executor/nodeIndexscan.c | 7 +-
src/backend/executor/nodeLimit.c | 6 +-
src/backend/executor/nodeLockRows.c | 6 +-
src/backend/executor/nodeMaterial.c | 6 +-
src/backend/executor/nodeMergeAppend.c | 7 +-
src/backend/executor/nodeMergejoin.c | 6 +-
src/backend/executor/nodeModifyTable.c | 6 +-
src/backend/executor/nodeNamedtuplestorescan.c | 7 +-
src/backend/executor/nodeNestloop.c | 6 +-
src/backend/executor/nodeProjectSet.c | 6 +-
src/backend/executor/nodeRecursiveunion.c | 6 +-
src/backend/executor/nodeResult.c | 6 +-
src/backend/executor/nodeSamplescan.c | 7 +-
src/backend/executor/nodeSeqscan.c | 7 +-
src/backend/executor/nodeSetOp.c | 6 +-
src/backend/executor/nodeSort.c | 6 +-
src/backend/executor/nodeSubqueryscan.c | 7 +-
src/backend/executor/nodeTableFuncscan.c | 7 +-
src/backend/executor/nodeTidscan.c | 7 +-
src/backend/executor/nodeUnique.c | 6 +-
src/backend/executor/nodeValuesscan.c | 7 +-
src/backend/executor/nodeWindowAgg.c | 6 +-
src/backend/executor/nodeWorktablescan.c | 7 +-
src/include/executor/executor.h | 28 ++-
src/include/executor/nodeAgg.h | 1 -
src/include/executor/nodeAppend.h | 1 -
src/include/executor/nodeBitmapHeapscan.h | 1 -
src/include/executor/nodeCtescan.h | 1 -
src/include/executor/nodeCustom.h | 1 -
src/include/executor/nodeForeignscan.h | 1 -
src/include/executor/nodeFunctionscan.h | 1 -
src/include/executor/nodeGather.h | 1 -
src/include/executor/nodeGatherMerge.h | 1 -
src/include/executor/nodeGroup.h | 1 -
src/include/executor/nodeHashjoin.h | 1 -
src/include/executor/nodeIndexonlyscan.h | 1 -
src/include/executor/nodeIndexscan.h | 1 -
src/include/executor/nodeLimit.h | 1 -
src/include/executor/nodeLockRows.h | 1 -
src/include/executor/nodeMaterial.h | 1 -
src/include/executor/nodeMergeAppend.h | 1 -
src/include/executor/nodeMergejoin.h | 1 -
src/include/executor/nodeModifyTable.h | 1 -
src/include/executor/nodeNamedtuplestorescan.h | 1 -
src/include/executor/nodeNestloop.h | 1 -
src/include/executor/nodeProjectSet.h | 1 -
src/include/executor/nodeRecursiveunion.h | 1 -
src/include/executor/nodeResult.h | 1 -
src/include/executor/nodeSamplescan.h | 1 -
src/include/executor/nodeSeqscan.h | 1 -
src/include/executor/nodeSetOp.h | 1 -
src/include/executor/nodeSort.h | 1 -
src/include/executor/nodeSubqueryscan.h | 1 -
src/include/executor/nodeTableFuncscan.h | 1 -
src/include/executor/nodeTidscan.h | 1 -
src/include/executor/nodeUnique.h | 1 -
src/include/executor/nodeValuesscan.h | 1 -
src/include/executor/nodeWindowAgg.h | 1 -
src/include/executor/nodeWorktablescan.h | 1 -
src/include/nodes/execnodes.h | 15 ++
73 files changed, 264 insertions(+), 302 deletions(-)
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 294ad2cff9..07f1530e4e 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -23,9 +23,9 @@
* ExecEndNode - shut down a plan node and its subplans
*
* NOTES
- * This used to be three files. It is now all combined into
- * one file so that it is easier to keep ExecInitNode, ExecProcNode,
- * and ExecEndNode in sync when new nodes are added.
+ * This used to be three files. It is now all combined into one file so
+ * that it is easier to keep the dispatch routines in sync when new nodes
+ * are added.
*
* EXAMPLE
* Suppose we want the age of the manager of the shoe department and
@@ -122,6 +122,10 @@
#include "miscadmin.h"
+static TupleTableSlot *ExecProcNodeFirst(PlanState *node);
+static TupleTableSlot *ExecProcNodeInstr(PlanState *node);
+
+
/* ------------------------------------------------------------------------
* ExecInitNode
*
@@ -143,6 +147,13 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
List *subps;
ListCell *l;
+ /*
+ * Make sure there's enough stack available. Need to check here in
+ * addition of ExecProcNode() (via ExecProcNodeFirst()), to make sure the
+ * stack isn't overrun while initializing the node tree.
+ */
+ check_stack_depth();
+
/*
* do nothing when we get to the end of a leaf on tree.
*/
@@ -364,6 +375,13 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
break;
}
+ /*
+ * Add a wrapper around the ExecProcNode callback that checks stack-depth
+ * first.
+ */
+ result->ExecProcNodeReal = result->ExecProcNode;
+ result->ExecProcNode = ExecProcNodeFirst;
+
/*
* Initialize any initPlans present in this node. The planner put them in
* a separate list for us.
@@ -388,197 +406,50 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
}
-/* ----------------------------------------------------------------
- * ExecProcNode
- *
- * Execute the given node to return a(nother) tuple.
- * ----------------------------------------------------------------
+/*
+ * ExecProcNode helper that performs some additional checks, before calling
+ * the relevant executor node (possibly via an instrumentation wrapper).
*/
-TupleTableSlot *
-ExecProcNode(PlanState *node)
+static TupleTableSlot *
+ExecProcNodeFirst(PlanState *node)
+{
+ /*
+ * Perform stack depth check during the first execution of the node. We
+ * only do so the first time round because it turns out to not be cheap on
+ * some common architectures (eg. x86)
+ */
+ check_stack_depth();
+
+ /*
+ * If instrumentation is required, change the wrapper to one that just
+ * does the instrumentation. Otherwise we can dispense with all wrappers
+ * and have ExecProcNode() now directly call the relevant function from
+ * now on.
+ */
+ if (node->instrument)
+ node->ExecProcNode = ExecProcNodeInstr;
+ else
+ node->ExecProcNode = node->ExecProcNodeReal;
+
+ return node->ExecProcNode(node);
+}
+
+
+/*
+ * Wrapper for the proper ExecProcNode invocation that performs
+ * instrumentation. Keeping this in a separate function allows to avoid the
+ * overhead for the common case where no instrumentation is required.
+ */
+static TupleTableSlot *
+ExecProcNodeInstr(PlanState *node)
{
TupleTableSlot *result;
- CHECK_FOR_INTERRUPTS();
+ InstrStartNode(node->instrument);
- if (node->chgParam != NULL) /* something changed */
- ExecReScan(node); /* let ReScan handle this */
+ result = node->ExecProcNodeReal(node);
- if (node->instrument)
- InstrStartNode(node->instrument);
-
- switch (nodeTag(node))
- {
- /*
- * control nodes
- */
- case T_ResultState:
- result = ExecResult((ResultState *) node);
- break;
-
- case T_ProjectSetState:
- result = ExecProjectSet((ProjectSetState *) node);
- break;
-
- case T_ModifyTableState:
- result = ExecModifyTable((ModifyTableState *) node);
- break;
-
- case T_AppendState:
- result = ExecAppend((AppendState *) node);
- break;
-
- case T_MergeAppendState:
- result = ExecMergeAppend((MergeAppendState *) node);
- break;
-
- case T_RecursiveUnionState:
- result = ExecRecursiveUnion((RecursiveUnionState *) node);
- break;
-
- /* BitmapAndState does not yield tuples */
-
- /* BitmapOrState does not yield tuples */
-
- /*
- * scan nodes
- */
- case T_SeqScanState:
- result = ExecSeqScan((SeqScanState *) node);
- break;
-
- case T_SampleScanState:
- result = ExecSampleScan((SampleScanState *) node);
- break;
-
- case T_IndexScanState:
- result = ExecIndexScan((IndexScanState *) node);
- break;
-
- case T_IndexOnlyScanState:
- result = ExecIndexOnlyScan((IndexOnlyScanState *) node);
- break;
-
- /* BitmapIndexScanState does not yield tuples */
-
- case T_BitmapHeapScanState:
- result = ExecBitmapHeapScan((BitmapHeapScanState *) node);
- break;
-
- case T_TidScanState:
- result = ExecTidScan((TidScanState *) node);
- break;
-
- case T_SubqueryScanState:
- result = ExecSubqueryScan((SubqueryScanState *) node);
- break;
-
- case T_FunctionScanState:
- result = ExecFunctionScan((FunctionScanState *) node);
- break;
-
- case T_TableFuncScanState:
- result = ExecTableFuncScan((TableFuncScanState *) node);
- break;
-
- case T_ValuesScanState:
- result = ExecValuesScan((ValuesScanState *) node);
- break;
-
- case T_CteScanState:
- result = ExecCteScan((CteScanState *) node);
- break;
-
- case T_NamedTuplestoreScanState:
- result = ExecNamedTuplestoreScan((NamedTuplestoreScanState *) node);
- break;
-
- case T_WorkTableScanState:
- result = ExecWorkTableScan((WorkTableScanState *) node);
- break;
-
- case T_ForeignScanState:
- result = ExecForeignScan((ForeignScanState *) node);
- break;
-
- case T_CustomScanState:
- result = ExecCustomScan((CustomScanState *) node);
- break;
-
- /*
- * join nodes
- */
- case T_NestLoopState:
- result = ExecNestLoop((NestLoopState *) node);
- break;
-
- case T_MergeJoinState:
- result = ExecMergeJoin((MergeJoinState *) node);
- break;
-
- case T_HashJoinState:
- result = ExecHashJoin((HashJoinState *) node);
- break;
-
- /*
- * materialization nodes
- */
- case T_MaterialState:
- result = ExecMaterial((MaterialState *) node);
- break;
-
- case T_SortState:
- result = ExecSort((SortState *) node);
- break;
-
- case T_GroupState:
- result = ExecGroup((GroupState *) node);
- break;
-
- case T_AggState:
- result = ExecAgg((AggState *) node);
- break;
-
- case T_WindowAggState:
- result = ExecWindowAgg((WindowAggState *) node);
- break;
-
- case T_UniqueState:
- result = ExecUnique((UniqueState *) node);
- break;
-
- case T_GatherState:
- result = ExecGather((GatherState *) node);
- break;
-
- case T_GatherMergeState:
- result = ExecGatherMerge((GatherMergeState *) node);
- break;
-
- case T_HashState:
- result = ExecHash((HashState *) node);
- break;
-
- case T_SetOpState:
- result = ExecSetOp((SetOpState *) node);
- break;
-
- case T_LockRowsState:
- result = ExecLockRows((LockRowsState *) node);
- break;
-
- case T_LimitState:
- result = ExecLimit((LimitState *) node);
- break;
-
- default:
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
- result = NULL;
- break;
- }
-
- if (node->instrument)
- InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
+ InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
return result;
}
@@ -602,6 +473,7 @@ MultiExecProcNode(PlanState *node)
{
Node *result;
+ check_stack_depth();
CHECK_FOR_INTERRUPTS();
if (node->chgParam != NULL) /* something changed */
@@ -653,6 +525,13 @@ MultiExecProcNode(PlanState *node)
void
ExecEndNode(PlanState *node)
{
+ /*
+ * Make sure there's enough stack available. Need to check here in
+ * addition of ExecProcNode() (via ExecProcNodeFirst()), because it's not
+ * guaranteed that ExecProcNode() is reached for all nods.
+ */
+ check_stack_depth();
+
/*
* do nothing when we get to the end of a leaf on tree.
*/
@@ -854,6 +733,8 @@ ExecEndNode(PlanState *node)
bool
ExecShutdownNode(PlanState *node)
{
+ check_stack_depth();
+
if (node == NULL)
return false;
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index de9a18e71c..649fb8d38e 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -2095,9 +2095,10 @@ lookup_hash_entries(AggState *aggstate)
* stored in the expression context to be used when ExecProject evaluates
* the result tuple.
*/
-TupleTableSlot *
-ExecAgg(AggState *node)
+static TupleTableSlot *
+ExecAgg(PlanState *pstate)
{
+ AggState *node = castNode(AggState, pstate);
TupleTableSlot *result = NULL;
if (!node->agg_done)
@@ -2687,6 +2688,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
aggstate = makeNode(AggState);
aggstate->ss.ps.plan = (Plan *) node;
aggstate->ss.ps.state = estate;
+ aggstate->ss.ps.ExecProcNode = ExecAgg;
aggstate->aggs = NIL;
aggstate->numaggs = 0;
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index aae5e3fa63..402a6342d0 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -60,6 +60,7 @@
#include "executor/execdebug.h"
#include "executor/nodeAppend.h"
+static TupleTableSlot *ExecAppend(PlanState *pstate);
static bool exec_append_initialize_next(AppendState *appendstate);
@@ -146,6 +147,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
*/
appendstate->ps.plan = (Plan *) node;
appendstate->ps.state = estate;
+ appendstate->ps.ExecProcNode = ExecAppend;
appendstate->appendplans = appendplanstates;
appendstate->as_nplans = nplans;
@@ -196,9 +198,11 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
* Handles iteration over multiple subplans.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecAppend(AppendState *node)
+static TupleTableSlot *
+ExecAppend(PlanState *pstate)
{
+ AppendState *node = castNode(AppendState, pstate);
+
for (;;)
{
PlanState *subnode;
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 7e0ba030b7..4046f2ce78 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -662,9 +662,11 @@ BitmapHeapRecheck(BitmapHeapScanState *node, TupleTableSlot *slot)
* ExecBitmapHeapScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecBitmapHeapScan(BitmapHeapScanState *node)
+static TupleTableSlot *
+ExecBitmapHeapScan(PlanState *pstate)
{
+ BitmapHeapScanState *node = castNode(BitmapHeapScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) BitmapHeapNext,
(ExecScanRecheckMtd) BitmapHeapRecheck);
@@ -812,6 +814,7 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
scanstate = makeNode(BitmapHeapScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecBitmapHeapScan;
scanstate->tbm = NULL;
scanstate->tbmiterator = NULL;
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index bed7949c5a..79676ca978 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -149,9 +149,11 @@ CteScanRecheck(CteScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecCteScan(CteScanState *node)
+static TupleTableSlot *
+ExecCteScan(PlanState *pstate)
{
+ CteScanState *node = castNode(CteScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) CteScanNext,
(ExecScanRecheckMtd) CteScanRecheck);
@@ -191,6 +193,7 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
scanstate = makeNode(CteScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecCteScan;
scanstate->eflags = eflags;
scanstate->cte_table = NULL;
scanstate->eof_cte = false;
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index 69e27047f1..17c6e9f681 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -44,6 +44,7 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
/* fill up fields of ScanState */
css->ss.ps.plan = &cscan->scan.plan;
css->ss.ps.state = estate;
+ css->ss.ps.ExecProcNode = (ExecProcNodeCB) css->methods->ExecCustomScan;
/* create expression context for node */
ExecAssignExprContext(estate, &css->ss.ps);
@@ -101,13 +102,6 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
return css;
}
-TupleTableSlot *
-ExecCustomScan(CustomScanState *node)
-{
- Assert(node->methods->ExecCustomScan != NULL);
- return node->methods->ExecCustomScan(node);
-}
-
void
ExecEndCustomScan(CustomScanState *node)
{
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 9cde112554..9987862e25 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -113,9 +113,11 @@ ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecForeignScan(ForeignScanState *node)
+static TupleTableSlot *
+ExecForeignScan(PlanState *pstate)
{
+ ForeignScanState *node = castNode(ForeignScanState, pstate);
+
return ExecScan((ScanState *) node,
(ExecScanAccessMtd) ForeignNext,
(ExecScanRecheckMtd) ForeignRecheck);
@@ -144,6 +146,7 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
scanstate = makeNode(ForeignScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecForeignScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 3217d641d7..9f87a7e5cd 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -262,9 +262,11 @@ FunctionRecheck(FunctionScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecFunctionScan(FunctionScanState *node)
+static TupleTableSlot *
+ExecFunctionScan(PlanState *pstate)
{
+ FunctionScanState *node = castNode(FunctionScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) FunctionNext,
(ExecScanRecheckMtd) FunctionRecheck);
@@ -299,6 +301,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
scanstate = makeNode(FunctionScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecFunctionScan;
scanstate->eflags = eflags;
/*
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index f83cd584d7..b051481f45 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -43,6 +43,7 @@
#include "utils/rel.h"
+static TupleTableSlot *ExecGather(PlanState *pstate);
static TupleTableSlot *gather_getnext(GatherState *gatherstate);
static HeapTuple gather_readnext(GatherState *gatherstate);
static void ExecShutdownGatherWorkers(GatherState *node);
@@ -69,6 +70,7 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
gatherstate = makeNode(GatherState);
gatherstate->ps.plan = (Plan *) node;
gatherstate->ps.state = estate;
+ gatherstate->ps.ExecProcNode = ExecGather;
gatherstate->need_to_scan_locally = !node->single_copy;
/*
@@ -120,9 +122,10 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
* the next qualifying tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecGather(GatherState *node)
+static TupleTableSlot *
+ExecGather(PlanState *pstate)
{
+ GatherState *node = castNode(GatherState, pstate);
TupleTableSlot *fslot = node->funnel_slot;
int i;
TupleTableSlot *slot;
diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c
index 80ee1fc89b..d4a5005fd5 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -44,6 +44,7 @@ typedef struct GMReaderTupleBuffer
*/
#define MAX_TUPLE_STORE 10
+static TupleTableSlot *ExecGatherMerge(PlanState *pstate);
static int32 heap_compare_slots(Datum a, Datum b, void *arg);
static TupleTableSlot *gather_merge_getnext(GatherMergeState *gm_state);
static HeapTuple gm_readnext_tuple(GatherMergeState *gm_state, int nreader,
@@ -75,6 +76,7 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
gm_state = makeNode(GatherMergeState);
gm_state->ps.plan = (Plan *) node;
gm_state->ps.state = estate;
+ gm_state->ps.ExecProcNode = ExecGatherMerge;
/*
* Miscellaneous initialization
@@ -157,9 +159,10 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
* the next qualifying tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecGatherMerge(GatherMergeState *node)
+static TupleTableSlot *
+ExecGatherMerge(PlanState *pstate)
{
+ GatherMergeState *node = castNode(GatherMergeState, pstate);
TupleTableSlot *slot;
ExprContext *econtext;
int i;
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index af9ba4905e..2d85df9120 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -31,9 +31,10 @@
*
* Return one tuple for each group of matching input tuples.
*/
-TupleTableSlot *
-ExecGroup(GroupState *node)
+static TupleTableSlot *
+ExecGroup(PlanState *pstate)
{
+ GroupState *node = castNode(GroupState, pstate);
ExprContext *econtext;
int numCols;
AttrNumber *grpColIdx;
@@ -172,6 +173,7 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
grpstate = makeNode(GroupState);
grpstate->ss.ps.plan = (Plan *) node;
grpstate->ss.ps.state = estate;
+ grpstate->ss.ps.ExecProcNode = ExecGroup;
grpstate->grp_done = FALSE;
/*
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 668ed871e1..abd5ebeca8 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -58,9 +58,10 @@ static bool ExecHashJoinNewBatch(HashJoinState *hjstate);
* the other one is "outer".
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecHashJoin(HashJoinState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecHashJoin(PlanState *pstate)
{
+ HashJoinState *node = castNode(HashJoinState, pstate);
PlanState *outerNode;
HashState *hashNode;
ExprState *joinqual;
@@ -398,6 +399,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
hjstate = makeNode(HashJoinState);
hjstate->js.ps.plan = (Plan *) node;
hjstate->js.ps.state = estate;
+ hjstate->js.ps.ExecProcNode = ExecHashJoin;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 890e54416a..a7a5760fd7 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -303,9 +303,11 @@ IndexOnlyRecheck(IndexOnlyScanState *node, TupleTableSlot *slot)
* ExecIndexOnlyScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecIndexOnlyScan(IndexOnlyScanState *node)
+static TupleTableSlot *
+ExecIndexOnlyScan(PlanState *pstate)
{
+ IndexOnlyScanState *node = castNode(IndexOnlyScanState, pstate);
+
/*
* If we have runtime keys and they've not already been set up, do it now.
*/
@@ -473,6 +475,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
indexstate = makeNode(IndexOnlyScanState);
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
+ indexstate->ss.ps.ExecProcNode = ExecIndexOnlyScan;
indexstate->ioss_HeapFetches = 0;
/*
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index d8aceb1f2c..fd751da83d 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -535,9 +535,11 @@ reorderqueue_pop(IndexScanState *node)
* ExecIndexScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecIndexScan(IndexScanState *node)
+static TupleTableSlot *
+ExecIndexScan(PlanState *pstate)
{
+ IndexScanState *node = castNode(IndexScanState, pstate);
+
/*
* If we have runtime keys and they've not already been set up, do it now.
*/
@@ -903,6 +905,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
indexstate = makeNode(IndexScanState);
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
+ indexstate->ss.ps.ExecProcNode = ExecIndexScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index abd060d75f..077e012cd8 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -36,9 +36,10 @@ 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 */
-ExecLimit(LimitState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecLimit(PlanState *pstate)
{
+ LimitState *node = castNode(LimitState, pstate);
ScanDirection direction;
TupleTableSlot *slot;
PlanState *outerPlan;
@@ -375,6 +376,7 @@ ExecInitLimit(Limit *node, EState *estate, int eflags)
limitstate = makeNode(LimitState);
limitstate->ps.plan = (Plan *) node;
limitstate->ps.state = estate;
+ limitstate->ps.ExecProcNode = ExecLimit;
limitstate->lstate = LIMIT_INITIAL;
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index f519794cf3..1badd48e29 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -35,9 +35,10 @@
* ExecLockRows
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecLockRows(LockRowsState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecLockRows(PlanState *pstate)
{
+ LockRowsState *node = castNode(LockRowsState, pstate);
TupleTableSlot *slot;
EState *estate;
PlanState *outerPlan;
@@ -361,6 +362,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
lrstate = makeNode(LockRowsState);
lrstate->ps.plan = (Plan *) node;
lrstate->ps.state = estate;
+ lrstate->ps.ExecProcNode = ExecLockRows;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 32b7269cda..a7be569887 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -35,9 +35,10 @@
*
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* result tuple from subplan */
-ExecMaterial(MaterialState *node)
+static TupleTableSlot * /* result tuple from subplan */
+ExecMaterial(PlanState *pstate)
{
+ MaterialState *node = castNode(MaterialState, pstate);
EState *estate;
ScanDirection dir;
bool forward;
@@ -171,6 +172,7 @@ ExecInitMaterial(Material *node, EState *estate, int eflags)
matstate = makeNode(MaterialState);
matstate->ss.ps.plan = (Plan *) node;
matstate->ss.ps.state = estate;
+ matstate->ss.ps.ExecProcNode = ExecMaterial;
/*
* We must have a tuplestore buffering the subplan output to do backward
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index fef83dbdbd..e98a0ff13f 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -50,6 +50,7 @@
*/
typedef int32 SlotNumber;
+static TupleTableSlot *ExecMergeAppend(PlanState *pstate);
static int heap_compare_slots(Datum a, Datum b, void *arg);
@@ -89,6 +90,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
*/
mergestate->ps.plan = (Plan *) node;
mergestate->ps.state = estate;
+ mergestate->ps.ExecProcNode = ExecMergeAppend;
mergestate->mergeplans = mergeplanstates;
mergestate->ms_nplans = nplans;
@@ -169,9 +171,10 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
* Handles iteration over multiple subplans.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecMergeAppend(MergeAppendState *node)
+static TupleTableSlot *
+ExecMergeAppend(PlanState *pstate)
{
+ MergeAppendState *node = castNode(MergeAppendState, pstate);
TupleTableSlot *result;
SlotNumber i;
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 6a145ee33a..822cf1ca37 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -595,9 +595,10 @@ ExecMergeTupleDump(MergeJoinState *mergestate)
* ExecMergeJoin
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecMergeJoin(MergeJoinState *node)
+static TupleTableSlot *
+ExecMergeJoin(PlanState *pstate)
{
+ MergeJoinState *node = castNode(MergeJoinState, pstate);
ExprState *joinqual;
ExprState *otherqual;
bool qualResult;
@@ -1445,6 +1446,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
mergestate = makeNode(MergeJoinState);
mergestate->js.ps.plan = (Plan *) node;
mergestate->js.ps.state = estate;
+ mergestate->js.ps.ExecProcNode = ExecMergeJoin;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 77ba15dd90..5ec00ed232 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1535,9 +1535,10 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
* if needed.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecModifyTable(ModifyTableState *node)
+static TupleTableSlot *
+ExecModifyTable(PlanState *pstate)
{
+ ModifyTableState *node = castNode(ModifyTableState, pstate);
EState *estate = node->ps.state;
CmdType operation = node->operation;
ResultRelInfo *saved_resultRelInfo;
@@ -1804,6 +1805,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate = makeNode(ModifyTableState);
mtstate->ps.plan = (Plan *) node;
mtstate->ps.state = estate;
+ mtstate->ps.ExecProcNode = ExecModifyTable;
mtstate->operation = operation;
mtstate->canSetTag = node->canSetTag;
diff --git a/src/backend/executor/nodeNamedtuplestorescan.c b/src/backend/executor/nodeNamedtuplestorescan.c
index 62234869ab..3a65b9f5dc 100644
--- a/src/backend/executor/nodeNamedtuplestorescan.c
+++ b/src/backend/executor/nodeNamedtuplestorescan.c
@@ -63,9 +63,11 @@ NamedTuplestoreScanRecheck(NamedTuplestoreScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecNamedTuplestoreScan(NamedTuplestoreScanState *node)
+static TupleTableSlot *
+ExecNamedTuplestoreScan(PlanState *pstate)
{
+ NamedTuplestoreScanState *node = castNode(NamedTuplestoreScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) NamedTuplestoreScanNext,
(ExecScanRecheckMtd) NamedTuplestoreScanRecheck);
@@ -97,6 +99,7 @@ ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflag
scanstate = makeNode(NamedTuplestoreScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecNamedTuplestoreScan;
enr = get_ENR(estate->es_queryEnv, node->enrname);
if (!enr)
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 0065fe601e..64bf7aa89e 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -56,9 +56,10 @@
* are prepared to return the first tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecNestLoop(NestLoopState *node)
+static TupleTableSlot *
+ExecNestLoop(PlanState *pstate)
{
+ NestLoopState *node = castNode(NestLoopState, pstate);
NestLoop *nl;
PlanState *innerPlan;
PlanState *outerPlan;
@@ -272,6 +273,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
nlstate = makeNode(NestLoopState);
nlstate->js.ps.plan = (Plan *) node;
nlstate->js.ps.state = estate;
+ nlstate->js.ps.ExecProcNode = ExecNestLoop;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c
index 01048cc826..327fbbdf5d 100644
--- a/src/backend/executor/nodeProjectSet.c
+++ b/src/backend/executor/nodeProjectSet.c
@@ -38,9 +38,10 @@ static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing);
* returning functions).
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecProjectSet(ProjectSetState *node)
+static TupleTableSlot *
+ExecProjectSet(PlanState *pstate)
{
+ ProjectSetState *node = castNode(ProjectSetState, pstate);
TupleTableSlot *outerTupleSlot;
TupleTableSlot *resultSlot;
PlanState *outerPlan;
@@ -212,6 +213,7 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
state = makeNode(ProjectSetState);
state->ps.plan = (Plan *) node;
state->ps.state = estate;
+ state->ps.ExecProcNode = ExecProjectSet;
state->pending_srf_tuples = false;
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index fc1c00d68f..5fb58c3fad 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -66,9 +66,10 @@ build_hash_table(RecursiveUnionState *rustate)
* 2.6 go back to 2.2
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecRecursiveUnion(RecursiveUnionState *node)
+static TupleTableSlot *
+ExecRecursiveUnion(PlanState *pstate)
{
+ RecursiveUnionState *node = castNode(RecursiveUnionState, pstate);
PlanState *outerPlan = outerPlanState(node);
PlanState *innerPlan = innerPlanState(node);
RecursiveUnion *plan = (RecursiveUnion *) node->ps.plan;
@@ -170,6 +171,7 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags)
rustate = makeNode(RecursiveUnionState);
rustate->ps.plan = (Plan *) node;
rustate->ps.state = estate;
+ rustate->ps.ExecProcNode = ExecRecursiveUnion;
rustate->eqfunctions = NULL;
rustate->hashfunctions = NULL;
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index a753a53419..a212584aa4 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -63,9 +63,10 @@
* 'nil' if the constant qualification is not satisfied.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecResult(ResultState *node)
+static TupleTableSlot *
+ExecResult(PlanState *pstate)
{
+ ResultState *node = castNode(ResultState, pstate);
TupleTableSlot *outerTupleSlot;
PlanState *outerPlan;
ExprContext *econtext;
@@ -188,6 +189,7 @@ ExecInitResult(Result *node, EState *estate, int eflags)
resstate = makeNode(ResultState);
resstate->ps.plan = (Plan *) node;
resstate->ps.state = estate;
+ resstate->ps.ExecProcNode = ExecResult;
resstate->rs_done = false;
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index b710ef7edf..f7dda8eb24 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -96,10 +96,10 @@ SampleRecheck(SampleScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSampleScan(SampleScanState *node)
+static TupleTableSlot *
+ExecSampleScan(PlanState *pstate)
{
- return ExecScan((ScanState *) node,
+ return ExecScan((ScanState *) pstate,
(ExecScanAccessMtd) SampleNext,
(ExecScanRecheckMtd) SampleRecheck);
}
@@ -153,6 +153,7 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
scanstate = makeNode(SampleScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecSampleScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 307df87c82..1814465b96 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -121,10 +121,10 @@ SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSeqScan(SeqScanState *node)
+static TupleTableSlot *
+ExecSeqScan(PlanState *pstate)
{
- return ExecScan((ScanState *) node,
+ return ExecScan((ScanState *) pstate,
(ExecScanAccessMtd) SeqNext,
(ExecScanRecheckMtd) SeqRecheck);
}
@@ -177,6 +177,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
scanstate = makeNode(SeqScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecSeqScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 9c7812e519..42388c53b0 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -179,9 +179,10 @@ set_output_count(SetOpState *setopstate, SetOpStatePerGroup pergroup)
* ExecSetOp
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecSetOp(SetOpState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecSetOp(PlanState *pstate)
{
+ SetOpState *node = castNode(SetOpState, pstate);
SetOp *plannode = (SetOp *) node->ps.plan;
TupleTableSlot *resultTupleSlot = node->ps.ps_ResultTupleSlot;
@@ -480,6 +481,7 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags)
setopstate = makeNode(SetOpState);
setopstate->ps.plan = (Plan *) node;
setopstate->ps.state = estate;
+ setopstate->ps.ExecProcNode = ExecSetOp;
setopstate->eqfunctions = NULL;
setopstate->hashfunctions = NULL;
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index 924b458df8..c04424e2a6 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -35,9 +35,10 @@
* -- the outer child is prepared to return the first tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSort(SortState *node)
+static TupleTableSlot *
+ExecSort(PlanState *pstate)
{
+ SortState *node = castNode(SortState, pstate);
EState *estate;
ScanDirection dir;
Tuplesortstate *tuplesortstate;
@@ -163,6 +164,7 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
sortstate = makeNode(SortState);
sortstate->ss.ps.plan = (Plan *) node;
sortstate->ss.ps.state = estate;
+ sortstate->ss.ps.ExecProcNode = ExecSort;
/*
* We must have random access to the sort output to do backward scan or
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index ae184700a6..088c92992e 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -79,9 +79,11 @@ SubqueryRecheck(SubqueryScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSubqueryScan(SubqueryScanState *node)
+static TupleTableSlot *
+ExecSubqueryScan(PlanState *pstate)
{
+ SubqueryScanState *node = castNode(SubqueryScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) SubqueryNext,
(ExecScanRecheckMtd) SubqueryRecheck);
@@ -109,6 +111,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
subquerystate = makeNode(SubqueryScanState);
subquerystate->ss.ps.plan = (Plan *) node;
subquerystate->ss.ps.state = estate;
+ subquerystate->ss.ps.ExecProcNode = ExecSubqueryScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index bb016ec8f6..822d72e0e2 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -93,9 +93,11 @@ TableFuncRecheck(TableFuncScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecTableFuncScan(TableFuncScanState *node)
+static TupleTableSlot *
+ExecTableFuncScan(PlanState *pstate)
{
+ TableFuncScanState *node = castNode(TableFuncScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) TableFuncNext,
(ExecScanRecheckMtd) TableFuncRecheck);
@@ -128,6 +130,7 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
scanstate = makeNode(TableFuncScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecTableFuncScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 96af2d21d9..4dad320cf7 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -442,9 +442,11 @@ TidRecheck(TidScanState *node, TupleTableSlot *slot)
* -- tidPtr is -1.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecTidScan(TidScanState *node)
+static TupleTableSlot *
+ExecTidScan(PlanState *pstate)
{
+ TidScanState *node = castNode(TidScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) TidNext,
(ExecScanRecheckMtd) TidRecheck);
@@ -516,6 +518,7 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
tidstate = makeNode(TidScanState);
tidstate->ss.ps.plan = (Plan *) node;
tidstate->ss.ps.state = estate;
+ tidstate->ss.ps.ExecProcNode = ExecTidScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 28cc1e90f8..f45d3a59c4 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -42,9 +42,10 @@
* ExecUnique
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecUnique(UniqueState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecUnique(PlanState *pstate)
{
+ UniqueState *node = castNode(UniqueState, pstate);
Unique *plannode = (Unique *) node->ps.plan;
TupleTableSlot *resultTupleSlot;
TupleTableSlot *slot;
@@ -122,6 +123,7 @@ ExecInitUnique(Unique *node, EState *estate, int eflags)
uniquestate = makeNode(UniqueState);
uniquestate->ps.plan = (Plan *) node;
uniquestate->ps.state = estate;
+ uniquestate->ps.ExecProcNode = ExecUnique;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index 9ee776c4c3..6eacaed8bb 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -185,9 +185,11 @@ ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecValuesScan(ValuesScanState *node)
+static TupleTableSlot *
+ExecValuesScan(PlanState *pstate)
{
+ ValuesScanState *node = castNode(ValuesScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) ValuesNext,
(ExecScanRecheckMtd) ValuesRecheck);
@@ -218,6 +220,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
scanstate = makeNode(ValuesScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecValuesScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 8f13fe0c73..295d937f86 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1587,9 +1587,10 @@ update_frametailpos(WindowObject winobj, TupleTableSlot *slot)
* returned rows is exactly the same as its outer subplan's result.
* -----------------
*/
-TupleTableSlot *
-ExecWindowAgg(WindowAggState *winstate)
+static TupleTableSlot *
+ExecWindowAgg(PlanState *pstate)
{
+ WindowAggState *winstate = castNode(WindowAggState, pstate);
ExprContext *econtext;
int i;
int numfuncs;
@@ -1788,6 +1789,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
winstate = makeNode(WindowAggState);
winstate->ss.ps.plan = (Plan *) node;
winstate->ss.ps.state = estate;
+ winstate->ss.ps.ExecProcNode = ExecWindowAgg;
/*
* Create expression contexts. We need two, one for per-input-tuple
diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c
index d7616be065..d5ffadda3e 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -77,9 +77,11 @@ WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecWorkTableScan(WorkTableScanState *node)
+static TupleTableSlot *
+ExecWorkTableScan(PlanState *pstate)
{
+ WorkTableScanState *node = castNode(WorkTableScanState, pstate);
+
/*
* On the first call, find the ancestor RecursiveUnion's state via the
* Param slot reserved for it. (We can't do this during node init because
@@ -144,6 +146,7 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
scanstate = makeNode(WorkTableScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
scanstate->rustate = NULL; /* we'll set this later */
/*
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 59c28b709e..8a44ed372f 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -14,6 +14,7 @@
#ifndef EXECUTOR_H
#define EXECUTOR_H
+#include "miscadmin.h" /* for CHECK_FOR_INTERRUPTS() */
#include "catalog/partition.h"
#include "executor/execdesc.h"
#include "nodes/parsenodes.h"
@@ -225,14 +226,37 @@ extern void EvalPlanQualBegin(EPQState *epqstate, EState *parentestate);
extern void EvalPlanQualEnd(EPQState *epqstate);
/*
- * prototypes from functions in execProcnode.c
+ * functions in execProcnode.c
*/
extern PlanState *ExecInitNode(Plan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecProcNode(PlanState *node);
extern Node *MultiExecProcNode(PlanState *node);
extern void ExecEndNode(PlanState *node);
extern bool ExecShutdownNode(PlanState *node);
+
+/* ----------------------------------------------------------------
+ * ExecProcNode
+ *
+ * Execute the given node to return a(nother) tuple.
+ * ----------------------------------------------------------------
+ */
+#ifndef FRONTEND
+static inline TupleTableSlot *
+ExecProcNode(PlanState *node)
+{
+ TupleTableSlot *result;
+
+ CHECK_FOR_INTERRUPTS();
+
+ if (node->chgParam != NULL) /* something changed */
+ ExecReScan(node); /* let ReScan handle this */
+
+ result = node->ExecProcNode(node);
+
+ return result;
+}
+#endif
+
/*
* prototypes from functions in execExpr.c
*/
diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h
index fa11ba93a6..eff5af9c2a 100644
--- a/src/include/executor/nodeAgg.h
+++ b/src/include/executor/nodeAgg.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern AggState *ExecInitAgg(Agg *node, EState *estate, int eflags);
-extern TupleTableSlot *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 ee0b6ad23d..4e38a1380e 100644
--- a/src/include/executor/nodeAppend.h
+++ b/src/include/executor/nodeAppend.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern AppendState *ExecInitAppend(Append *node, EState *estate, int eflags);
-extern TupleTableSlot *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 f477d1c772..c77694cf22 100644
--- a/src/include/executor/nodeBitmapHeapscan.h
+++ b/src/include/executor/nodeBitmapHeapscan.h
@@ -18,7 +18,6 @@
#include "access/parallel.h"
extern BitmapHeapScanState *ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecEndBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecReScanBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecBitmapHeapEstimate(BitmapHeapScanState *node,
diff --git a/src/include/executor/nodeCtescan.h b/src/include/executor/nodeCtescan.h
index 397bdfdd1c..d2fbcbd586 100644
--- a/src/include/executor/nodeCtescan.h
+++ b/src/include/executor/nodeCtescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern CteScanState *ExecInitCteScan(CteScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 e81bcf7f21..a1cc63ae1f 100644
--- a/src/include/executor/nodeCustom.h
+++ b/src/include/executor/nodeCustom.h
@@ -21,7 +21,6 @@
*/
extern CustomScanState *ExecInitCustomScan(CustomScan *custom_scan,
EState *estate, int eflags);
-extern TupleTableSlot *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 3ff4ecd8c9..0b662597d8 100644
--- a/src/include/executor/nodeForeignscan.h
+++ b/src/include/executor/nodeForeignscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern ForeignScanState *ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 5e830ebdea..aaa9d8c316 100644
--- a/src/include/executor/nodeFunctionscan.h
+++ b/src/include/executor/nodeFunctionscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 b0006934d4..189bd70041 100644
--- a/src/include/executor/nodeGather.h
+++ b/src/include/executor/nodeGather.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern GatherState *ExecInitGather(Gather *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecGather(GatherState *node);
extern void ExecEndGather(GatherState *node);
extern void ExecShutdownGather(GatherState *node);
extern void ExecReScanGather(GatherState *node);
diff --git a/src/include/executor/nodeGatherMerge.h b/src/include/executor/nodeGatherMerge.h
index 14b31a086c..0154d73312 100644
--- a/src/include/executor/nodeGatherMerge.h
+++ b/src/include/executor/nodeGatherMerge.h
@@ -19,7 +19,6 @@
extern GatherMergeState *ExecInitGatherMerge(GatherMerge *node,
EState *estate,
int eflags);
-extern TupleTableSlot *ExecGatherMerge(GatherMergeState *node);
extern void ExecEndGatherMerge(GatherMergeState *node);
extern void ExecReScanGatherMerge(GatherMergeState *node);
extern void ExecShutdownGatherMerge(GatherMergeState *node);
diff --git a/src/include/executor/nodeGroup.h b/src/include/executor/nodeGroup.h
index 7358b61707..b0d7e312c9 100644
--- a/src/include/executor/nodeGroup.h
+++ b/src/include/executor/nodeGroup.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern GroupState *ExecInitGroup(Group *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecGroup(GroupState *node);
extern void ExecEndGroup(GroupState *node);
extern void ExecReScanGroup(GroupState *node);
diff --git a/src/include/executor/nodeHashjoin.h b/src/include/executor/nodeHashjoin.h
index 541c81edc7..7469bfbf60 100644
--- a/src/include/executor/nodeHashjoin.h
+++ b/src/include/executor/nodeHashjoin.h
@@ -18,7 +18,6 @@
#include "storage/buffile.h"
extern HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *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 cf227daae0..c8a709c26e 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -18,7 +18,6 @@
#include "access/parallel.h"
extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 0118234eca..1668e347ee 100644
--- a/src/include/executor/nodeIndexscan.h
+++ b/src/include/executor/nodeIndexscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern IndexScanState *ExecInitIndexScan(IndexScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 7bb20d9978..db65b5524c 100644
--- a/src/include/executor/nodeLimit.h
+++ b/src/include/executor/nodeLimit.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern LimitState *ExecInitLimit(Limit *node, EState *estate, int eflags);
-extern TupleTableSlot *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 6b90756e4c..c9d05b87f1 100644
--- a/src/include/executor/nodeLockRows.h
+++ b/src/include/executor/nodeLockRows.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern LockRowsState *ExecInitLockRows(LockRows *node, EState *estate, int eflags);
-extern TupleTableSlot *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 f69abbca82..4b3c2578c9 100644
--- a/src/include/executor/nodeMaterial.h
+++ b/src/include/executor/nodeMaterial.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MaterialState *ExecInitMaterial(Material *node, EState *estate, int eflags);
-extern TupleTableSlot *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 3cc6ef549b..a0ccbae965 100644
--- a/src/include/executor/nodeMergeAppend.h
+++ b/src/include/executor/nodeMergeAppend.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MergeAppendState *ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags);
-extern TupleTableSlot *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 32df25ae8b..d20e41505d 100644
--- a/src/include/executor/nodeMergejoin.h
+++ b/src/include/executor/nodeMergejoin.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *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 5a406f236d..a2e7af98de 100644
--- a/src/include/executor/nodeModifyTable.h
+++ b/src/include/executor/nodeModifyTable.h
@@ -16,7 +16,6 @@
#include "nodes/execnodes.h"
extern ModifyTableState *ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecModifyTable(ModifyTableState *node);
extern void ExecEndModifyTable(ModifyTableState *node);
extern void ExecReScanModifyTable(ModifyTableState *node);
diff --git a/src/include/executor/nodeNamedtuplestorescan.h b/src/include/executor/nodeNamedtuplestorescan.h
index 7f72fbe98a..395d978f62 100644
--- a/src/include/executor/nodeNamedtuplestorescan.h
+++ b/src/include/executor/nodeNamedtuplestorescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern NamedTuplestoreScanState *ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecNamedTuplestoreScan(NamedTuplestoreScanState *node);
extern void ExecEndNamedTuplestoreScan(NamedTuplestoreScanState *node);
extern void ExecReScanNamedTuplestoreScan(NamedTuplestoreScanState *node);
diff --git a/src/include/executor/nodeNestloop.h b/src/include/executor/nodeNestloop.h
index 8e0fcc1922..0d6486cc57 100644
--- a/src/include/executor/nodeNestloop.h
+++ b/src/include/executor/nodeNestloop.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecNestLoop(NestLoopState *node);
extern void ExecEndNestLoop(NestLoopState *node);
extern void ExecReScanNestLoop(NestLoopState *node);
diff --git a/src/include/executor/nodeProjectSet.h b/src/include/executor/nodeProjectSet.h
index 2f6999e8db..a0b0521f8d 100644
--- a/src/include/executor/nodeProjectSet.h
+++ b/src/include/executor/nodeProjectSet.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ProjectSetState *ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecProjectSet(ProjectSetState *node);
extern void ExecEndProjectSet(ProjectSetState *node);
extern void ExecReScanProjectSet(ProjectSetState *node);
diff --git a/src/include/executor/nodeRecursiveunion.h b/src/include/executor/nodeRecursiveunion.h
index f0eba05bee..e6ce1b4783 100644
--- a/src/include/executor/nodeRecursiveunion.h
+++ b/src/include/executor/nodeRecursiveunion.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern RecursiveUnionState *ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags);
-extern TupleTableSlot *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 61d3cb2cc2..20e0063410 100644
--- a/src/include/executor/nodeResult.h
+++ b/src/include/executor/nodeResult.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ResultState *ExecInitResult(Result *node, EState *estate, int eflags);
-extern TupleTableSlot *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 ed06e77e4e..607bbd9412 100644
--- a/src/include/executor/nodeSamplescan.h
+++ b/src/include/executor/nodeSamplescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SampleScanState *ExecInitSampleScan(SampleScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 06e0686b0b..0fba79f8de 100644
--- a/src/include/executor/nodeSeqscan.h
+++ b/src/include/executor/nodeSeqscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern SeqScanState *ExecInitSeqScan(SeqScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 af85977183..c15f945046 100644
--- a/src/include/executor/nodeSetOp.h
+++ b/src/include/executor/nodeSetOp.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate, int eflags);
-extern TupleTableSlot *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 1d2b7130b3..ed0e9dbb53 100644
--- a/src/include/executor/nodeSort.h
+++ b/src/include/executor/nodeSort.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SortState *ExecInitSort(Sort *node, EState *estate, int eflags);
-extern TupleTableSlot *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 c852e2947f..710e050285 100644
--- a/src/include/executor/nodeSubqueryscan.h
+++ b/src/include/executor/nodeSubqueryscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SubqueryScanState *ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSubqueryScan(SubqueryScanState *node);
extern void ExecEndSubqueryScan(SubqueryScanState *node);
extern void ExecReScanSubqueryScan(SubqueryScanState *node);
diff --git a/src/include/executor/nodeTableFuncscan.h b/src/include/executor/nodeTableFuncscan.h
index c58156e99c..c4672c0ac0 100644
--- a/src/include/executor/nodeTableFuncscan.h
+++ b/src/include/executor/nodeTableFuncscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern TableFuncScanState *ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecTableFuncScan(TableFuncScanState *node);
extern void ExecEndTableFuncScan(TableFuncScanState *node);
extern void ExecReScanTableFuncScan(TableFuncScanState *node);
diff --git a/src/include/executor/nodeTidscan.h b/src/include/executor/nodeTidscan.h
index d07ed7c864..e68aaf3829 100644
--- a/src/include/executor/nodeTidscan.h
+++ b/src/include/executor/nodeTidscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern TidScanState *ExecInitTidScan(TidScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 3d0ac9dde1..008774ae0f 100644
--- a/src/include/executor/nodeUnique.h
+++ b/src/include/executor/nodeUnique.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern UniqueState *ExecInitUnique(Unique *node, EState *estate, int eflags);
-extern TupleTableSlot *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 c28bb1acce..772a5e9705 100644
--- a/src/include/executor/nodeValuesscan.h
+++ b/src/include/executor/nodeValuesscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ValuesScanState *ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 db1ad60677..1c177309ae 100644
--- a/src/include/executor/nodeWindowAgg.h
+++ b/src/include/executor/nodeWindowAgg.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern WindowAggState *ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags);
-extern TupleTableSlot *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 c222d9f6b4..df05e75111 100644
--- a/src/include/executor/nodeWorktablescan.h
+++ b/src/include/executor/nodeWorktablescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern WorkTableScanState *ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 85fac8ab91..4f78761462 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -818,6 +818,17 @@ typedef struct DomainConstraintState
* ----------------------------------------------------------------
*/
+struct PlanState;
+
+/* ----------------
+ * ExecProcNodeCB
+ *
+ * This is the callback called by ExecProcNode to return tuples from an
+ * executor node.
+ * ----------------
+ */
+typedef TupleTableSlot* (*ExecProcNodeCB) (struct PlanState *node);
+
/* ----------------
* PlanState node
*
@@ -835,6 +846,10 @@ typedef struct PlanState
* nodes point to one EState for the whole
* top-level plan */
+ ExecProcNodeCB ExecProcNode; /* callback to execute node */
+ ExecProcNodeCB ExecProcNodeReal; /* actual callback, if above is a
+ * wrapper */
+
Instrumentation *instrument; /* Optional runtime stats for this node */
WorkerInstrumentation *worker_instrument; /* per-worker instrumentation */
--
2.13.1.392.g8d1b10321b.dirty
On 21/07/2017 13:40, Andres Freund wrote:
Attached is a
patch that converts just ExecProcNode. The big change in comparison to
the earlier patch is that the assignment of the callback is now done in
the respective ExecInit* routines. As a consequence the ExecProcNode
callbacks now are static.
Thanks for working on it. Just in case, I reviewed the patch and didn't
find any issue with it.
--
Julien Rouhaud
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@anarazel.de> writes:
On 2017-07-18 16:53:43 -0400, Tom Lane wrote:
BTW, I don't see why you really need to mess with anything except
ExecProcNode? Surely the other cases such as MultiExecProcNode are
not called often enough to justify changing them away from the
switch technology. Yeah, maybe it would be a bit cleaner if they
all looked alike ... but if you're trying to make a patch that's
as little invasive as possible for v10, I'd suggest converting just
ExecProcNode to this style.
Yea, I was making that statement when not aiming for v10. Attached is a
patch that converts just ExecProcNode.
I read through this patch (didn't test it at all yet).
I dislike having the miscadmin.h include in executor.h - but I don't
quite see a better alternative.
I seriously, seriously, seriously dislike that. You practically might as
well put miscadmin.h into postgres.h. Instead, what do you think of
requiring the individual ExecProcNode functions to perform
CHECK_FOR_INTERRUPTS? Since they're already responsible for doing that
if they have any long-running internal loops, this doesn't seem like a
modularity violation. It is a risk for bugs-of-omission, sure, but so
are a lot of other things that the per-node code has to do.
There might be something to be said for handling the chgParam/rescan tests
similarly. That would reduce the ExecProcNode macro to a triviality,
which would be a good thing for understandability of the code I think.
Some other thoughts:
* I think the comments need more work. Am willing to make a pass over
that if you want.
* In most places, if there's an immediate return-if-trivial-case test,
we check stack depth only after that. There's no point in checking
and then returning; either you already crashed, or you're at peak
stack so far as this code path is concerned.
* Can we redefine the ExecCustomScan function pointer as type
ExecProcNodeCB, eliminating the unsightly cast in nodeCustom.c?
* The various callers of ExecScan() are pretty inconsistently coded.
I don't care that much whether they use castNode() or just forcibly
cast to ScanState*, but let's make them all look the same.
* I believe the usual term for what these function pointers are is
"methods", not "callbacks". Certainly we'd call them that if we
were working in C++.
I still think we should backpatch at least the check_stack_depth() calls
in ExecInitNode(), ExecEndNode().
No big objection, although I'm not sure it's necessary.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Jul 18, 2017 at 01:04:10PM -0700, Andres Freund wrote:
Ok, I'll flesh out the patch till Thursday. But I do think we're going
to have to do something about the back branches, too.
This PostgreSQL 10 open item is past due for your status update. Kindly send
a status update within 24 hours, and include a date for your subsequent status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On July 24, 2017 7:10:19 AM GMT+01:00, Noah Misch <noah@leadboat.com> wrote:
On Tue, Jul 18, 2017 at 01:04:10PM -0700, Andres Freund wrote:
Ok, I'll flesh out the patch till Thursday. But I do think we're
going
to have to do something about the back branches, too.
This PostgreSQL 10 open item is past due for your status update.
Kindly send
a status update within 24 hours, and include a date for your subsequent
status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
I sent out a note fleshed out patch last week, which Tom reviewed. Planning to update it to address that review today or tomorrow.
Andres
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi,
On 2017-07-21 20:17:54 -0400, Tom Lane wrote:
I dislike having the miscadmin.h include in executor.h - but I don't
quite see a better alternative.I seriously, seriously, seriously dislike that. You practically might as
well put miscadmin.h into postgres.h. Instead, what do you think of
requiring the individual ExecProcNode functions to perform
CHECK_FOR_INTERRUPTS? Since they're already responsible for doing that
if they have any long-running internal loops, this doesn't seem like a
modularity violation. It is a risk for bugs-of-omission, sure, but so
are a lot of other things that the per-node code has to do.
That'd work. Another alternative would be to move the inline definition
of ExecProcNode() (and probably a bunch of other related functions) into
a more internals oriented header. It seems likely that we're going to
add more inline functions to the executor, and that'd reduce the
coupling of external and internal users a bit.
* I think the comments need more work. Am willing to make a pass over
that if you want.
That'd be good, but let's wait till we have something more final.
* In most places, if there's an immediate return-if-trivial-case test,
we check stack depth only after that. There's no point in checking
and then returning; either you already crashed, or you're at peak
stack so far as this code path is concerned.
I went back/forth a bit on that one. The calling code might call other
functions that go deeper on the stack, which won't have the checks. Fine
with moving, just wanted to explain why I got there.
* Can we redefine the ExecCustomScan function pointer as type
ExecProcNodeCB, eliminating the unsightly cast in nodeCustom.c?
That'd change an "extension API", which is why I skipped it at this
point of the release cycle. It's not like we didn't have this type of
cast all over before. Ok, with changing it, but that's where I came
down.
* The various callers of ExecScan() are pretty inconsistently coded.
I don't care that much whether they use castNode() or just forcibly
cast to ScanState*, but let's make them all look the same.
I tried changed the minimum, perfectly fine to move to castNode in a
wholesale manner. Btw, I really want to get rid of ExecScan(), at least
as an external function. Does a lot of unnecessary things in a lot of
cases, and makes branch prediction a lot worse. Not v10 stuff tho.
* I believe the usual term for what these function pointers are is
"methods", not "callbacks". Certainly we'd call them that if we
were working in C++.
K.
- Andres
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@anarazel.de> writes:
On 2017-07-21 20:17:54 -0400, Tom Lane wrote:
I dislike having the miscadmin.h include in executor.h - but I don't
quite see a better alternative.
I seriously, seriously, seriously dislike that. You practically might as
well put miscadmin.h into postgres.h. Instead, what do you think of
requiring the individual ExecProcNode functions to perform
CHECK_FOR_INTERRUPTS? Since they're already responsible for doing that
if they have any long-running internal loops, this doesn't seem like a
modularity violation. It is a risk for bugs-of-omission, sure, but so
are a lot of other things that the per-node code has to do.
That'd work. Another alternative would be to move the inline definition
of ExecProcNode() (and probably a bunch of other related functions) into
a more internals oriented header. It seems likely that we're going to
add more inline functions to the executor, and that'd reduce the
coupling of external and internal users a bit.
Well, it still ends up that the callers of ExecProcNode need to include
miscadmin.h, whereas if we move it into the per-node functions, then the
per-node files need to include miscadmin.h. I think the latter is better
because those files may need to have other CHECK_FOR_INTERRUPTS calls
anyway. It's less clear from a modularity standpoint that executor
callers should need miscadmin.h. (Or in short, I'm not really okay
with *any* header file including miscadmin.h.)
* I think the comments need more work. Am willing to make a pass over
that if you want.
That'd be good, but let's wait till we have something more final.
Agreed, I'll wait till you produce another version.
* Can we redefine the ExecCustomScan function pointer as type
ExecProcNodeCB, eliminating the unsightly cast in nodeCustom.c?
That'd change an "extension API", which is why I skipped it at this
point of the release cycle. It's not like we didn't have this type of
cast all over before. Ok, with changing it, but that's where I came
down.
Is this patch really not changing anything else that a custom-scan
extension would touch? If not, I'm okay with postponing this bit
of cleanup to v11.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2017-07-24 13:27:58 -0400, Tom Lane wrote:
Andres Freund <andres@anarazel.de> writes:
I seriously, seriously, seriously dislike that. You practically might as
well put miscadmin.h into postgres.h. Instead, what do you think of
requiring the individual ExecProcNode functions to perform
CHECK_FOR_INTERRUPTS? Since they're already responsible for doing that
if they have any long-running internal loops, this doesn't seem like a
modularity violation. It is a risk for bugs-of-omission, sure, but so
are a lot of other things that the per-node code has to do.That'd work. Another alternative would be to move the inline definition
of ExecProcNode() (and probably a bunch of other related functions) into
a more internals oriented header. It seems likely that we're going to
add more inline functions to the executor, and that'd reduce the
coupling of external and internal users a bit.Well, it still ends up that the callers of ExecProcNode need to include
miscadmin.h, whereas if we move it into the per-node functions, then the
per-node files need to include miscadmin.h. I think the latter is better
because those files may need to have other CHECK_FOR_INTERRUPTS calls
anyway.
It's less clear from a modularity standpoint that executor
callers should need miscadmin.h.
Well, that's why I'm pondering an executor_internal.h or something -
there shouldn't be ExecProcNode() callers that don't also need CFI(),
and no executor callers should need ExecProcNode(). executor.h right now
really defines infrastructure to *use* the executor
(Executor{Start,Run,Finish,End,Rewind}), functions internal to the
executor (lots of initialization functions, EPQ, partition logic), some
things inbetween (e.g. expression related stuff), and some things that
really should be separate ExecOpenIndices etc, execReplication.c
functions. But that's not something we can easily clear up just now.
(Or in short, I'm not really okay with *any* header file including
miscadmin.h.)
Perhaps that's a sign that we should split it up? It's a weird grab bag
atm. utils/interrupt.h or such would e.g. make sense for for the
*INTERRUPTS, and *CRIT_SECTION macros, as well as ProcessInterrupts()
itself, which imo isn't super well placed in postgres.c
either. Including utils/interrupt.h in a header would be much less
odious in my opinion than including miscadmin.h.
* Can we redefine the ExecCustomScan function pointer as type
ExecProcNodeCB, eliminating the unsightly cast in nodeCustom.c?That'd change an "extension API", which is why I skipped it at this
point of the release cycle. It's not like we didn't have this type of
cast all over before. Ok, with changing it, but that's where I came
down.Is this patch really not changing anything else that a custom-scan
extension would touch? If not, I'm okay with postponing this bit
of cleanup to v11.
Not that I can see - I've build & tested citus which uses custom scans
these days with and without patch without trouble. Nor do I see any
change in the current patch that'd be troublesome - after all the
API of ExecProcNode() stays the same.
- Andres
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi,
On 2017-07-24 13:27:58 -0400, Tom Lane wrote:
Andres Freund <andres@anarazel.de> writes:
* I think the comments need more work. Am willing to make a pass over
that if you want.That'd be good, but let's wait till we have something more final.
Agreed, I'll wait till you produce another version.
Attached. Did a bunch of cleanup myself already.
I've moved the CHECK_FOR_INTERRUPTS() to the callsites. That
unsurprisingly ends up being somewhat verbose, and there's a bunch of
minor judgement calls where exactly to place them. While doing so I've
also added a few extra ones. Did this in a separate patch to make it
easier to review.
I'm pretty jetlagged right now, so I want to do another pass to make
sure I didn't forget any CFI()s, but the general shape looks right.
Tried to address the rest of your feedback too.
* Can we redefine the ExecCustomScan function pointer as type
ExecProcNodeCB, eliminating the unsightly cast in nodeCustom.c?That'd change an "extension API", which is why I skipped it at this
point of the release cycle. It's not like we didn't have this type of
cast all over before. Ok, with changing it, but that's where I came
down.Is this patch really not changing anything else that a custom-scan
extension would touch? If not, I'm okay with postponing this bit
of cleanup to v11.
FWIW, I've reintroduced ExecCustomScan() which I'd previously removed,
because it now contains a CHECK_FOR_INTERRUPTS(). So this seems moot.
Greetings,
Andres Freund
Attachments:
0001-Move-interrupt-checking-from-ExecProcNode-to-callers.patchtext/x-patch; charset=us-asciiDownload
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
0002-Move-ExecProcNode-from-dispatch-to-function-pointer-.patchtext/x-patch; charset=us-asciiDownload
From 56af1543ed85b5779b7fa2b33bdc8ec163d3df06 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Mon, 17 Jul 2017 00:33:49 -0700
Subject: [PATCH 2/2] Move ExecProcNode from dispatch to function pointer based
model.
This allows us to add stack-depth checks the first time an executor
node is called, and skip that overhead on following calls.
Additionally it yields a nice speedup.
We should move towards that model for further routines, but as this is
required for v10, it seems better to only do the necessary (which
already is quite large).
Todo: Expand (scope, need in v10) & link.
Author: Andres Freund
Reported-By: Julien Rouhaud
Discussion:
https://postgr.es/m/22833.1490390175@sss.pgh.pa.us
https://postgr.es/m/b0af9eaa-130c-60d0-9e4e-7a135b1e0c76@dalibo.com
---
src/backend/executor/execProcnode.c | 246 +++++++------------------
src/backend/executor/nodeAgg.c | 6 +-
src/backend/executor/nodeAppend.c | 8 +-
src/backend/executor/nodeBitmapHeapscan.c | 7 +-
src/backend/executor/nodeCtescan.c | 7 +-
src/backend/executor/nodeCustom.c | 11 +-
src/backend/executor/nodeForeignscan.c | 9 +-
src/backend/executor/nodeFunctionscan.c | 7 +-
src/backend/executor/nodeGather.c | 7 +-
src/backend/executor/nodeGatherMerge.c | 7 +-
src/backend/executor/nodeGroup.c | 6 +-
src/backend/executor/nodeHashjoin.c | 6 +-
src/backend/executor/nodeIndexonlyscan.c | 7 +-
src/backend/executor/nodeIndexscan.c | 7 +-
src/backend/executor/nodeLimit.c | 6 +-
src/backend/executor/nodeLockRows.c | 6 +-
src/backend/executor/nodeMaterial.c | 6 +-
src/backend/executor/nodeMergeAppend.c | 7 +-
src/backend/executor/nodeMergejoin.c | 6 +-
src/backend/executor/nodeModifyTable.c | 6 +-
src/backend/executor/nodeNamedtuplestorescan.c | 7 +-
src/backend/executor/nodeNestloop.c | 6 +-
src/backend/executor/nodeProjectSet.c | 6 +-
src/backend/executor/nodeRecursiveunion.c | 6 +-
src/backend/executor/nodeResult.c | 6 +-
src/backend/executor/nodeSamplescan.c | 9 +-
src/backend/executor/nodeSeqscan.c | 9 +-
src/backend/executor/nodeSetOp.c | 6 +-
src/backend/executor/nodeSort.c | 6 +-
src/backend/executor/nodeSubqueryscan.c | 7 +-
src/backend/executor/nodeTableFuncscan.c | 7 +-
src/backend/executor/nodeTidscan.c | 7 +-
src/backend/executor/nodeUnique.c | 6 +-
src/backend/executor/nodeValuesscan.c | 7 +-
src/backend/executor/nodeWindowAgg.c | 6 +-
src/backend/executor/nodeWorktablescan.c | 7 +-
src/include/executor/executor.h | 25 ++-
src/include/executor/nodeAgg.h | 1 -
src/include/executor/nodeAppend.h | 1 -
src/include/executor/nodeBitmapHeapscan.h | 1 -
src/include/executor/nodeCtescan.h | 1 -
src/include/executor/nodeCustom.h | 1 -
src/include/executor/nodeForeignscan.h | 1 -
src/include/executor/nodeFunctionscan.h | 1 -
src/include/executor/nodeGather.h | 1 -
src/include/executor/nodeGatherMerge.h | 1 -
src/include/executor/nodeGroup.h | 1 -
src/include/executor/nodeHashjoin.h | 1 -
src/include/executor/nodeIndexonlyscan.h | 1 -
src/include/executor/nodeIndexscan.h | 1 -
src/include/executor/nodeLimit.h | 1 -
src/include/executor/nodeLockRows.h | 1 -
src/include/executor/nodeMaterial.h | 1 -
src/include/executor/nodeMergeAppend.h | 1 -
src/include/executor/nodeMergejoin.h | 1 -
src/include/executor/nodeModifyTable.h | 1 -
src/include/executor/nodeNamedtuplestorescan.h | 1 -
src/include/executor/nodeNestloop.h | 1 -
src/include/executor/nodeProjectSet.h | 1 -
src/include/executor/nodeRecursiveunion.h | 1 -
src/include/executor/nodeResult.h | 1 -
src/include/executor/nodeSamplescan.h | 1 -
src/include/executor/nodeSeqscan.h | 1 -
src/include/executor/nodeSetOp.h | 1 -
src/include/executor/nodeSort.h | 1 -
src/include/executor/nodeSubqueryscan.h | 1 -
src/include/executor/nodeTableFuncscan.h | 1 -
src/include/executor/nodeTidscan.h | 1 -
src/include/executor/nodeUnique.h | 1 -
src/include/executor/nodeValuesscan.h | 1 -
src/include/executor/nodeWindowAgg.h | 1 -
src/include/executor/nodeWorktablescan.h | 1 -
src/include/nodes/execnodes.h | 15 ++
73 files changed, 271 insertions(+), 290 deletions(-)
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 20fd9f822e..f4fbd18fa4 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -23,9 +23,9 @@
* ExecEndNode - shut down a plan node and its subplans
*
* NOTES
- * This used to be three files. It is now all combined into
- * one file so that it is easier to keep ExecInitNode, ExecProcNode,
- * and ExecEndNode in sync when new nodes are added.
+ * This used to be three files. It is now all combined into one file so
+ * that it is easier to keep the dispatch routines in sync when new nodes
+ * are added.
*
* EXAMPLE
* Suppose we want the age of the manager of the shoe department and
@@ -122,6 +122,10 @@
#include "miscadmin.h"
+static TupleTableSlot *ExecProcNodeFirst(PlanState *node);
+static TupleTableSlot *ExecProcNodeInstr(PlanState *node);
+
+
/* ------------------------------------------------------------------------
* ExecInitNode
*
@@ -149,6 +153,13 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
if (node == NULL)
return NULL;
+ /*
+ * Make sure there's enough stack available. Need to check here, in
+ * addition to ExecProcNode() (via ExecProcNodeFirst()), to ensure the
+ * stack isn't overrun while initializing the node tree.
+ */
+ check_stack_depth();
+
switch (nodeTag(node))
{
/*
@@ -364,6 +375,13 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
break;
}
+ /*
+ * Add a wrapper around the ExecProcNode callback that checks stack-depth
+ * first.
+ */
+ result->ExecProcNodeReal = result->ExecProcNode;
+ result->ExecProcNode = ExecProcNodeFirst;
+
/*
* Initialize any initPlans present in this node. The planner put them in
* a separate list for us.
@@ -388,195 +406,53 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
}
-/* ----------------------------------------------------------------
- * ExecProcNode
- *
- * Execute the given node to return a(nother) tuple.
- * ----------------------------------------------------------------
+/*
+ * ExecProcNode helper that performs some additional checks, before calling
+ * the relevant executor node (possibly via an instrumentation wrapper).
*/
-TupleTableSlot *
-ExecProcNode(PlanState *node)
+static TupleTableSlot *
+ExecProcNodeFirst(PlanState *node)
{
- TupleTableSlot *result;
-
if (node->chgParam != NULL) /* something changed */
ExecReScan(node); /* let ReScan handle this */
+ /*
+ * Perform stack depth check during the first execution of the node. We
+ * only do so the first time round because it turns out to not be cheap on
+ * some common architectures (eg. x86).
+ */
+ check_stack_depth();
+
+ /*
+ * If instrumentation is required, change the wrapper to one that just
+ * does the instrumentation. Otherwise we can dispense with all wrappers
+ * and have ExecProcNode() directly call the relevant function from now
+ * on.
+ */
if (node->instrument)
- InstrStartNode(node->instrument);
+ node->ExecProcNode = ExecProcNodeInstr;
+ else
+ node->ExecProcNode = node->ExecProcNodeReal;
- switch (nodeTag(node))
- {
- /*
- * control nodes
- */
- case T_ResultState:
- result = ExecResult((ResultState *) node);
- break;
+ return node->ExecProcNode(node);
+}
- case T_ProjectSetState:
- result = ExecProjectSet((ProjectSetState *) node);
- break;
- case T_ModifyTableState:
- result = ExecModifyTable((ModifyTableState *) node);
- break;
+/*
+ * Wrapper for the real ExecProcNode handler invocation, that performs
+ * instrumentation. Keeping this a separate function allows to avoid the
+ * overhead for the common case where no instrumentation is required.
+ */
+static TupleTableSlot *
+ExecProcNodeInstr(PlanState *node)
+{
+ TupleTableSlot *result;
- case T_AppendState:
- result = ExecAppend((AppendState *) node);
- break;
+ InstrStartNode(node->instrument);
- case T_MergeAppendState:
- result = ExecMergeAppend((MergeAppendState *) node);
- break;
+ result = node->ExecProcNodeReal(node);
- case T_RecursiveUnionState:
- result = ExecRecursiveUnion((RecursiveUnionState *) node);
- break;
-
- /* BitmapAndState does not yield tuples */
-
- /* BitmapOrState does not yield tuples */
-
- /*
- * scan nodes
- */
- case T_SeqScanState:
- result = ExecSeqScan((SeqScanState *) node);
- break;
-
- case T_SampleScanState:
- result = ExecSampleScan((SampleScanState *) node);
- break;
-
- case T_IndexScanState:
- result = ExecIndexScan((IndexScanState *) node);
- break;
-
- case T_IndexOnlyScanState:
- result = ExecIndexOnlyScan((IndexOnlyScanState *) node);
- break;
-
- /* BitmapIndexScanState does not yield tuples */
-
- case T_BitmapHeapScanState:
- result = ExecBitmapHeapScan((BitmapHeapScanState *) node);
- break;
-
- case T_TidScanState:
- result = ExecTidScan((TidScanState *) node);
- break;
-
- case T_SubqueryScanState:
- result = ExecSubqueryScan((SubqueryScanState *) node);
- break;
-
- case T_FunctionScanState:
- result = ExecFunctionScan((FunctionScanState *) node);
- break;
-
- case T_TableFuncScanState:
- result = ExecTableFuncScan((TableFuncScanState *) node);
- break;
-
- case T_ValuesScanState:
- result = ExecValuesScan((ValuesScanState *) node);
- break;
-
- case T_CteScanState:
- result = ExecCteScan((CteScanState *) node);
- break;
-
- case T_NamedTuplestoreScanState:
- result = ExecNamedTuplestoreScan((NamedTuplestoreScanState *) node);
- break;
-
- case T_WorkTableScanState:
- result = ExecWorkTableScan((WorkTableScanState *) node);
- break;
-
- case T_ForeignScanState:
- result = ExecForeignScan((ForeignScanState *) node);
- break;
-
- case T_CustomScanState:
- result = ExecCustomScan((CustomScanState *) node);
- break;
-
- /*
- * join nodes
- */
- case T_NestLoopState:
- result = ExecNestLoop((NestLoopState *) node);
- break;
-
- case T_MergeJoinState:
- result = ExecMergeJoin((MergeJoinState *) node);
- break;
-
- case T_HashJoinState:
- result = ExecHashJoin((HashJoinState *) node);
- break;
-
- /*
- * materialization nodes
- */
- case T_MaterialState:
- result = ExecMaterial((MaterialState *) node);
- break;
-
- case T_SortState:
- result = ExecSort((SortState *) node);
- break;
-
- case T_GroupState:
- result = ExecGroup((GroupState *) node);
- break;
-
- case T_AggState:
- result = ExecAgg((AggState *) node);
- break;
-
- case T_WindowAggState:
- result = ExecWindowAgg((WindowAggState *) node);
- break;
-
- case T_UniqueState:
- result = ExecUnique((UniqueState *) node);
- break;
-
- case T_GatherState:
- result = ExecGather((GatherState *) node);
- break;
-
- case T_GatherMergeState:
- result = ExecGatherMerge((GatherMergeState *) node);
- break;
-
- case T_HashState:
- result = ExecHash((HashState *) node);
- break;
-
- case T_SetOpState:
- result = ExecSetOp((SetOpState *) node);
- break;
-
- case T_LockRowsState:
- result = ExecLockRows((LockRowsState *) node);
- break;
-
- case T_LimitState:
- result = ExecLimit((LimitState *) node);
- break;
-
- default:
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
- result = NULL;
- break;
- }
-
- if (node->instrument)
- InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
+ InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
return result;
}
@@ -600,6 +476,7 @@ MultiExecProcNode(PlanState *node)
{
Node *result;
+ check_stack_depth();
CHECK_FOR_INTERRUPTS();
if (node->chgParam != NULL) /* something changed */
@@ -657,6 +534,13 @@ ExecEndNode(PlanState *node)
if (node == NULL)
return;
+ /*
+ * Make sure there's enough stack available. Need to check here, in
+ * addition to ExecProcNode() (via ExecProcNodeFirst()), because it's not
+ * guaranteed that ExecProcNode() is reached for all nodes.
+ */
+ check_stack_depth();
+
if (node->chgParam != NULL)
{
bms_free(node->chgParam);
@@ -852,6 +736,8 @@ ExecEndNode(PlanState *node)
bool
ExecShutdownNode(PlanState *node)
{
+ check_stack_depth();
+
if (node == NULL)
return false;
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index f9073e79aa..7a95b13f58 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -2097,9 +2097,10 @@ lookup_hash_entries(AggState *aggstate)
* stored in the expression context to be used when ExecProject evaluates
* the result tuple.
*/
-TupleTableSlot *
-ExecAgg(AggState *node)
+static TupleTableSlot *
+ExecAgg(PlanState *pstate)
{
+ AggState *node = castNode(AggState, pstate);
TupleTableSlot *result = NULL;
if (!node->agg_done)
@@ -2689,6 +2690,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
aggstate = makeNode(AggState);
aggstate->ss.ps.plan = (Plan *) node;
aggstate->ss.ps.state = estate;
+ aggstate->ss.ps.ExecProcNode = ExecAgg;
aggstate->aggs = NIL;
aggstate->numaggs = 0;
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 58045e05e5..bed9bb8713 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -61,6 +61,7 @@
#include "executor/nodeAppend.h"
#include "miscadmin.h"
+static TupleTableSlot *ExecAppend(PlanState *pstate);
static bool exec_append_initialize_next(AppendState *appendstate);
@@ -147,6 +148,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
*/
appendstate->ps.plan = (Plan *) node;
appendstate->ps.state = estate;
+ appendstate->ps.ExecProcNode = ExecAppend;
appendstate->appendplans = appendplanstates;
appendstate->as_nplans = nplans;
@@ -197,9 +199,11 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
* Handles iteration over multiple subplans.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecAppend(AppendState *node)
+static TupleTableSlot *
+ExecAppend(PlanState *pstate)
{
+ AppendState *node = castNode(AppendState, pstate);
+
for (;;)
{
PlanState *subnode;
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 7e0ba030b7..4046f2ce78 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -662,9 +662,11 @@ BitmapHeapRecheck(BitmapHeapScanState *node, TupleTableSlot *slot)
* ExecBitmapHeapScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecBitmapHeapScan(BitmapHeapScanState *node)
+static TupleTableSlot *
+ExecBitmapHeapScan(PlanState *pstate)
{
+ BitmapHeapScanState *node = castNode(BitmapHeapScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) BitmapHeapNext,
(ExecScanRecheckMtd) BitmapHeapRecheck);
@@ -812,6 +814,7 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
scanstate = makeNode(BitmapHeapScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecBitmapHeapScan;
scanstate->tbm = NULL;
scanstate->tbmiterator = NULL;
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index e7d3c69c4b..be17c9c85d 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -151,9 +151,11 @@ CteScanRecheck(CteScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecCteScan(CteScanState *node)
+static TupleTableSlot *
+ExecCteScan(PlanState *pstate)
{
+ CteScanState *node = castNode(CteScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) CteScanNext,
(ExecScanRecheckMtd) CteScanRecheck);
@@ -193,6 +195,7 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
scanstate = makeNode(CteScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecCteScan;
scanstate->eflags = eflags;
scanstate->cte_table = NULL;
scanstate->eof_cte = false;
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index e28e41df59..ece0537798 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -21,6 +21,10 @@
#include "utils/memutils.h"
#include "utils/rel.h"
+
+static TupleTableSlot *ExecCustomScan(PlanState *pstate);
+
+
CustomScanState *
ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
{
@@ -45,6 +49,7 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
/* fill up fields of ScanState */
css->ss.ps.plan = &cscan->scan.plan;
css->ss.ps.state = estate;
+ css->ss.ps.ExecProcNode = ExecCustomScan;
/* create expression context for node */
ExecAssignExprContext(estate, &css->ss.ps);
@@ -102,9 +107,11 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
return css;
}
-TupleTableSlot *
-ExecCustomScan(CustomScanState *node)
+static TupleTableSlot *
+ExecCustomScan(PlanState *pstate)
{
+ CustomScanState *node = castNode(CustomScanState, pstate);
+
Assert(node->methods->ExecCustomScan != NULL);
CHECK_FOR_INTERRUPTS();
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 2873f24e36..4a84e7abf8 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -116,10 +116,12 @@ ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecForeignScan(ForeignScanState *node)
+static TupleTableSlot *
+ExecForeignScan(PlanState *pstate)
{
- return ExecScan((ScanState *) node,
+ ForeignScanState *node = castNode(ForeignScanState, pstate);
+
+ return ExecScan(&node->ss,
(ExecScanAccessMtd) ForeignNext,
(ExecScanRecheckMtd) ForeignRecheck);
}
@@ -147,6 +149,7 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
scanstate = makeNode(ForeignScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecForeignScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 3217d641d7..9f87a7e5cd 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -262,9 +262,11 @@ FunctionRecheck(FunctionScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecFunctionScan(FunctionScanState *node)
+static TupleTableSlot *
+ExecFunctionScan(PlanState *pstate)
{
+ FunctionScanState *node = castNode(FunctionScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) FunctionNext,
(ExecScanRecheckMtd) FunctionRecheck);
@@ -299,6 +301,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
scanstate = makeNode(FunctionScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecFunctionScan;
scanstate->eflags = eflags;
/*
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index 7f12b526ba..b2500f6f0c 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -43,6 +43,7 @@
#include "utils/rel.h"
+static TupleTableSlot *ExecGather(PlanState *pstate);
static TupleTableSlot *gather_getnext(GatherState *gatherstate);
static HeapTuple gather_readnext(GatherState *gatherstate);
static void ExecShutdownGatherWorkers(GatherState *node);
@@ -69,6 +70,7 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
gatherstate = makeNode(GatherState);
gatherstate->ps.plan = (Plan *) node;
gatherstate->ps.state = estate;
+ gatherstate->ps.ExecProcNode = ExecGather;
gatherstate->need_to_scan_locally = !node->single_copy;
/*
@@ -120,9 +122,10 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
* the next qualifying tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecGather(GatherState *node)
+static TupleTableSlot *
+ExecGather(PlanState *pstate)
{
+ GatherState *node = castNode(GatherState, pstate);
TupleTableSlot *fslot = node->funnel_slot;
int i;
TupleTableSlot *slot;
diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c
index a7065b4519..2fb7303d07 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -44,6 +44,7 @@ typedef struct GMReaderTupleBuffer
*/
#define MAX_TUPLE_STORE 10
+static TupleTableSlot *ExecGatherMerge(PlanState *pstate);
static int32 heap_compare_slots(Datum a, Datum b, void *arg);
static TupleTableSlot *gather_merge_getnext(GatherMergeState *gm_state);
static HeapTuple gm_readnext_tuple(GatherMergeState *gm_state, int nreader,
@@ -75,6 +76,7 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
gm_state = makeNode(GatherMergeState);
gm_state->ps.plan = (Plan *) node;
gm_state->ps.state = estate;
+ gm_state->ps.ExecProcNode = ExecGatherMerge;
/*
* Miscellaneous initialization
@@ -157,9 +159,10 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
* the next qualifying tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecGatherMerge(GatherMergeState *node)
+static TupleTableSlot *
+ExecGatherMerge(PlanState *pstate)
{
+ GatherMergeState *node = castNode(GatherMergeState, pstate);
TupleTableSlot *slot;
ExprContext *econtext;
int i;
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index a83d88efd8..83d06315e7 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -32,9 +32,10 @@
*
* Return one tuple for each group of matching input tuples.
*/
-TupleTableSlot *
-ExecGroup(GroupState *node)
+static TupleTableSlot *
+ExecGroup(PlanState *pstate)
{
+ GroupState *node = castNode(GroupState, pstate);
ExprContext *econtext;
int numCols;
AttrNumber *grpColIdx;
@@ -178,6 +179,7 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
grpstate = makeNode(GroupState);
grpstate->ss.ps.plan = (Plan *) node;
grpstate->ss.ps.state = estate;
+ grpstate->ss.ps.ExecProcNode = ExecGroup;
grpstate->grp_done = FALSE;
/*
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 0a9595948c..fc7bd2d8a6 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -58,9 +58,10 @@ static bool ExecHashJoinNewBatch(HashJoinState *hjstate);
* the other one is "outer".
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecHashJoin(HashJoinState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecHashJoin(PlanState *pstate)
{
+ HashJoinState *node = castNode(HashJoinState, pstate);
PlanState *outerNode;
HashState *hashNode;
ExprState *joinqual;
@@ -393,6 +394,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
hjstate = makeNode(HashJoinState);
hjstate->js.ps.plan = (Plan *) node;
hjstate->js.ps.state = estate;
+ hjstate->js.ps.ExecProcNode = ExecHashJoin;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 890e54416a..a7a5760fd7 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -303,9 +303,11 @@ IndexOnlyRecheck(IndexOnlyScanState *node, TupleTableSlot *slot)
* ExecIndexOnlyScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecIndexOnlyScan(IndexOnlyScanState *node)
+static TupleTableSlot *
+ExecIndexOnlyScan(PlanState *pstate)
{
+ IndexOnlyScanState *node = castNode(IndexOnlyScanState, pstate);
+
/*
* If we have runtime keys and they've not already been set up, do it now.
*/
@@ -473,6 +475,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
indexstate = makeNode(IndexOnlyScanState);
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
+ indexstate->ss.ps.ExecProcNode = ExecIndexOnlyScan;
indexstate->ioss_HeapFetches = 0;
/*
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 75b10115f5..bc89d59095 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -535,9 +535,11 @@ reorderqueue_pop(IndexScanState *node)
* ExecIndexScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecIndexScan(IndexScanState *node)
+static TupleTableSlot *
+ExecIndexScan(PlanState *pstate)
{
+ IndexScanState *node = castNode(IndexScanState, pstate);
+
/*
* If we have runtime keys and they've not already been set up, do it now.
*/
@@ -903,6 +905,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
indexstate = makeNode(IndexScanState);
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
+ indexstate->ss.ps.ExecProcNode = ExecIndexScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index c6aaa5bdd4..c8004d1528 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -37,9 +37,10 @@ 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 */
-ExecLimit(LimitState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecLimit(PlanState *pstate)
{
+ LimitState *node = castNode(LimitState, pstate);
ScanDirection direction;
TupleTableSlot *slot;
PlanState *outerPlan;
@@ -379,6 +380,7 @@ ExecInitLimit(Limit *node, EState *estate, int eflags)
limitstate = makeNode(LimitState);
limitstate->ps.plan = (Plan *) node;
limitstate->ps.state = estate;
+ limitstate->ps.ExecProcNode = ExecLimit;
limitstate->lstate = LIMIT_INITIAL;
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index 424fd0593d..70e4ecbc12 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -36,9 +36,10 @@
* ExecLockRows
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecLockRows(LockRowsState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecLockRows(PlanState *pstate)
{
+ LockRowsState *node = castNode(LockRowsState, pstate);
TupleTableSlot *slot;
EState *estate;
PlanState *outerPlan;
@@ -363,6 +364,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
lrstate = makeNode(LockRowsState);
lrstate->ps.plan = (Plan *) node;
lrstate->ps.state = estate;
+ lrstate->ps.ExecProcNode = ExecLockRows;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 3342949590..44c9dc110c 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -35,9 +35,10 @@
*
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* result tuple from subplan */
-ExecMaterial(MaterialState *node)
+static TupleTableSlot * /* result tuple from subplan */
+ExecMaterial(PlanState *pstate)
{
+ MaterialState *node = castNode(MaterialState, pstate);
EState *estate;
ScanDirection dir;
bool forward;
@@ -173,6 +174,7 @@ ExecInitMaterial(Material *node, EState *estate, int eflags)
matstate = makeNode(MaterialState);
matstate->ss.ps.plan = (Plan *) node;
matstate->ss.ps.state = estate;
+ matstate->ss.ps.ExecProcNode = ExecMaterial;
/*
* We must have a tuplestore buffering the subplan output to do backward
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index 8e0ce1ef3f..77db9f61e3 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -50,6 +50,7 @@
*/
typedef int32 SlotNumber;
+static TupleTableSlot *ExecMergeAppend(PlanState *pstate);
static int heap_compare_slots(Datum a, Datum b, void *arg);
@@ -89,6 +90,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
*/
mergestate->ps.plan = (Plan *) node;
mergestate->ps.state = estate;
+ mergestate->ps.ExecProcNode = ExecMergeAppend;
mergestate->mergeplans = mergeplanstates;
mergestate->ms_nplans = nplans;
@@ -169,9 +171,10 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
* Handles iteration over multiple subplans.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecMergeAppend(MergeAppendState *node)
+static TupleTableSlot *
+ExecMergeAppend(PlanState *pstate)
{
+ MergeAppendState *node = castNode(MergeAppendState, pstate);
TupleTableSlot *result;
SlotNumber i;
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 657af4692f..b3928c2b17 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -596,9 +596,10 @@ ExecMergeTupleDump(MergeJoinState *mergestate)
* ExecMergeJoin
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecMergeJoin(MergeJoinState *node)
+static TupleTableSlot *
+ExecMergeJoin(PlanState *pstate)
{
+ MergeJoinState *node = castNode(MergeJoinState, pstate);
ExprState *joinqual;
ExprState *otherqual;
bool qualResult;
@@ -1448,6 +1449,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
mergestate = makeNode(MergeJoinState);
mergestate->js.ps.plan = (Plan *) node;
mergestate->js.ps.state = estate;
+ mergestate->js.ps.ExecProcNode = ExecMergeJoin;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 11cb207b34..fdd2bfa182 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1535,9 +1535,10 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
* if needed.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecModifyTable(ModifyTableState *node)
+static TupleTableSlot *
+ExecModifyTable(PlanState *pstate)
{
+ ModifyTableState *node = castNode(ModifyTableState, pstate);
EState *estate = node->ps.state;
CmdType operation = node->operation;
ResultRelInfo *saved_resultRelInfo;
@@ -1806,6 +1807,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate = makeNode(ModifyTableState);
mtstate->ps.plan = (Plan *) node;
mtstate->ps.state = estate;
+ mtstate->ps.ExecProcNode = ExecModifyTable;
mtstate->operation = operation;
mtstate->canSetTag = node->canSetTag;
diff --git a/src/backend/executor/nodeNamedtuplestorescan.c b/src/backend/executor/nodeNamedtuplestorescan.c
index 62234869ab..3a65b9f5dc 100644
--- a/src/backend/executor/nodeNamedtuplestorescan.c
+++ b/src/backend/executor/nodeNamedtuplestorescan.c
@@ -63,9 +63,11 @@ NamedTuplestoreScanRecheck(NamedTuplestoreScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecNamedTuplestoreScan(NamedTuplestoreScanState *node)
+static TupleTableSlot *
+ExecNamedTuplestoreScan(PlanState *pstate)
{
+ NamedTuplestoreScanState *node = castNode(NamedTuplestoreScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) NamedTuplestoreScanNext,
(ExecScanRecheckMtd) NamedTuplestoreScanRecheck);
@@ -97,6 +99,7 @@ ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflag
scanstate = makeNode(NamedTuplestoreScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecNamedTuplestoreScan;
enr = get_ENR(estate->es_queryEnv, node->enrname);
if (!enr)
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index ec8862653e..5a3b61869f 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -57,9 +57,10 @@
* are prepared to return the first tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecNestLoop(NestLoopState *node)
+static TupleTableSlot *
+ExecNestLoop(PlanState *pstate)
{
+ NestLoopState *node = castNode(NestLoopState, pstate);
NestLoop *nl;
PlanState *innerPlan;
PlanState *outerPlan;
@@ -275,6 +276,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
nlstate = makeNode(NestLoopState);
nlstate->js.ps.plan = (Plan *) node;
nlstate->js.ps.state = estate;
+ nlstate->js.ps.ExecProcNode = ExecNestLoop;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c
index fbce3e09c5..1b502f8a1c 100644
--- a/src/backend/executor/nodeProjectSet.c
+++ b/src/backend/executor/nodeProjectSet.c
@@ -39,9 +39,10 @@ static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing);
* returning functions).
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecProjectSet(ProjectSetState *node)
+static TupleTableSlot *
+ExecProjectSet(PlanState *pstate)
{
+ ProjectSetState *node = castNode(ProjectSetState, pstate);
TupleTableSlot *outerTupleSlot;
TupleTableSlot *resultSlot;
PlanState *outerPlan;
@@ -217,6 +218,7 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
state = makeNode(ProjectSetState);
state->ps.plan = (Plan *) node;
state->ps.state = estate;
+ state->ps.ExecProcNode = ExecProjectSet;
state->pending_srf_tuples = false;
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index 7b5f5a972c..2580152ab7 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -66,9 +66,10 @@ build_hash_table(RecursiveUnionState *rustate)
* 2.6 go back to 2.2
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecRecursiveUnion(RecursiveUnionState *node)
+static TupleTableSlot *
+ExecRecursiveUnion(PlanState *pstate)
{
+ RecursiveUnionState *node = castNode(RecursiveUnionState, pstate);
PlanState *outerPlan = outerPlanState(node);
PlanState *innerPlan = innerPlanState(node);
RecursiveUnion *plan = (RecursiveUnion *) node->ps.plan;
@@ -172,6 +173,7 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags)
rustate = makeNode(RecursiveUnionState);
rustate->ps.plan = (Plan *) node;
rustate->ps.state = estate;
+ rustate->ps.ExecProcNode = ExecRecursiveUnion;
rustate->eqfunctions = NULL;
rustate->hashfunctions = NULL;
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index eec3048245..b508d166ac 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -64,9 +64,10 @@
* 'nil' if the constant qualification is not satisfied.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecResult(ResultState *node)
+static TupleTableSlot *
+ExecResult(PlanState *pstate)
{
+ ResultState *node = castNode(ResultState, pstate);
TupleTableSlot *outerTupleSlot;
PlanState *outerPlan;
ExprContext *econtext;
@@ -191,6 +192,7 @@ ExecInitResult(Result *node, EState *estate, int eflags)
resstate = makeNode(ResultState);
resstate->ps.plan = (Plan *) node;
resstate->ps.state = estate;
+ resstate->ps.ExecProcNode = ExecResult;
resstate->rs_done = false;
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index b710ef7edf..9c74a836e4 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -96,10 +96,12 @@ SampleRecheck(SampleScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSampleScan(SampleScanState *node)
+static TupleTableSlot *
+ExecSampleScan(PlanState *pstate)
{
- return ExecScan((ScanState *) node,
+ SampleScanState *node = castNode(SampleScanState, pstate);
+
+ return ExecScan(&node->ss,
(ExecScanAccessMtd) SampleNext,
(ExecScanRecheckMtd) SampleRecheck);
}
@@ -153,6 +155,7 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
scanstate = makeNode(SampleScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecSampleScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 307df87c82..5c49d4ca8a 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -121,10 +121,12 @@ SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSeqScan(SeqScanState *node)
+static TupleTableSlot *
+ExecSeqScan(PlanState *pstate)
{
- return ExecScan((ScanState *) node,
+ SeqScanState *node = castNode(SeqScanState, pstate);
+
+ return ExecScan(&node->ss,
(ExecScanAccessMtd) SeqNext,
(ExecScanRecheckMtd) SeqRecheck);
}
@@ -177,6 +179,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
scanstate = makeNode(SeqScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecSeqScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 0e8f1b2a72..be4861c0da 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -180,9 +180,10 @@ set_output_count(SetOpState *setopstate, SetOpStatePerGroup pergroup)
* ExecSetOp
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecSetOp(SetOpState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecSetOp(PlanState *pstate)
{
+ SetOpState *node = castNode(SetOpState, pstate);
SetOp *plannode = (SetOp *) node->ps.plan;
TupleTableSlot *resultTupleSlot = node->ps.ps_ResultTupleSlot;
@@ -489,6 +490,7 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags)
setopstate = makeNode(SetOpState);
setopstate->ps.plan = (Plan *) node;
setopstate->ps.state = estate;
+ setopstate->ps.ExecProcNode = ExecSetOp;
setopstate->eqfunctions = NULL;
setopstate->hashfunctions = NULL;
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index e74fa48124..74968068e8 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -35,9 +35,10 @@
* -- the outer child is prepared to return the first tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSort(SortState *node)
+static TupleTableSlot *
+ExecSort(PlanState *pstate)
{
+ SortState *node = castNode(SortState, pstate);
EState *estate;
ScanDirection dir;
Tuplesortstate *tuplesortstate;
@@ -167,6 +168,7 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
sortstate = makeNode(SortState);
sortstate->ss.ps.plan = (Plan *) node;
sortstate->ss.ps.state = estate;
+ sortstate->ss.ps.ExecProcNode = ExecSort;
/*
* We must have random access to the sort output to do backward scan or
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index 83b1b2b085..e08ab0bed2 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -82,9 +82,11 @@ SubqueryRecheck(SubqueryScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSubqueryScan(SubqueryScanState *node)
+static TupleTableSlot *
+ExecSubqueryScan(PlanState *pstate)
{
+ SubqueryScanState *node = castNode(SubqueryScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) SubqueryNext,
(ExecScanRecheckMtd) SubqueryRecheck);
@@ -112,6 +114,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
subquerystate = makeNode(SubqueryScanState);
subquerystate->ss.ps.plan = (Plan *) node;
subquerystate->ss.ps.state = estate;
+ subquerystate->ss.ps.ExecProcNode = ExecSubqueryScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index bb016ec8f6..822d72e0e2 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -93,9 +93,11 @@ TableFuncRecheck(TableFuncScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecTableFuncScan(TableFuncScanState *node)
+static TupleTableSlot *
+ExecTableFuncScan(PlanState *pstate)
{
+ TableFuncScanState *node = castNode(TableFuncScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) TableFuncNext,
(ExecScanRecheckMtd) TableFuncRecheck);
@@ -128,6 +130,7 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
scanstate = makeNode(TableFuncScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecTableFuncScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 96af2d21d9..4dad320cf7 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -442,9 +442,11 @@ TidRecheck(TidScanState *node, TupleTableSlot *slot)
* -- tidPtr is -1.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecTidScan(TidScanState *node)
+static TupleTableSlot *
+ExecTidScan(PlanState *pstate)
{
+ TidScanState *node = castNode(TidScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) TidNext,
(ExecScanRecheckMtd) TidRecheck);
@@ -516,6 +518,7 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
tidstate = makeNode(TidScanState);
tidstate->ss.ps.plan = (Plan *) node;
tidstate->ss.ps.state = estate;
+ tidstate->ss.ps.ExecProcNode = ExecTidScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 9f101375ef..94c22fbec2 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -43,9 +43,10 @@
* ExecUnique
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecUnique(UniqueState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecUnique(PlanState *pstate)
{
+ UniqueState *node = castNode(UniqueState, pstate);
Unique *plannode = (Unique *) node->ps.plan;
TupleTableSlot *resultTupleSlot;
TupleTableSlot *slot;
@@ -125,6 +126,7 @@ ExecInitUnique(Unique *node, EState *estate, int eflags)
uniquestate = makeNode(UniqueState);
uniquestate->ps.plan = (Plan *) node;
uniquestate->ps.state = estate;
+ uniquestate->ps.ExecProcNode = ExecUnique;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index 9ee776c4c3..6eacaed8bb 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -185,9 +185,11 @@ ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecValuesScan(ValuesScanState *node)
+static TupleTableSlot *
+ExecValuesScan(PlanState *pstate)
{
+ ValuesScanState *node = castNode(ValuesScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) ValuesNext,
(ExecScanRecheckMtd) ValuesRecheck);
@@ -218,6 +220,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
scanstate = makeNode(ValuesScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecValuesScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 838d3458d5..29599d7338 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1593,9 +1593,10 @@ update_frametailpos(WindowObject winobj, TupleTableSlot *slot)
* returned rows is exactly the same as its outer subplan's result.
* -----------------
*/
-TupleTableSlot *
-ExecWindowAgg(WindowAggState *winstate)
+static TupleTableSlot *
+ExecWindowAgg(PlanState *pstate)
{
+ WindowAggState *winstate = castNode(WindowAggState, pstate);
ExprContext *econtext;
int i;
int numfuncs;
@@ -1794,6 +1795,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
winstate = makeNode(WindowAggState);
winstate->ss.ps.plan = (Plan *) node;
winstate->ss.ps.state = estate;
+ winstate->ss.ps.ExecProcNode = ExecWindowAgg;
/*
* Create expression contexts. We need two, one for per-input-tuple
diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c
index d7616be065..d5ffadda3e 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -77,9 +77,11 @@ WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecWorkTableScan(WorkTableScanState *node)
+static TupleTableSlot *
+ExecWorkTableScan(PlanState *pstate)
{
+ WorkTableScanState *node = castNode(WorkTableScanState, pstate);
+
/*
* On the first call, find the ancestor RecursiveUnion's state via the
* Param slot reserved for it. (We can't do this during node init because
@@ -144,6 +146,7 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
scanstate = makeNode(WorkTableScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
scanstate->rustate = NULL; /* we'll set this later */
/*
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 59c28b709e..5139cab305 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -225,14 +225,35 @@ extern void EvalPlanQualBegin(EPQState *epqstate, EState *parentestate);
extern void EvalPlanQualEnd(EPQState *epqstate);
/*
- * prototypes from functions in execProcnode.c
+ * functions in execProcnode.c
*/
extern PlanState *ExecInitNode(Plan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecProcNode(PlanState *node);
extern Node *MultiExecProcNode(PlanState *node);
extern void ExecEndNode(PlanState *node);
extern bool ExecShutdownNode(PlanState *node);
+
+/* ----------------------------------------------------------------
+ * ExecProcNode
+ *
+ * Execute the given node to return a(nother) tuple.
+ * ----------------------------------------------------------------
+ */
+#ifndef FRONTEND
+static inline TupleTableSlot *
+ExecProcNode(PlanState *node)
+{
+ TupleTableSlot *result;
+
+ if (node->chgParam != NULL) /* something changed */
+ ExecReScan(node); /* let ReScan handle this */
+
+ result = node->ExecProcNode(node);
+
+ return result;
+}
+#endif
+
/*
* prototypes from functions in execExpr.c
*/
diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h
index fa11ba93a6..eff5af9c2a 100644
--- a/src/include/executor/nodeAgg.h
+++ b/src/include/executor/nodeAgg.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern AggState *ExecInitAgg(Agg *node, EState *estate, int eflags);
-extern TupleTableSlot *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 ee0b6ad23d..4e38a1380e 100644
--- a/src/include/executor/nodeAppend.h
+++ b/src/include/executor/nodeAppend.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern AppendState *ExecInitAppend(Append *node, EState *estate, int eflags);
-extern TupleTableSlot *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 f477d1c772..c77694cf22 100644
--- a/src/include/executor/nodeBitmapHeapscan.h
+++ b/src/include/executor/nodeBitmapHeapscan.h
@@ -18,7 +18,6 @@
#include "access/parallel.h"
extern BitmapHeapScanState *ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecEndBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecReScanBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecBitmapHeapEstimate(BitmapHeapScanState *node,
diff --git a/src/include/executor/nodeCtescan.h b/src/include/executor/nodeCtescan.h
index 397bdfdd1c..d2fbcbd586 100644
--- a/src/include/executor/nodeCtescan.h
+++ b/src/include/executor/nodeCtescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern CteScanState *ExecInitCteScan(CteScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 e81bcf7f21..a1cc63ae1f 100644
--- a/src/include/executor/nodeCustom.h
+++ b/src/include/executor/nodeCustom.h
@@ -21,7 +21,6 @@
*/
extern CustomScanState *ExecInitCustomScan(CustomScan *custom_scan,
EState *estate, int eflags);
-extern TupleTableSlot *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 3ff4ecd8c9..0b662597d8 100644
--- a/src/include/executor/nodeForeignscan.h
+++ b/src/include/executor/nodeForeignscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern ForeignScanState *ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 5e830ebdea..aaa9d8c316 100644
--- a/src/include/executor/nodeFunctionscan.h
+++ b/src/include/executor/nodeFunctionscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 b0006934d4..189bd70041 100644
--- a/src/include/executor/nodeGather.h
+++ b/src/include/executor/nodeGather.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern GatherState *ExecInitGather(Gather *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecGather(GatherState *node);
extern void ExecEndGather(GatherState *node);
extern void ExecShutdownGather(GatherState *node);
extern void ExecReScanGather(GatherState *node);
diff --git a/src/include/executor/nodeGatherMerge.h b/src/include/executor/nodeGatherMerge.h
index 14b31a086c..0154d73312 100644
--- a/src/include/executor/nodeGatherMerge.h
+++ b/src/include/executor/nodeGatherMerge.h
@@ -19,7 +19,6 @@
extern GatherMergeState *ExecInitGatherMerge(GatherMerge *node,
EState *estate,
int eflags);
-extern TupleTableSlot *ExecGatherMerge(GatherMergeState *node);
extern void ExecEndGatherMerge(GatherMergeState *node);
extern void ExecReScanGatherMerge(GatherMergeState *node);
extern void ExecShutdownGatherMerge(GatherMergeState *node);
diff --git a/src/include/executor/nodeGroup.h b/src/include/executor/nodeGroup.h
index 7358b61707..b0d7e312c9 100644
--- a/src/include/executor/nodeGroup.h
+++ b/src/include/executor/nodeGroup.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern GroupState *ExecInitGroup(Group *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecGroup(GroupState *node);
extern void ExecEndGroup(GroupState *node);
extern void ExecReScanGroup(GroupState *node);
diff --git a/src/include/executor/nodeHashjoin.h b/src/include/executor/nodeHashjoin.h
index 541c81edc7..7469bfbf60 100644
--- a/src/include/executor/nodeHashjoin.h
+++ b/src/include/executor/nodeHashjoin.h
@@ -18,7 +18,6 @@
#include "storage/buffile.h"
extern HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *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 cf227daae0..c8a709c26e 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -18,7 +18,6 @@
#include "access/parallel.h"
extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 0118234eca..1668e347ee 100644
--- a/src/include/executor/nodeIndexscan.h
+++ b/src/include/executor/nodeIndexscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern IndexScanState *ExecInitIndexScan(IndexScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 7bb20d9978..db65b5524c 100644
--- a/src/include/executor/nodeLimit.h
+++ b/src/include/executor/nodeLimit.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern LimitState *ExecInitLimit(Limit *node, EState *estate, int eflags);
-extern TupleTableSlot *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 6b90756e4c..c9d05b87f1 100644
--- a/src/include/executor/nodeLockRows.h
+++ b/src/include/executor/nodeLockRows.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern LockRowsState *ExecInitLockRows(LockRows *node, EState *estate, int eflags);
-extern TupleTableSlot *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 f69abbca82..4b3c2578c9 100644
--- a/src/include/executor/nodeMaterial.h
+++ b/src/include/executor/nodeMaterial.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MaterialState *ExecInitMaterial(Material *node, EState *estate, int eflags);
-extern TupleTableSlot *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 3cc6ef549b..a0ccbae965 100644
--- a/src/include/executor/nodeMergeAppend.h
+++ b/src/include/executor/nodeMergeAppend.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MergeAppendState *ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags);
-extern TupleTableSlot *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 32df25ae8b..d20e41505d 100644
--- a/src/include/executor/nodeMergejoin.h
+++ b/src/include/executor/nodeMergejoin.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *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 5a406f236d..a2e7af98de 100644
--- a/src/include/executor/nodeModifyTable.h
+++ b/src/include/executor/nodeModifyTable.h
@@ -16,7 +16,6 @@
#include "nodes/execnodes.h"
extern ModifyTableState *ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecModifyTable(ModifyTableState *node);
extern void ExecEndModifyTable(ModifyTableState *node);
extern void ExecReScanModifyTable(ModifyTableState *node);
diff --git a/src/include/executor/nodeNamedtuplestorescan.h b/src/include/executor/nodeNamedtuplestorescan.h
index 7f72fbe98a..395d978f62 100644
--- a/src/include/executor/nodeNamedtuplestorescan.h
+++ b/src/include/executor/nodeNamedtuplestorescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern NamedTuplestoreScanState *ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecNamedTuplestoreScan(NamedTuplestoreScanState *node);
extern void ExecEndNamedTuplestoreScan(NamedTuplestoreScanState *node);
extern void ExecReScanNamedTuplestoreScan(NamedTuplestoreScanState *node);
diff --git a/src/include/executor/nodeNestloop.h b/src/include/executor/nodeNestloop.h
index 8e0fcc1922..0d6486cc57 100644
--- a/src/include/executor/nodeNestloop.h
+++ b/src/include/executor/nodeNestloop.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecNestLoop(NestLoopState *node);
extern void ExecEndNestLoop(NestLoopState *node);
extern void ExecReScanNestLoop(NestLoopState *node);
diff --git a/src/include/executor/nodeProjectSet.h b/src/include/executor/nodeProjectSet.h
index 2f6999e8db..a0b0521f8d 100644
--- a/src/include/executor/nodeProjectSet.h
+++ b/src/include/executor/nodeProjectSet.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ProjectSetState *ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecProjectSet(ProjectSetState *node);
extern void ExecEndProjectSet(ProjectSetState *node);
extern void ExecReScanProjectSet(ProjectSetState *node);
diff --git a/src/include/executor/nodeRecursiveunion.h b/src/include/executor/nodeRecursiveunion.h
index f0eba05bee..e6ce1b4783 100644
--- a/src/include/executor/nodeRecursiveunion.h
+++ b/src/include/executor/nodeRecursiveunion.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern RecursiveUnionState *ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags);
-extern TupleTableSlot *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 61d3cb2cc2..20e0063410 100644
--- a/src/include/executor/nodeResult.h
+++ b/src/include/executor/nodeResult.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ResultState *ExecInitResult(Result *node, EState *estate, int eflags);
-extern TupleTableSlot *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 ed06e77e4e..607bbd9412 100644
--- a/src/include/executor/nodeSamplescan.h
+++ b/src/include/executor/nodeSamplescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SampleScanState *ExecInitSampleScan(SampleScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 06e0686b0b..0fba79f8de 100644
--- a/src/include/executor/nodeSeqscan.h
+++ b/src/include/executor/nodeSeqscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern SeqScanState *ExecInitSeqScan(SeqScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 af85977183..c15f945046 100644
--- a/src/include/executor/nodeSetOp.h
+++ b/src/include/executor/nodeSetOp.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate, int eflags);
-extern TupleTableSlot *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 1d2b7130b3..ed0e9dbb53 100644
--- a/src/include/executor/nodeSort.h
+++ b/src/include/executor/nodeSort.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SortState *ExecInitSort(Sort *node, EState *estate, int eflags);
-extern TupleTableSlot *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 c852e2947f..710e050285 100644
--- a/src/include/executor/nodeSubqueryscan.h
+++ b/src/include/executor/nodeSubqueryscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SubqueryScanState *ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSubqueryScan(SubqueryScanState *node);
extern void ExecEndSubqueryScan(SubqueryScanState *node);
extern void ExecReScanSubqueryScan(SubqueryScanState *node);
diff --git a/src/include/executor/nodeTableFuncscan.h b/src/include/executor/nodeTableFuncscan.h
index c58156e99c..c4672c0ac0 100644
--- a/src/include/executor/nodeTableFuncscan.h
+++ b/src/include/executor/nodeTableFuncscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern TableFuncScanState *ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecTableFuncScan(TableFuncScanState *node);
extern void ExecEndTableFuncScan(TableFuncScanState *node);
extern void ExecReScanTableFuncScan(TableFuncScanState *node);
diff --git a/src/include/executor/nodeTidscan.h b/src/include/executor/nodeTidscan.h
index d07ed7c864..e68aaf3829 100644
--- a/src/include/executor/nodeTidscan.h
+++ b/src/include/executor/nodeTidscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern TidScanState *ExecInitTidScan(TidScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 3d0ac9dde1..008774ae0f 100644
--- a/src/include/executor/nodeUnique.h
+++ b/src/include/executor/nodeUnique.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern UniqueState *ExecInitUnique(Unique *node, EState *estate, int eflags);
-extern TupleTableSlot *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 c28bb1acce..772a5e9705 100644
--- a/src/include/executor/nodeValuesscan.h
+++ b/src/include/executor/nodeValuesscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ValuesScanState *ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 db1ad60677..1c177309ae 100644
--- a/src/include/executor/nodeWindowAgg.h
+++ b/src/include/executor/nodeWindowAgg.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern WindowAggState *ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags);
-extern TupleTableSlot *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 c222d9f6b4..df05e75111 100644
--- a/src/include/executor/nodeWorktablescan.h
+++ b/src/include/executor/nodeWorktablescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern WorkTableScanState *ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 85fac8ab91..b8083e6684 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -818,6 +818,17 @@ typedef struct DomainConstraintState
* ----------------------------------------------------------------
*/
+struct PlanState;
+
+/* ----------------
+ * ExecProcNodeMtd
+ *
+ * This is the method called by ExecProcNode to return tuples from an
+ * executor node.
+ * ----------------
+ */
+typedef TupleTableSlot* (*ExecProcNodeMtd) (struct PlanState *node);
+
/* ----------------
* PlanState node
*
@@ -835,6 +846,10 @@ typedef struct PlanState
* nodes point to one EState for the whole
* top-level plan */
+ ExecProcNodeMtd ExecProcNode; /* function to execute node */
+ ExecProcNodeMtd ExecProcNodeReal; /* actual function, if above is a
+ * wrapper */
+
Instrumentation *instrument; /* Optional runtime stats for this node */
WorkerInstrumentation *worker_instrument; /* per-worker instrumentation */
--
2.13.1.392.g8d1b10321b.dirty
Andres Freund <andres@anarazel.de> writes:
I've moved the CHECK_FOR_INTERRUPTS() to the callsites. That
unsurprisingly ends up being somewhat verbose, and there's a bunch of
minor judgement calls where exactly to place them. While doing so I've
also added a few extra ones. Did this in a separate patch to make it
easier to review.
Hm, that seems kinda backwards to me; I was envisioning the checks
moving to the callees not the callers. I think it'd end up being
about the same number of occurrences of CHECK_FOR_INTERRUPTS(),
and there would be less of a judgment call about where to put them.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2017-07-26 15:03:37 -0400, Tom Lane wrote:
Andres Freund <andres@anarazel.de> writes:
I've moved the CHECK_FOR_INTERRUPTS() to the callsites. That
unsurprisingly ends up being somewhat verbose, and there's a bunch of
minor judgement calls where exactly to place them. While doing so I've
also added a few extra ones. Did this in a separate patch to make it
easier to review.Hm, that seems kinda backwards to me; I was envisioning the checks
moving to the callees not the callers. I think it'd end up being
about the same number of occurrences of CHECK_FOR_INTERRUPTS(),
and there would be less of a judgment call about where to put them.
Hm, that seems a bit riskier - easy to forget one of the places where we
might need a CFI(). We certainly are missing a bunch of them in various
nodes - I tried to add ones I saw as missing, but it's quite some
code. Keeping them close to ExecProcNode() makes that call easier. I'm
not quite seing how solely putting them in callees removes the judgement
call issue?
Greetings,
Andres Freund
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@anarazel.de> writes:
On 2017-07-26 15:03:37 -0400, Tom Lane wrote:
Hm, that seems kinda backwards to me; I was envisioning the checks
moving to the callees not the callers. I think it'd end up being
about the same number of occurrences of CHECK_FOR_INTERRUPTS(),
and there would be less of a judgment call about where to put them.
Hm, that seems a bit riskier - easy to forget one of the places where we
might need a CFI().
I would argue the contrary. If we put a CFI at the head of each node
execution function, then it's just boilerplate that you copy-and-paste
when you invent a new node type. The way you've coded it here, it
seems to involve a lot of judgment calls. That's very far from being
copy and paste, and the more different it looks from one node type
to another, the easier it will be to forget it.
We certainly are missing a bunch of them in various nodes
It's certainly possible that there are long-running loops not involving
any ExecProcNode recursion at all, but that would be a bug independent
of this issue. The CFI in ExecProcNode itself can be replaced exactly
either by asking all callers to do it, or by asking all callees to do it.
I think the latter is going to be more uniform and harder to screw up.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Jul 24, 2017 at 08:04:30AM +0100, Andres Freund wrote:
On July 24, 2017 7:10:19 AM GMT+01:00, Noah Misch <noah@leadboat.com> wrote:
On Tue, Jul 18, 2017 at 01:04:10PM -0700, Andres Freund wrote:
Ok, I'll flesh out the patch till Thursday. But I do think we're
going
to have to do something about the back branches, too.
This PostgreSQL 10 open item is past due for your status update.
Kindly send
a status update within 24 hours, and include a date for your subsequent
status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.comI sent out a note fleshed out patch last week, which Tom reviewed. Planning to update it to address that review today or tomorrow.
This PostgreSQL 10 open item is past due for your status update. Kindly send
a status update within 24 hours, and include a date for your subsequent status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2017-07-26 16:28:38 -0400, Tom Lane wrote:
Andres Freund <andres@anarazel.de> writes:
On 2017-07-26 15:03:37 -0400, Tom Lane wrote:
Hm, that seems kinda backwards to me; I was envisioning the checks
moving to the callees not the callers. I think it'd end up being
about the same number of occurrences of CHECK_FOR_INTERRUPTS(),
and there would be less of a judgment call about where to put them.Hm, that seems a bit riskier - easy to forget one of the places where we
might need a CFI().I would argue the contrary. If we put a CFI at the head of each node
execution function, then it's just boilerplate that you copy-and-paste
when you invent a new node type. The way you've coded it here, it
seems to involve a lot of judgment calls. That's very far from being
copy and paste, and the more different it looks from one node type
to another, the easier it will be to forget it.We certainly are missing a bunch of them in various nodes
It's certainly possible that there are long-running loops not involving
any ExecProcNode recursion at all, but that would be a bug independent
of this issue. The CFI in ExecProcNode itself can be replaced exactly
either by asking all callers to do it, or by asking all callees to do it.
I think the latter is going to be more uniform and harder to screw up.
Looks a bit better. Still a lot of judgement-y calls tho, e.g. when one
node function just calls the next, or when there's loops etc. I found
a good number of missing CFIs...
What do you think?
- Andres
Attachments:
0001-Move-interrupt-checking-from-ExecProcNode-to-executo.patchtext/x-patch; charset=us-asciiDownload
From a8dd50100915f4bc889bc923d749d0661a88b973 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 executor
nodes.
In a followup commit ExecProcNode(), and especially the large switch
it contains, will be replaced by a function pointer directly to the
correct node. The node functions will then get invoked by a thin
inline function wrapper. To avoid having to include miscadmin.h in
headers - CHECK_FOR_INTERRUPTS() - move the interrupt checks into the
individual executor routines.
While looking through all executor nodes, I noticed a number of
missing interrupt checks, add these too.
Author: Andres Freund
Reviewed-By: Tom Lane
Discussion:
https://postgr.es/m/22833.1490390175@sss.pgh.pa.us
---
src/backend/executor/execProcnode.c | 2 --
src/backend/executor/execScan.c | 1 +
src/backend/executor/nodeAgg.c | 5 +++++
src/backend/executor/nodeAppend.c | 3 +++
src/backend/executor/nodeBitmapHeapscan.c | 3 +++
src/backend/executor/nodeCustom.c | 3 +++
src/backend/executor/nodeGather.c | 4 ++++
src/backend/executor/nodeGatherMerge.c | 4 ++++
src/backend/executor/nodeGroup.c | 3 +++
src/backend/executor/nodeHash.c | 6 ++++++
src/backend/executor/nodeHashjoin.c | 9 ++-------
src/backend/executor/nodeIndexonlyscan.c | 3 +++
src/backend/executor/nodeIndexscan.c | 6 ++++++
src/backend/executor/nodeLimit.c | 3 +++
src/backend/executor/nodeMaterial.c | 2 ++
src/backend/executor/nodeMergeAppend.c | 4 +++-
src/backend/executor/nodeMergejoin.c | 3 +++
src/backend/executor/nodeModifyTable.c | 2 ++
src/backend/executor/nodeNestloop.c | 3 +++
src/backend/executor/nodeProjectSet.c | 3 +++
src/backend/executor/nodeRecursiveunion.c | 2 ++
src/backend/executor/nodeResult.c | 3 +++
src/backend/executor/nodeSetOp.c | 5 +++++
src/backend/executor/nodeSort.c | 2 ++
src/backend/executor/nodeSubplan.c | 5 +++++
src/backend/executor/nodeTableFuncscan.c | 2 ++
src/backend/executor/nodeTidscan.c | 3 +++
src/backend/executor/nodeUnique.c | 3 +++
src/backend/executor/nodeWindowAgg.c | 5 +++++
29 files changed, 92 insertions(+), 10 deletions(-)
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/execScan.c b/src/backend/executor/execScan.c
index 4f131b3ee0..dc40f6b699 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -139,6 +139,7 @@ ExecScan(ScanState *node,
*/
if (!qual && !projInfo)
{
+ CHECK_FOR_INTERRUPTS();
ResetExprContext(econtext);
return ExecScanFetch(node, accessMtd, recheckMtd);
}
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index de9a18e71c..c1096ed8b0 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -677,6 +677,7 @@ fetch_input_tuple(AggState *aggstate)
if (aggstate->sort_in)
{
+ CHECK_FOR_INTERRUPTS();
if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
aggstate->sort_slot, NULL))
return NULL;
@@ -1414,6 +1415,8 @@ process_ordered_aggregate_multi(AggState *aggstate,
while (tuplesort_gettupleslot(pertrans->sortstates[aggstate->current_set],
true, true, slot1, &newAbbrevVal))
{
+ CHECK_FOR_INTERRUPTS();
+
/*
* Extract the first numTransInputs columns as datums to pass to the
* transfn. (This will help execTuplesMatch too, so we do it
@@ -2563,6 +2566,8 @@ agg_retrieve_hash_table(AggState *aggstate)
TupleTableSlot *hashslot = perhash->hashslot;
int i;
+ CHECK_FOR_INTERRUPTS();
+
/*
* Find the next entry in the hash table
*/
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/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 7e0ba030b7..cf109d5049 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -41,6 +41,7 @@
#include "access/transam.h"
#include "executor/execdebug.h"
#include "executor/nodeBitmapHeapscan.h"
+#include "miscadmin.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "storage/predicate.h"
@@ -192,6 +193,8 @@ BitmapHeapNext(BitmapHeapScanState *node)
Page dp;
ItemId lp;
+ CHECK_FOR_INTERRUPTS();
+
/*
* Get next page of results if needed
*/
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/nodeGather.c b/src/backend/executor/nodeGather.c
index f83cd584d7..5dbe19c056 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -128,6 +128,8 @@ ExecGather(GatherState *node)
TupleTableSlot *slot;
ExprContext *econtext;
+ CHECK_FOR_INTERRUPTS();
+
/*
* Initialize the parallel context and workers on first execution. We do
* this on first execution rather than during node initialization, as it
@@ -247,6 +249,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..0aff3798f7 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -164,6 +164,8 @@ ExecGatherMerge(GatherMergeState *node)
ExprContext *econtext;
int i;
+ CHECK_FOR_INTERRUPTS();
+
/*
* As with Gather, we don't launch workers until this node is actually
* executed.
@@ -393,6 +395,8 @@ gather_merge_init(GatherMergeState *gm_state)
reread:
for (i = 0; i < nreaders + 1; i++)
{
+ CHECK_FOR_INTERRUPTS();
+
if (!gm_state->gm_tuple_buffers[i].done &&
(TupIsNull(gm_state->gm_slots[i]) ||
gm_state->gm_slots[i]->tts_isempty))
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index af9ba4905e..fc5e0e59bc 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"
/*
@@ -40,6 +41,8 @@ ExecGroup(GroupState *node)
TupleTableSlot *firsttupleslot;
TupleTableSlot *outerslot;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get state info from node
*/
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 075f4ed11c..fbeb562489 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -810,6 +810,9 @@ ExecHashIncreaseNumBuckets(HashJoinTable hashtable)
idx += MAXALIGN(HJTUPLE_OVERHEAD +
HJTUPLE_MINTUPLE(hashTuple)->t_len);
}
+
+ /* allow this loop to be cancellable */
+ CHECK_FOR_INTERRUPTS();
}
}
@@ -1192,6 +1195,9 @@ ExecScanHashTableForUnmatched(HashJoinState *hjstate, ExprContext *econtext)
hashTuple = hashTuple->next;
}
+
+ /* allow this loop to be cancellable */
+ CHECK_FOR_INTERRUPTS();
}
/*
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 668ed871e1..917c3b6cef 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
*/
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 890e54416a..e2000764a4 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -34,6 +34,7 @@
#include "executor/execdebug.h"
#include "executor/nodeIndexonlyscan.h"
#include "executor/nodeIndexscan.h"
+#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/predicate.h"
#include "utils/memutils.h"
@@ -117,6 +118,8 @@ IndexOnlyNext(IndexOnlyScanState *node)
{
HeapTuple tuple = NULL;
+ CHECK_FOR_INTERRUPTS();
+
/*
* We can skip the heap fetch if the TID references a heap page on
* which all tuples are known visible to everybody. In any case,
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 75b10115f5..581a2092be 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -34,6 +34,7 @@
#include "executor/execdebug.h"
#include "executor/nodeIndexscan.h"
#include "lib/pairingheap.h"
+#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "utils/array.h"
@@ -131,6 +132,8 @@ IndexNext(IndexScanState *node)
*/
while ((tuple = index_getnext(scandesc, direction)) != NULL)
{
+ CHECK_FOR_INTERRUPTS();
+
/*
* Store the scanned tuple in the scan tuple slot of the scan state.
* Note: we pass 'false' because tuples returned by amgetnext are
@@ -233,6 +236,8 @@ IndexNextWithReorder(IndexScanState *node)
for (;;)
{
+ CHECK_FOR_INTERRUPTS();
+
/*
* Check the reorder queue first. If the topmost tuple in the queue
* has an ORDER BY value smaller than (or equal to) the value last
@@ -299,6 +304,7 @@ next_indextuple:
{
/* Fails recheck, so drop it and loop back for another */
InstrCountFiltered2(node, 1);
+ CHECK_FOR_INTERRUPTS();
goto next_indextuple;
}
}
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index abd060d75f..2ed3523257 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
*/
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..d41def1350 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
@@ -175,6 +175,8 @@ ExecMergeAppend(MergeAppendState *node)
TupleTableSlot *result;
SlotNumber i;
+ CHECK_FOR_INTERRUPTS();
+
if (!node->ms_initialized)
{
/*
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..637a582e1c 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1551,6 +1551,8 @@ ExecModifyTable(ModifyTableState *node)
HeapTupleData oldtupdata;
HeapTuple oldtuple;
+ CHECK_FOR_INTERRUPTS();
+
/*
* This should NOT get called during EvalPlanQual; we should have passed a
* subplan tree to EvalPlanQual, instead. Use a runtime test not just
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..3b69c7adee 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"
@@ -46,6 +47,8 @@ ExecProjectSet(ProjectSetState *node)
PlanState *outerPlan;
ExprContext *econtext;
+ CHECK_FOR_INTERRUPTS();
+
econtext = node->ps.ps_ExprContext;
/*
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index fc1c00d68f..2802fffa2b 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -75,6 +75,8 @@ ExecRecursiveUnion(RecursiveUnionState *node)
TupleTableSlot *slot;
bool isnew;
+ CHECK_FOR_INTERRUPTS();
+
/* 1. Evaluate non-recursive term */
if (!node->recursing)
{
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index a753a53419..f007f46784 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"
@@ -70,6 +71,8 @@ ExecResult(ResultState *node)
PlanState *outerPlan;
ExprContext *econtext;
+ CHECK_FOR_INTERRUPTS();
+
econtext = node->ps.ps_ExprContext;
/*
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 9c7812e519..56c5643f17 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"
@@ -185,6 +186,8 @@ ExecSetOp(SetOpState *node)
SetOp *plannode = (SetOp *) node->ps.plan;
TupleTableSlot *resultTupleSlot = node->ps.ps_ResultTupleSlot;
+ CHECK_FOR_INTERRUPTS();
+
/*
* If the previously-returned tuple needs to be returned more than once,
* keep returning it.
@@ -428,6 +431,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..799a4e9204 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
*/
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index e8fa4c8547..fe10e809df 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"
@@ -65,6 +66,8 @@ ExecSubPlan(SubPlanState *node,
{
SubPlan *subplan = node->subplan;
+ CHECK_FOR_INTERRUPTS();
+
/* Set non-null as default */
*isNull = false;
@@ -618,6 +621,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,
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index bb016ec8f6..2859363fe2 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -440,6 +440,8 @@ tfuncLoadRows(TableFuncScanState *tstate, ExprContext *econtext)
ListCell *cell = list_head(tstate->coldefexprs);
int colno;
+ CHECK_FOR_INTERRUPTS();
+
ExecClearTuple(tstate->ss.ss_ScanTupleSlot);
/*
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 96af2d21d9..c122473bdf 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -26,6 +26,7 @@
#include "catalog/pg_type.h"
#include "executor/execdebug.h"
#include "executor/nodeTidscan.h"
+#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "storage/bufmgr.h"
#include "utils/array.h"
@@ -400,6 +401,8 @@ TidNext(TidScanState *node)
node->tss_TidPtr--;
else
node->tss_TidPtr++;
+
+ CHECK_FOR_INTERRUPTS();
}
/*
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 28cc1e90f8..db78c88368 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"
@@ -50,6 +51,8 @@ ExecUnique(UniqueState *node)
TupleTableSlot *slot;
PlanState *outerPlan;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get information from the node
*/
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 8f13fe0c73..9da35ac506 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1594,6 +1594,8 @@ ExecWindowAgg(WindowAggState *winstate)
int i;
int numfuncs;
+ CHECK_FOR_INTERRUPTS();
+
if (winstate->all_done)
return NULL;
@@ -2371,6 +2373,9 @@ window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
WindowAggState *winstate = winobj->winstate;
MemoryContext oldcontext;
+ /* often called repeatedly in a row */
+ CHECK_FOR_INTERRUPTS();
+
/* Don't allow passing -1 to spool_tuples here */
if (pos < 0)
return false;
--
2.13.1.392.g8d1b10321b.dirty
On Thu, Jul 27, 2017 at 02:29:32AM +0000, Noah Misch wrote:
On Mon, Jul 24, 2017 at 08:04:30AM +0100, Andres Freund wrote:
On July 24, 2017 7:10:19 AM GMT+01:00, Noah Misch <noah@leadboat.com> wrote:
On Tue, Jul 18, 2017 at 01:04:10PM -0700, Andres Freund wrote:
Ok, I'll flesh out the patch till Thursday. But I do think we're
going
to have to do something about the back branches, too.
This PostgreSQL 10 open item is past due for your status update.
Kindly send
a status update within 24 hours, and include a date for your subsequent
status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.comI sent out a note fleshed out patch last week, which Tom reviewed. Planning to update it to address that review today or tomorrow.
This PostgreSQL 10 open item is past due for your status update. Kindly send
a status update within 24 hours, and include a date for your subsequent status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
IMMEDIATE ATTENTION REQUIRED. This PostgreSQL 10 open item is long past due
for your status update. Please reacquaint yourself with the policy on open
item ownership[1]/messages/by-id/20170404140717.GA2675809@tornado.leadboat.com and then reply immediately. If I do not hear from you by
2017-07-29 05:00 UTC, I will transfer this item to release management team
ownership without further notice.
[1]: /messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2017-07-27 21:46:57 -0700, Noah Misch wrote:
On Thu, Jul 27, 2017 at 02:29:32AM +0000, Noah Misch wrote:
On Mon, Jul 24, 2017 at 08:04:30AM +0100, Andres Freund wrote:
On July 24, 2017 7:10:19 AM GMT+01:00, Noah Misch <noah@leadboat.com> wrote:
On Tue, Jul 18, 2017 at 01:04:10PM -0700, Andres Freund wrote:
Ok, I'll flesh out the patch till Thursday. But I do think we're
going
to have to do something about the back branches, too.
This PostgreSQL 10 open item is past due for your status update.
Kindly send
a status update within 24 hours, and include a date for your subsequent
status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.comI sent out a note fleshed out patch last week, which Tom reviewed. Planning to update it to address that review today or tomorrow.
This PostgreSQL 10 open item is past due for your status update. Kindly send
a status update within 24 hours, and include a date for your subsequent status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.comIMMEDIATE ATTENTION REQUIRED. This PostgreSQL 10 open item is long past due
for your status update. Please reacquaint yourself with the policy on open
item ownership[1] and then reply immediately. If I do not hear from you by
2017-07-29 05:00 UTC, I will transfer this item to release management team
ownership without further notice.[1] /messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
I've updated the patch based on review (today). Awaiting new review.
FWIW, I don't see the point of these messages when there is a new patch
version posted today.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Jul 27, 2017 at 09:49:18PM -0700, Andres Freund wrote:
On 2017-07-27 21:46:57 -0700, Noah Misch wrote:
On Thu, Jul 27, 2017 at 02:29:32AM +0000, Noah Misch wrote:
On Mon, Jul 24, 2017 at 08:04:30AM +0100, Andres Freund wrote:
On July 24, 2017 7:10:19 AM GMT+01:00, Noah Misch <noah@leadboat.com> wrote:
On Tue, Jul 18, 2017 at 01:04:10PM -0700, Andres Freund wrote:
Ok, I'll flesh out the patch till Thursday. But I do think we're
going
to have to do something about the back branches, too.
This PostgreSQL 10 open item is past due for your status update.
Kindly send
a status update within 24 hours, and include a date for your subsequent
status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.comI sent out a note fleshed out patch last week, which Tom reviewed. Planning to update it to address that review today or tomorrow.
This PostgreSQL 10 open item is past due for your status update. Kindly send
a status update within 24 hours, and include a date for your subsequent status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.comIMMEDIATE ATTENTION REQUIRED. This PostgreSQL 10 open item is long past due
for your status update. Please reacquaint yourself with the policy on open
item ownership[1] and then reply immediately. If I do not hear from you by
2017-07-29 05:00 UTC, I will transfer this item to release management team
ownership without further notice.[1] /messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
I've updated the patch based on review (today). Awaiting new review.
FWIW, I don't see the point of these messages when there is a new patch
version posted today.
The policy says, "Each update shall state a date when the community will
receive another update". Nothing you've sent today specifies a deadline for
your next update, so your ownership of this item remains out of compliance.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2017-07-27 22:04:59 -0700, Noah Misch wrote:
On Thu, Jul 27, 2017 at 09:49:18PM -0700, Andres Freund wrote:
On 2017-07-27 21:46:57 -0700, Noah Misch wrote:
On Thu, Jul 27, 2017 at 02:29:32AM +0000, Noah Misch wrote:
On Mon, Jul 24, 2017 at 08:04:30AM +0100, Andres Freund wrote:
On July 24, 2017 7:10:19 AM GMT+01:00, Noah Misch <noah@leadboat.com> wrote:
On Tue, Jul 18, 2017 at 01:04:10PM -0700, Andres Freund wrote:
Ok, I'll flesh out the patch till Thursday. But I do think we're
going
to have to do something about the back branches, too.
This PostgreSQL 10 open item is past due for your status update.
Kindly send
a status update within 24 hours, and include a date for your subsequent
status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.comI sent out a note fleshed out patch last week, which Tom reviewed. Planning to update it to address that review today or tomorrow.
This PostgreSQL 10 open item is past due for your status update. Kindly send
a status update within 24 hours, and include a date for your subsequent status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.comIMMEDIATE ATTENTION REQUIRED. This PostgreSQL 10 open item is long past due
for your status update. Please reacquaint yourself with the policy on open
item ownership[1] and then reply immediately. If I do not hear from you by
2017-07-29 05:00 UTC, I will transfer this item to release management team
ownership without further notice.[1] /messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
I've updated the patch based on review (today). Awaiting new review.
FWIW, I don't see the point of these messages when there is a new patch
version posted today.The policy says, "Each update shall state a date when the community will
receive another update". Nothing you've sent today specifies a deadline for
your next update, so your ownership of this item remains out of
compliance.
For me that means the policy isn't quite right. It's not like I can
force Tom to review the patch at a specific date. But the thread has
been progressing steadily over the last days, so I'm not particularly
concerned.
Greetings,
Andres Freund
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Jul 27, 2017 at 10:08:57PM -0700, Andres Freund wrote:
On 2017-07-27 22:04:59 -0700, Noah Misch wrote:
On Thu, Jul 27, 2017 at 09:49:18PM -0700, Andres Freund wrote:
On 2017-07-27 21:46:57 -0700, Noah Misch wrote:
On Thu, Jul 27, 2017 at 02:29:32AM +0000, Noah Misch wrote:
On Mon, Jul 24, 2017 at 08:04:30AM +0100, Andres Freund wrote:
On July 24, 2017 7:10:19 AM GMT+01:00, Noah Misch <noah@leadboat.com> wrote:
On Tue, Jul 18, 2017 at 01:04:10PM -0700, Andres Freund wrote:
Ok, I'll flesh out the patch till Thursday. But I do think we're
going
to have to do something about the back branches, too.
This PostgreSQL 10 open item is past due for your status update.
Kindly send
a status update within 24 hours, and include a date for your subsequent
status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.comI sent out a note fleshed out patch last week, which Tom reviewed. Planning to update it to address that review today or tomorrow.
This PostgreSQL 10 open item is past due for your status update. Kindly send
a status update within 24 hours, and include a date for your subsequent status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.comIMMEDIATE ATTENTION REQUIRED. This PostgreSQL 10 open item is long past due
for your status update. Please reacquaint yourself with the policy on open
item ownership[1] and then reply immediately. If I do not hear from you by
2017-07-29 05:00 UTC, I will transfer this item to release management team
ownership without further notice.[1] /messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
I've updated the patch based on review (today). Awaiting new review.
FWIW, I don't see the point of these messages when there is a new patch
version posted today.The policy says, "Each update shall state a date when the community will
receive another update". Nothing you've sent today specifies a deadline for
your next update, so your ownership of this item remains out of
compliance.For me that means the policy isn't quite right. It's not like I can
force Tom to review the patch at a specific date. But the thread has
been progressing steadily over the last days, so I'm not particularly
concerned.
Your colleagues achieve compliance despite uncertainty; for inspiration, I
recommend examining Alvaro's status updates as examples of this. The policy
currently governs your open items even if you disagree with it.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2017-07-28 09:29:58 -0700, Noah Misch wrote:
On Thu, Jul 27, 2017 at 10:08:57PM -0700, Andres Freund wrote:
For me that means the policy isn't quite right. It's not like I can
force Tom to review the patch at a specific date. But the thread has
been progressing steadily over the last days, so I'm not particularly
concerned.Your colleagues achieve compliance despite uncertainty; for inspiration, I
recommend examining Alvaro's status updates as examples of this. The policy
currently governs your open items even if you disagree with it.
That's just process over substance. Publishing repeated "I'll look at
it again in $small_n days" doesn't really provide something useful.
Anyway, I'll commit it after another pass in ~1 week if it doesn't get a
review till then, but I assume it'll.
Greetings,
Andres Freund
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@anarazel.de> writes:
Anyway, I'll commit it after another pass in ~1 week if it doesn't get a
review till then, but I assume it'll.
FWIW, I intend to review it today, or tomorrow at the very latest.
(Right now I'm buried in perl droppings.)
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Jul 28, 2017 at 12:29 PM, Noah Misch <noah@leadboat.com> wrote:
Your colleagues achieve compliance despite uncertainty; for inspiration, I
recommend examining Alvaro's status updates as examples of this. The policy
currently governs your open items even if you disagree with it.
I emphatically agree with that. If the RMT is to accomplish its
purpose, it must be able to exert authority even when an individual
contributor doesn't like the decisions it makes.
On the other hand, nothing in the open item policy the current RMT has
adopted prohibits you from using judgement about when and how
vigorously to enforce that policy in any particular case, and I would
encourage you to do so. It didn't make much sense to keep sending
Kevin increasingly strident form letters about each individual item
when he wasn't responding to any emails at all, and it makes equally
little sense to me to nag someone over a technical failure to include
a date when things are obviously progressing adequately. As Andres
quite rightly says downthread:
That's just process over substance.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@anarazel.de> writes:
On 2017-07-26 16:28:38 -0400, Tom Lane wrote:
It's certainly possible that there are long-running loops not involving
any ExecProcNode recursion at all, but that would be a bug independent
of this issue. The CFI in ExecProcNode itself can be replaced exactly
either by asking all callers to do it, or by asking all callees to do it.
I think the latter is going to be more uniform and harder to screw up.
Looks a bit better. Still a lot of judgement-y calls tho, e.g. when one
node function just calls the next, or when there's loops etc. I found
a good number of missing CFIs...
What do you think?
Here's a reviewed version of this patch. Differences from yours:
* I think you put ExecScan's CFI in the wrong place; AFAICT yours
only covers its fast path.
* I think ExecAgg needs a CFI at the head, just to be sure it's hit
in any path through that.
* I agree that putting CFI inside ExecHashJoin's state machine loop
is a good idea, because it might have to trawl through quite a lot of
a batch file before finding a returnable tuple. But I think in merge
and nestloop joins it's sufficient to put one CFI at the head. Neither
of those cases can do very much processing without invoking a child
node, where a CFI will happen.
* You missed ExecLockRows altogether.
* I added some comments and cosmetic tweaks.
regards, tom lane
Attachments:
move-executor-CFIs-v3.patchtext/x-diff; charset=us-ascii; name=move-executor-CFIs-v3.patchDownload
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 294ad2c..20fd9f8 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/execScan.c b/src/backend/executor/execScan.c
index 4f131b3..6fde7cd 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -126,6 +126,8 @@ ExecScan(ScanState *node,
ExprState *qual;
ProjectionInfo *projInfo;
+ CHECK_FOR_INTERRUPTS();
+
/*
* Fetch data from node
*/
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index de9a18e..377916d 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -677,6 +677,8 @@ fetch_input_tuple(AggState *aggstate)
if (aggstate->sort_in)
{
+ /* make sure we check for interrupts in either path through here */
+ CHECK_FOR_INTERRUPTS();
if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
aggstate->sort_slot, NULL))
return NULL;
@@ -1414,6 +1416,8 @@ process_ordered_aggregate_multi(AggState *aggstate,
while (tuplesort_gettupleslot(pertrans->sortstates[aggstate->current_set],
true, true, slot1, &newAbbrevVal))
{
+ CHECK_FOR_INTERRUPTS();
+
/*
* Extract the first numTransInputs columns as datums to pass to the
* transfn. (This will help execTuplesMatch too, so we do it
@@ -2100,6 +2104,8 @@ ExecAgg(AggState *node)
{
TupleTableSlot *result = NULL;
+ CHECK_FOR_INTERRUPTS();
+
if (!node->agg_done)
{
/* Dispatch based on strategy */
@@ -2563,6 +2569,8 @@ agg_retrieve_hash_table(AggState *aggstate)
TupleTableSlot *hashslot = perhash->hashslot;
int i;
+ CHECK_FOR_INTERRUPTS();
+
/*
* Find the next entry in the hash table
*/
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index aae5e3f..58045e0 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/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 7e0ba03..cf109d5 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -41,6 +41,7 @@
#include "access/transam.h"
#include "executor/execdebug.h"
#include "executor/nodeBitmapHeapscan.h"
+#include "miscadmin.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "storage/predicate.h"
@@ -192,6 +193,8 @@ BitmapHeapNext(BitmapHeapScanState *node)
Page dp;
ItemId lp;
+ CHECK_FOR_INTERRUPTS();
+
/*
* Get next page of results if needed
*/
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index 69e2704..fc15974 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"
@@ -104,6 +105,8 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
TupleTableSlot *
ExecCustomScan(CustomScanState *node)
{
+ CHECK_FOR_INTERRUPTS();
+
Assert(node->methods->ExecCustomScan != NULL);
return node->methods->ExecCustomScan(node);
}
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index f83cd58..5dbe19c 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -128,6 +128,8 @@ ExecGather(GatherState *node)
TupleTableSlot *slot;
ExprContext *econtext;
+ CHECK_FOR_INTERRUPTS();
+
/*
* Initialize the parallel context and workers on first execution. We do
* this on first execution rather than during node initialization, as it
@@ -247,6 +249,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 80ee1fc..0aff379 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -164,6 +164,8 @@ ExecGatherMerge(GatherMergeState *node)
ExprContext *econtext;
int i;
+ CHECK_FOR_INTERRUPTS();
+
/*
* As with Gather, we don't launch workers until this node is actually
* executed.
@@ -393,6 +395,8 @@ gather_merge_init(GatherMergeState *gm_state)
reread:
for (i = 0; i < nreaders + 1; i++)
{
+ CHECK_FOR_INTERRUPTS();
+
if (!gm_state->gm_tuple_buffers[i].done &&
(TupIsNull(gm_state->gm_slots[i]) ||
gm_state->gm_slots[i]->tts_isempty))
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index af9ba49..fc5e0e5 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"
/*
@@ -40,6 +41,8 @@ ExecGroup(GroupState *node)
TupleTableSlot *firsttupleslot;
TupleTableSlot *outerslot;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get state info from node
*/
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 075f4ed..fbeb562 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -810,6 +810,9 @@ ExecHashIncreaseNumBuckets(HashJoinTable hashtable)
idx += MAXALIGN(HJTUPLE_OVERHEAD +
HJTUPLE_MINTUPLE(hashTuple)->t_len);
}
+
+ /* allow this loop to be cancellable */
+ CHECK_FOR_INTERRUPTS();
}
}
@@ -1192,6 +1195,9 @@ ExecScanHashTableForUnmatched(HashJoinState *hjstate, ExprContext *econtext)
hashTuple = hashTuple->next;
}
+
+ /* allow this loop to be cancellable */
+ CHECK_FOR_INTERRUPTS();
}
/*
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 668ed87..252960c 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -92,6 +92,14 @@ ExecHashJoin(HashJoinState *node)
*/
for (;;)
{
+ /*
+ * It's possible to iterate this loop many times before returning a
+ * tuple, in some pathological cases such as needing to move much of
+ * the current batch to a later batch. So let's check for interrupts
+ * each time through.
+ */
+ CHECK_FOR_INTERRUPTS();
+
switch (node->hj_JoinState)
{
case HJ_BUILD_HASHTABLE:
@@ -247,13 +255,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
*/
if (!ExecScanHashBucket(node, econtext))
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 890e544..e2000764 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -34,6 +34,7 @@
#include "executor/execdebug.h"
#include "executor/nodeIndexonlyscan.h"
#include "executor/nodeIndexscan.h"
+#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/predicate.h"
#include "utils/memutils.h"
@@ -117,6 +118,8 @@ IndexOnlyNext(IndexOnlyScanState *node)
{
HeapTuple tuple = NULL;
+ CHECK_FOR_INTERRUPTS();
+
/*
* We can skip the heap fetch if the TID references a heap page on
* which all tuples are known visible to everybody. In any case,
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 75b1011..6704ede 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -34,6 +34,7 @@
#include "executor/execdebug.h"
#include "executor/nodeIndexscan.h"
#include "lib/pairingheap.h"
+#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "utils/array.h"
@@ -131,6 +132,8 @@ IndexNext(IndexScanState *node)
*/
while ((tuple = index_getnext(scandesc, direction)) != NULL)
{
+ CHECK_FOR_INTERRUPTS();
+
/*
* Store the scanned tuple in the scan tuple slot of the scan state.
* Note: we pass 'false' because tuples returned by amgetnext are
@@ -233,6 +236,8 @@ IndexNextWithReorder(IndexScanState *node)
for (;;)
{
+ CHECK_FOR_INTERRUPTS();
+
/*
* Check the reorder queue first. If the topmost tuple in the queue
* has an ORDER BY value smaller than (or equal to) the value last
@@ -299,6 +304,8 @@ next_indextuple:
{
/* Fails recheck, so drop it and loop back for another */
InstrCountFiltered2(node, 1);
+ /* allow this loop to be cancellable */
+ CHECK_FOR_INTERRUPTS();
goto next_indextuple;
}
}
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index abd060d..2ed3523 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
*/
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index f519794..dd4e2c5 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"
@@ -44,6 +45,8 @@ ExecLockRows(LockRowsState *node)
bool epq_needed;
ListCell *lc;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get information from the node
*/
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 32b7269..3342949 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 fef83db..d41def1 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
@@ -175,6 +175,8 @@ ExecMergeAppend(MergeAppendState *node)
TupleTableSlot *result;
SlotNumber i;
+ CHECK_FOR_INTERRUPTS();
+
if (!node->ms_initialized)
{
/*
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 6a145ee..324b61b 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"
@@ -610,6 +611,8 @@ ExecMergeJoin(MergeJoinState *node)
bool doFillOuter;
bool doFillInner;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get information from node
*/
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 77ba15d..637a582 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1551,6 +1551,8 @@ ExecModifyTable(ModifyTableState *node)
HeapTupleData oldtupdata;
HeapTuple oldtuple;
+ CHECK_FOR_INTERRUPTS();
+
/*
* This should NOT get called during EvalPlanQual; we should have passed a
* subplan tree to EvalPlanQual, instead. Use a runtime test not just
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 0065fe6..bedc374 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"
@@ -69,6 +70,8 @@ ExecNestLoop(NestLoopState *node)
ExprContext *econtext;
ListCell *lc;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get information from the node
*/
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c
index 01048cc..3b69c7a 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"
@@ -46,6 +47,8 @@ ExecProjectSet(ProjectSetState *node)
PlanState *outerPlan;
ExprContext *econtext;
+ CHECK_FOR_INTERRUPTS();
+
econtext = node->ps.ps_ExprContext;
/*
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index fc1c00d..2802fff 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -75,6 +75,8 @@ ExecRecursiveUnion(RecursiveUnionState *node)
TupleTableSlot *slot;
bool isnew;
+ CHECK_FOR_INTERRUPTS();
+
/* 1. Evaluate non-recursive term */
if (!node->recursing)
{
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index a753a53..f007f46 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"
@@ -70,6 +71,8 @@ ExecResult(ResultState *node)
PlanState *outerPlan;
ExprContext *econtext;
+ CHECK_FOR_INTERRUPTS();
+
econtext = node->ps.ps_ExprContext;
/*
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 9c7812e..56c5643 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"
@@ -185,6 +186,8 @@ ExecSetOp(SetOpState *node)
SetOp *plannode = (SetOp *) node->ps.plan;
TupleTableSlot *resultTupleSlot = node->ps.ps_ResultTupleSlot;
+ CHECK_FOR_INTERRUPTS();
+
/*
* If the previously-returned tuple needs to be returned more than once,
* keep returning it.
@@ -428,6 +431,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 924b458..799a4e9 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
*/
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index e8fa4c8..fe10e80 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"
@@ -65,6 +66,8 @@ ExecSubPlan(SubPlanState *node,
{
SubPlan *subplan = node->subplan;
+ CHECK_FOR_INTERRUPTS();
+
/* Set non-null as default */
*isNull = false;
@@ -618,6 +621,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,
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index bb016ec..2859363 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -440,6 +440,8 @@ tfuncLoadRows(TableFuncScanState *tstate, ExprContext *econtext)
ListCell *cell = list_head(tstate->coldefexprs);
int colno;
+ CHECK_FOR_INTERRUPTS();
+
ExecClearTuple(tstate->ss.ss_ScanTupleSlot);
/*
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 96af2d2..c122473 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -26,6 +26,7 @@
#include "catalog/pg_type.h"
#include "executor/execdebug.h"
#include "executor/nodeTidscan.h"
+#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "storage/bufmgr.h"
#include "utils/array.h"
@@ -400,6 +401,8 @@ TidNext(TidScanState *node)
node->tss_TidPtr--;
else
node->tss_TidPtr++;
+
+ CHECK_FOR_INTERRUPTS();
}
/*
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 28cc1e9..db78c88 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"
@@ -50,6 +51,8 @@ ExecUnique(UniqueState *node)
TupleTableSlot *slot;
PlanState *outerPlan;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get information from the node
*/
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 8f13fe0..9da35ac 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1594,6 +1594,8 @@ ExecWindowAgg(WindowAggState *winstate)
int i;
int numfuncs;
+ CHECK_FOR_INTERRUPTS();
+
if (winstate->all_done)
return NULL;
@@ -2371,6 +2373,9 @@ window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
WindowAggState *winstate = winobj->winstate;
MemoryContext oldcontext;
+ /* often called repeatedly in a row */
+ CHECK_FOR_INTERRUPTS();
+
/* Don't allow passing -1 to spool_tuples here */
if (pos < 0)
return false;
On 2017-07-29 14:20:32 -0400, Tom Lane wrote:
Here's a reviewed version of this patch.
Thanks!
* I think you put ExecScan's CFI in the wrong place; AFAICT yours
only covers its fast path.
Sure - but the old path already has a CFI? And it has to be inside the
loop, because well, the loop ;).
* I think ExecAgg needs a CFI at the head, just to be sure it's hit
in any path through that.
Yep, makes esense.
* I agree that putting CFI inside ExecHashJoin's state machine loop
is a good idea, because it might have to trawl through quite a lot of
a batch file before finding a returnable tuple. But I think in merge
and nestloop joins it's sufficient to put one CFI at the head. Neither
of those cases can do very much processing without invoking a child
node, where a CFI will happen.
Ok, I can live with that.
* You missed ExecLockRows altogether.
Well, it directly calls the next ExecProcNode(), so I didn't think it
was necessary. One of the aforementioned judgement calls. But I'm
perfectly happy to have one there.
Thanks,
Andres
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@anarazel.de> writes:
[ 0002-Move-ExecProcNode-from-dispatch-to-function-pointer-.patch ]
Here's a reviewed version of this patch.
I added dummy ExecProcNodeMtd functions to the various node types that
lacked them because they expect to be called through MultiExecProcNode
instead. In the old coding, trying to call ExecProcNode on one of those
node types would have led to a useful error message; as you had it,
it'd have dumped core, which is not an improvement.
Also, I removed the ExecReScan stanza from ExecProcNodeFirst; that
should surely be redundant, because we should only get to that function
through ExecProcNode(). If somehow it's not redundant, please add a
comment explaining why not.
Some other minor cosmetic changes, mostly comment wordsmithing.
I think this (and the previous one) are committable.
regards, tom lane
Attachments:
use-function-pointer-for-ExecProcNode-v3.patchtext/x-diff; charset=us-ascii; name=use-function-pointer-for-ExecProcNode-v3.patchDownload
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 20fd9f8..d338cfe 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -17,15 +17,10 @@
*-------------------------------------------------------------------------
*/
/*
- * INTERFACE ROUTINES
- * ExecInitNode - initialize a plan node and its subplans
- * ExecProcNode - get a tuple by executing the plan node
- * ExecEndNode - shut down a plan node and its subplans
- *
* NOTES
* This used to be three files. It is now all combined into
- * one file so that it is easier to keep ExecInitNode, ExecProcNode,
- * and ExecEndNode in sync when new nodes are added.
+ * one file so that it is easier to keep the dispatch routines
+ * in sync when new nodes are added.
*
* EXAMPLE
* Suppose we want the age of the manager of the shoe department and
@@ -122,6 +117,10 @@
#include "miscadmin.h"
+static TupleTableSlot *ExecProcNodeFirst(PlanState *node);
+static TupleTableSlot *ExecProcNodeInstr(PlanState *node);
+
+
/* ------------------------------------------------------------------------
* ExecInitNode
*
@@ -149,6 +148,13 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
if (node == NULL)
return NULL;
+ /*
+ * Make sure there's enough stack available. Need to check here, in
+ * addition to ExecProcNode() (via ExecProcNodeFirst()), to ensure the
+ * stack isn't overrun while initializing the node tree.
+ */
+ check_stack_depth();
+
switch (nodeTag(node))
{
/*
@@ -365,6 +371,13 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
}
/*
+ * Add a wrapper around the ExecProcNode callback that checks stack depth
+ * during the first execution.
+ */
+ result->ExecProcNodeReal = result->ExecProcNode;
+ result->ExecProcNode = ExecProcNodeFirst;
+
+ /*
* Initialize any initPlans present in this node. The planner put them in
* a separate list for us.
*/
@@ -388,195 +401,51 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
}
-/* ----------------------------------------------------------------
- * ExecProcNode
- *
- * Execute the given node to return a(nother) tuple.
- * ----------------------------------------------------------------
+/*
+ * ExecProcNode wrapper that performs some one-time checks, before calling
+ * the relevant node method (possibly via an instrumentation wrapper).
*/
-TupleTableSlot *
-ExecProcNode(PlanState *node)
+static TupleTableSlot *
+ExecProcNodeFirst(PlanState *node)
{
- TupleTableSlot *result;
-
- if (node->chgParam != NULL) /* something changed */
- ExecReScan(node); /* let ReScan handle this */
+ /*
+ * Perform stack depth check during the first execution of the node. We
+ * only do so the first time round because it turns out to not be cheap on
+ * some common architectures (eg. x86). This relies on an assumption that
+ * ExecProcNode calls for a given plan node will always be made at roughly
+ * the same stack depth.
+ */
+ check_stack_depth();
+ /*
+ * If instrumentation is required, change the wrapper to one that just
+ * does instrumentation. Otherwise we can dispense with all wrappers and
+ * have ExecProcNode() directly call the relevant function from now on.
+ */
if (node->instrument)
- InstrStartNode(node->instrument);
-
- switch (nodeTag(node))
- {
- /*
- * control nodes
- */
- case T_ResultState:
- result = ExecResult((ResultState *) node);
- break;
-
- case T_ProjectSetState:
- result = ExecProjectSet((ProjectSetState *) node);
- break;
-
- case T_ModifyTableState:
- result = ExecModifyTable((ModifyTableState *) node);
- break;
-
- case T_AppendState:
- result = ExecAppend((AppendState *) node);
- break;
-
- case T_MergeAppendState:
- result = ExecMergeAppend((MergeAppendState *) node);
- break;
-
- case T_RecursiveUnionState:
- result = ExecRecursiveUnion((RecursiveUnionState *) node);
- break;
-
- /* BitmapAndState does not yield tuples */
-
- /* BitmapOrState does not yield tuples */
-
- /*
- * scan nodes
- */
- case T_SeqScanState:
- result = ExecSeqScan((SeqScanState *) node);
- break;
-
- case T_SampleScanState:
- result = ExecSampleScan((SampleScanState *) node);
- break;
-
- case T_IndexScanState:
- result = ExecIndexScan((IndexScanState *) node);
- break;
-
- case T_IndexOnlyScanState:
- result = ExecIndexOnlyScan((IndexOnlyScanState *) node);
- break;
-
- /* BitmapIndexScanState does not yield tuples */
-
- case T_BitmapHeapScanState:
- result = ExecBitmapHeapScan((BitmapHeapScanState *) node);
- break;
-
- case T_TidScanState:
- result = ExecTidScan((TidScanState *) node);
- break;
-
- case T_SubqueryScanState:
- result = ExecSubqueryScan((SubqueryScanState *) node);
- break;
-
- case T_FunctionScanState:
- result = ExecFunctionScan((FunctionScanState *) node);
- break;
-
- case T_TableFuncScanState:
- result = ExecTableFuncScan((TableFuncScanState *) node);
- break;
-
- case T_ValuesScanState:
- result = ExecValuesScan((ValuesScanState *) node);
- break;
-
- case T_CteScanState:
- result = ExecCteScan((CteScanState *) node);
- break;
-
- case T_NamedTuplestoreScanState:
- result = ExecNamedTuplestoreScan((NamedTuplestoreScanState *) node);
- break;
-
- case T_WorkTableScanState:
- result = ExecWorkTableScan((WorkTableScanState *) node);
- break;
-
- case T_ForeignScanState:
- result = ExecForeignScan((ForeignScanState *) node);
- break;
-
- case T_CustomScanState:
- result = ExecCustomScan((CustomScanState *) node);
- break;
-
- /*
- * join nodes
- */
- case T_NestLoopState:
- result = ExecNestLoop((NestLoopState *) node);
- break;
-
- case T_MergeJoinState:
- result = ExecMergeJoin((MergeJoinState *) node);
- break;
-
- case T_HashJoinState:
- result = ExecHashJoin((HashJoinState *) node);
- break;
-
- /*
- * materialization nodes
- */
- case T_MaterialState:
- result = ExecMaterial((MaterialState *) node);
- break;
-
- case T_SortState:
- result = ExecSort((SortState *) node);
- break;
-
- case T_GroupState:
- result = ExecGroup((GroupState *) node);
- break;
+ node->ExecProcNode = ExecProcNodeInstr;
+ else
+ node->ExecProcNode = node->ExecProcNodeReal;
- case T_AggState:
- result = ExecAgg((AggState *) node);
- break;
-
- case T_WindowAggState:
- result = ExecWindowAgg((WindowAggState *) node);
- break;
-
- case T_UniqueState:
- result = ExecUnique((UniqueState *) node);
- break;
-
- case T_GatherState:
- result = ExecGather((GatherState *) node);
- break;
-
- case T_GatherMergeState:
- result = ExecGatherMerge((GatherMergeState *) node);
- break;
-
- case T_HashState:
- result = ExecHash((HashState *) node);
- break;
+ return node->ExecProcNode(node);
+}
- case T_SetOpState:
- result = ExecSetOp((SetOpState *) node);
- break;
- case T_LockRowsState:
- result = ExecLockRows((LockRowsState *) node);
- break;
+/*
+ * ExecProcNode wrapper that performs instrumentation calls. By keeping
+ * this a separate function, we avoid overhead in the normal case where
+ * no instrumentation is wanted.
+ */
+static TupleTableSlot *
+ExecProcNodeInstr(PlanState *node)
+{
+ TupleTableSlot *result;
- case T_LimitState:
- result = ExecLimit((LimitState *) node);
- break;
+ InstrStartNode(node->instrument);
- default:
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
- result = NULL;
- break;
- }
+ result = node->ExecProcNodeReal(node);
- if (node->instrument)
- InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
+ InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
return result;
}
@@ -600,6 +469,8 @@ MultiExecProcNode(PlanState *node)
{
Node *result;
+ check_stack_depth();
+
CHECK_FOR_INTERRUPTS();
if (node->chgParam != NULL) /* something changed */
@@ -657,6 +528,13 @@ ExecEndNode(PlanState *node)
if (node == NULL)
return;
+ /*
+ * Make sure there's enough stack available. Need to check here, in
+ * addition to ExecProcNode() (via ExecProcNodeFirst()), because it's not
+ * guaranteed that ExecProcNode() is reached for all nodes.
+ */
+ check_stack_depth();
+
if (node->chgParam != NULL)
{
bms_free(node->chgParam);
@@ -855,6 +733,8 @@ ExecShutdownNode(PlanState *node)
if (node == NULL)
return false;
+ check_stack_depth();
+
planstate_tree_walker(node, ExecShutdownNode, NULL);
switch (nodeTag(node))
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 377916d..6a26773 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -2099,9 +2099,10 @@ lookup_hash_entries(AggState *aggstate)
* stored in the expression context to be used when ExecProject evaluates
* the result tuple.
*/
-TupleTableSlot *
-ExecAgg(AggState *node)
+static TupleTableSlot *
+ExecAgg(PlanState *pstate)
{
+ AggState *node = castNode(AggState, pstate);
TupleTableSlot *result = NULL;
CHECK_FOR_INTERRUPTS();
@@ -2695,6 +2696,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
aggstate = makeNode(AggState);
aggstate->ss.ps.plan = (Plan *) node;
aggstate->ss.ps.state = estate;
+ aggstate->ss.ps.ExecProcNode = ExecAgg;
aggstate->aggs = NIL;
aggstate->numaggs = 0;
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 58045e0..bed9bb8 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -61,6 +61,7 @@
#include "executor/nodeAppend.h"
#include "miscadmin.h"
+static TupleTableSlot *ExecAppend(PlanState *pstate);
static bool exec_append_initialize_next(AppendState *appendstate);
@@ -147,6 +148,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
*/
appendstate->ps.plan = (Plan *) node;
appendstate->ps.state = estate;
+ appendstate->ps.ExecProcNode = ExecAppend;
appendstate->appendplans = appendplanstates;
appendstate->as_nplans = nplans;
@@ -197,9 +199,11 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
* Handles iteration over multiple subplans.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecAppend(AppendState *node)
+static TupleTableSlot *
+ExecAppend(PlanState *pstate)
{
+ AppendState *node = castNode(AppendState, pstate);
+
for (;;)
{
PlanState *subnode;
diff --git a/src/backend/executor/nodeBitmapAnd.c b/src/backend/executor/nodeBitmapAnd.c
index e4eb028..1c5c312 100644
--- a/src/backend/executor/nodeBitmapAnd.c
+++ b/src/backend/executor/nodeBitmapAnd.c
@@ -33,6 +33,19 @@
/* ----------------------------------------------------------------
+ * ExecBitmapAnd
+ *
+ * stub for pro forma compliance
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+ExecBitmapAnd(PlanState *pstate)
+{
+ elog(ERROR, "BitmapAnd node does not support ExecProcNode call convention");
+ return NULL;
+}
+
+/* ----------------------------------------------------------------
* ExecInitBitmapAnd
*
* Begin all of the subscans of the BitmapAnd node.
@@ -63,6 +76,7 @@ ExecInitBitmapAnd(BitmapAnd *node, EState *estate, int eflags)
*/
bitmapandstate->ps.plan = (Plan *) node;
bitmapandstate->ps.state = estate;
+ bitmapandstate->ps.ExecProcNode = ExecBitmapAnd;
bitmapandstate->bitmapplans = bitmapplanstates;
bitmapandstate->nplans = nplans;
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index cf109d5..79f534e 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -665,9 +665,11 @@ BitmapHeapRecheck(BitmapHeapScanState *node, TupleTableSlot *slot)
* ExecBitmapHeapScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecBitmapHeapScan(BitmapHeapScanState *node)
+static TupleTableSlot *
+ExecBitmapHeapScan(PlanState *pstate)
{
+ BitmapHeapScanState *node = castNode(BitmapHeapScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) BitmapHeapNext,
(ExecScanRecheckMtd) BitmapHeapRecheck);
@@ -815,6 +817,7 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
scanstate = makeNode(BitmapHeapScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecBitmapHeapScan;
scanstate->tbm = NULL;
scanstate->tbmiterator = NULL;
diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c
index 2411a2e..6feb70f 100644
--- a/src/backend/executor/nodeBitmapIndexscan.c
+++ b/src/backend/executor/nodeBitmapIndexscan.c
@@ -29,6 +29,19 @@
/* ----------------------------------------------------------------
+ * ExecBitmapIndexScan
+ *
+ * stub for pro forma compliance
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+ExecBitmapIndexScan(PlanState *pstate)
+{
+ elog(ERROR, "BitmapIndexScan node does not support ExecProcNode call convention");
+ return NULL;
+}
+
+/* ----------------------------------------------------------------
* MultiExecBitmapIndexScan(node)
* ----------------------------------------------------------------
*/
@@ -208,6 +221,7 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
indexstate = makeNode(BitmapIndexScanState);
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
+ indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
/* normally we don't make the result bitmap till runtime */
indexstate->biss_result = NULL;
diff --git a/src/backend/executor/nodeBitmapOr.c b/src/backend/executor/nodeBitmapOr.c
index 4f0ddc6..66a7a89 100644
--- a/src/backend/executor/nodeBitmapOr.c
+++ b/src/backend/executor/nodeBitmapOr.c
@@ -34,6 +34,19 @@
/* ----------------------------------------------------------------
+ * ExecBitmapOr
+ *
+ * stub for pro forma compliance
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+ExecBitmapOr(PlanState *pstate)
+{
+ elog(ERROR, "BitmapOr node does not support ExecProcNode call convention");
+ return NULL;
+}
+
+/* ----------------------------------------------------------------
* ExecInitBitmapOr
*
* Begin all of the subscans of the BitmapOr node.
@@ -64,6 +77,7 @@ ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags)
*/
bitmaporstate->ps.plan = (Plan *) node;
bitmaporstate->ps.state = estate;
+ bitmaporstate->ps.ExecProcNode = ExecBitmapOr;
bitmaporstate->bitmapplans = bitmapplanstates;
bitmaporstate->nplans = nplans;
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index bed7949..79676ca 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -149,9 +149,11 @@ CteScanRecheck(CteScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecCteScan(CteScanState *node)
+static TupleTableSlot *
+ExecCteScan(PlanState *pstate)
{
+ CteScanState *node = castNode(CteScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) CteScanNext,
(ExecScanRecheckMtd) CteScanRecheck);
@@ -191,6 +193,7 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
scanstate = makeNode(CteScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecCteScan;
scanstate->eflags = eflags;
scanstate->cte_table = NULL;
scanstate->eof_cte = false;
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index fc15974..fb7645b 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -21,6 +21,10 @@
#include "utils/memutils.h"
#include "utils/rel.h"
+
+static TupleTableSlot *ExecCustomScan(PlanState *pstate);
+
+
CustomScanState *
ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
{
@@ -45,6 +49,7 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
/* fill up fields of ScanState */
css->ss.ps.plan = &cscan->scan.plan;
css->ss.ps.state = estate;
+ css->ss.ps.ExecProcNode = ExecCustomScan;
/* create expression context for node */
ExecAssignExprContext(estate, &css->ss.ps);
@@ -102,9 +107,11 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
return css;
}
-TupleTableSlot *
-ExecCustomScan(CustomScanState *node)
+static TupleTableSlot *
+ExecCustomScan(PlanState *pstate)
{
+ CustomScanState *node = castNode(CustomScanState, pstate);
+
CHECK_FOR_INTERRUPTS();
Assert(node->methods->ExecCustomScan != NULL);
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 9cde112..140e82e 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -113,10 +113,12 @@ ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecForeignScan(ForeignScanState *node)
+static TupleTableSlot *
+ExecForeignScan(PlanState *pstate)
{
- return ExecScan((ScanState *) node,
+ ForeignScanState *node = castNode(ForeignScanState, pstate);
+
+ return ExecScan(&node->ss,
(ExecScanAccessMtd) ForeignNext,
(ExecScanRecheckMtd) ForeignRecheck);
}
@@ -144,6 +146,7 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
scanstate = makeNode(ForeignScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecForeignScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 3217d64..9f87a7e 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -262,9 +262,11 @@ FunctionRecheck(FunctionScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecFunctionScan(FunctionScanState *node)
+static TupleTableSlot *
+ExecFunctionScan(PlanState *pstate)
{
+ FunctionScanState *node = castNode(FunctionScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) FunctionNext,
(ExecScanRecheckMtd) FunctionRecheck);
@@ -299,6 +301,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
scanstate = makeNode(FunctionScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecFunctionScan;
scanstate->eflags = eflags;
/*
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index 5dbe19c..e8d94ee 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -43,6 +43,7 @@
#include "utils/rel.h"
+static TupleTableSlot *ExecGather(PlanState *pstate);
static TupleTableSlot *gather_getnext(GatherState *gatherstate);
static HeapTuple gather_readnext(GatherState *gatherstate);
static void ExecShutdownGatherWorkers(GatherState *node);
@@ -69,6 +70,7 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
gatherstate = makeNode(GatherState);
gatherstate->ps.plan = (Plan *) node;
gatherstate->ps.state = estate;
+ gatherstate->ps.ExecProcNode = ExecGather;
gatherstate->need_to_scan_locally = !node->single_copy;
/*
@@ -120,9 +122,10 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
* the next qualifying tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecGather(GatherState *node)
+static TupleTableSlot *
+ExecGather(PlanState *pstate)
{
+ GatherState *node = castNode(GatherState, pstate);
TupleTableSlot *fslot = node->funnel_slot;
int i;
TupleTableSlot *slot;
diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c
index 0aff379..9a81e22 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -44,6 +44,7 @@ typedef struct GMReaderTupleBuffer
*/
#define MAX_TUPLE_STORE 10
+static TupleTableSlot *ExecGatherMerge(PlanState *pstate);
static int32 heap_compare_slots(Datum a, Datum b, void *arg);
static TupleTableSlot *gather_merge_getnext(GatherMergeState *gm_state);
static HeapTuple gm_readnext_tuple(GatherMergeState *gm_state, int nreader,
@@ -75,6 +76,7 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
gm_state = makeNode(GatherMergeState);
gm_state->ps.plan = (Plan *) node;
gm_state->ps.state = estate;
+ gm_state->ps.ExecProcNode = ExecGatherMerge;
/*
* Miscellaneous initialization
@@ -157,9 +159,10 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
* the next qualifying tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecGatherMerge(GatherMergeState *node)
+static TupleTableSlot *
+ExecGatherMerge(PlanState *pstate)
{
+ GatherMergeState *node = castNode(GatherMergeState, pstate);
TupleTableSlot *slot;
ExprContext *econtext;
int i;
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index fc5e0e5..ab4ae24 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -32,9 +32,10 @@
*
* Return one tuple for each group of matching input tuples.
*/
-TupleTableSlot *
-ExecGroup(GroupState *node)
+static TupleTableSlot *
+ExecGroup(PlanState *pstate)
{
+ GroupState *node = castNode(GroupState, pstate);
ExprContext *econtext;
int numCols;
AttrNumber *grpColIdx;
@@ -175,6 +176,7 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
grpstate = makeNode(GroupState);
grpstate->ss.ps.plan = (Plan *) node;
grpstate->ss.ps.state = estate;
+ grpstate->ss.ps.ExecProcNode = ExecGroup;
grpstate->grp_done = FALSE;
/*
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index fbeb562..d10d94c 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -56,8 +56,8 @@ static void *dense_alloc(HashJoinTable hashtable, Size size);
* stub for pro forma compliance
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecHash(HashState *node)
+static TupleTableSlot *
+ExecHash(PlanState *pstate)
{
elog(ERROR, "Hash node does not support ExecProcNode call convention");
return NULL;
@@ -172,6 +172,7 @@ ExecInitHash(Hash *node, EState *estate, int eflags)
hashstate = makeNode(HashState);
hashstate->ps.plan = (Plan *) node;
hashstate->ps.state = estate;
+ hashstate->ps.ExecProcNode = ExecHash;
hashstate->hashtable = NULL;
hashstate->hashkeys = NIL; /* will be set by parent HashJoin */
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 252960c..ab1632c 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -58,9 +58,10 @@ static bool ExecHashJoinNewBatch(HashJoinState *hjstate);
* the other one is "outer".
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecHashJoin(HashJoinState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecHashJoin(PlanState *pstate)
{
+ HashJoinState *node = castNode(HashJoinState, pstate);
PlanState *outerNode;
HashState *hashNode;
ExprState *joinqual;
@@ -399,6 +400,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
hjstate = makeNode(HashJoinState);
hjstate->js.ps.plan = (Plan *) node;
hjstate->js.ps.state = estate;
+ hjstate->js.ps.ExecProcNode = ExecHashJoin;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index e2000764..fe7ba3f 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -306,9 +306,11 @@ IndexOnlyRecheck(IndexOnlyScanState *node, TupleTableSlot *slot)
* ExecIndexOnlyScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecIndexOnlyScan(IndexOnlyScanState *node)
+static TupleTableSlot *
+ExecIndexOnlyScan(PlanState *pstate)
{
+ IndexOnlyScanState *node = castNode(IndexOnlyScanState, pstate);
+
/*
* If we have runtime keys and they've not already been set up, do it now.
*/
@@ -476,6 +478,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
indexstate = makeNode(IndexOnlyScanState);
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
+ indexstate->ss.ps.ExecProcNode = ExecIndexOnlyScan;
indexstate->ioss_HeapFetches = 0;
/*
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 6704ede..404076d 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -542,9 +542,11 @@ reorderqueue_pop(IndexScanState *node)
* ExecIndexScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecIndexScan(IndexScanState *node)
+static TupleTableSlot *
+ExecIndexScan(PlanState *pstate)
{
+ IndexScanState *node = castNode(IndexScanState, pstate);
+
/*
* If we have runtime keys and they've not already been set up, do it now.
*/
@@ -910,6 +912,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
indexstate = makeNode(IndexScanState);
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
+ indexstate->ss.ps.ExecProcNode = ExecIndexScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index 2ed3523..ac5a2ff 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -37,9 +37,10 @@ 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 */
-ExecLimit(LimitState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecLimit(PlanState *pstate)
{
+ LimitState *node = castNode(LimitState, pstate);
ScanDirection direction;
TupleTableSlot *slot;
PlanState *outerPlan;
@@ -378,6 +379,7 @@ ExecInitLimit(Limit *node, EState *estate, int eflags)
limitstate = makeNode(LimitState);
limitstate->ps.plan = (Plan *) node;
limitstate->ps.state = estate;
+ limitstate->ps.ExecProcNode = ExecLimit;
limitstate->lstate = LIMIT_INITIAL;
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index dd4e2c5..9389560 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -36,9 +36,10 @@
* ExecLockRows
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecLockRows(LockRowsState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecLockRows(PlanState *pstate)
{
+ LockRowsState *node = castNode(LockRowsState, pstate);
TupleTableSlot *slot;
EState *estate;
PlanState *outerPlan;
@@ -364,6 +365,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
lrstate = makeNode(LockRowsState);
lrstate->ps.plan = (Plan *) node;
lrstate->ps.state = estate;
+ lrstate->ps.ExecProcNode = ExecLockRows;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 3342949..91178f1 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -35,9 +35,10 @@
*
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* result tuple from subplan */
-ExecMaterial(MaterialState *node)
+static TupleTableSlot * /* result tuple from subplan */
+ExecMaterial(PlanState *pstate)
{
+ MaterialState *node = castNode(MaterialState, pstate);
EState *estate;
ScanDirection dir;
bool forward;
@@ -173,6 +174,7 @@ ExecInitMaterial(Material *node, EState *estate, int eflags)
matstate = makeNode(MaterialState);
matstate->ss.ps.plan = (Plan *) node;
matstate->ss.ps.state = estate;
+ matstate->ss.ps.ExecProcNode = ExecMaterial;
/*
* We must have a tuplestore buffering the subplan output to do backward
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index d41def1..6bf490b 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -50,6 +50,7 @@
*/
typedef int32 SlotNumber;
+static TupleTableSlot *ExecMergeAppend(PlanState *pstate);
static int heap_compare_slots(Datum a, Datum b, void *arg);
@@ -89,6 +90,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
*/
mergestate->ps.plan = (Plan *) node;
mergestate->ps.state = estate;
+ mergestate->ps.ExecProcNode = ExecMergeAppend;
mergestate->mergeplans = mergeplanstates;
mergestate->ms_nplans = nplans;
@@ -169,9 +171,10 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
* Handles iteration over multiple subplans.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecMergeAppend(MergeAppendState *node)
+static TupleTableSlot *
+ExecMergeAppend(PlanState *pstate)
{
+ MergeAppendState *node = castNode(MergeAppendState, pstate);
TupleTableSlot *result;
SlotNumber i;
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 324b61b..925b4cf 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -596,9 +596,10 @@ ExecMergeTupleDump(MergeJoinState *mergestate)
* ExecMergeJoin
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecMergeJoin(MergeJoinState *node)
+static TupleTableSlot *
+ExecMergeJoin(PlanState *pstate)
{
+ MergeJoinState *node = castNode(MergeJoinState, pstate);
ExprState *joinqual;
ExprState *otherqual;
bool qualResult;
@@ -1448,6 +1449,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
mergestate = makeNode(MergeJoinState);
mergestate->js.ps.plan = (Plan *) node;
mergestate->js.ps.state = estate;
+ mergestate->js.ps.ExecProcNode = ExecMergeJoin;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 637a582..0dde0ed 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1535,9 +1535,10 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
* if needed.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecModifyTable(ModifyTableState *node)
+static TupleTableSlot *
+ExecModifyTable(PlanState *pstate)
{
+ ModifyTableState *node = castNode(ModifyTableState, pstate);
EState *estate = node->ps.state;
CmdType operation = node->operation;
ResultRelInfo *saved_resultRelInfo;
@@ -1806,6 +1807,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate = makeNode(ModifyTableState);
mtstate->ps.plan = (Plan *) node;
mtstate->ps.state = estate;
+ mtstate->ps.ExecProcNode = ExecModifyTable;
mtstate->operation = operation;
mtstate->canSetTag = node->canSetTag;
diff --git a/src/backend/executor/nodeNamedtuplestorescan.c b/src/backend/executor/nodeNamedtuplestorescan.c
index 6223486..3a65b9f5 100644
--- a/src/backend/executor/nodeNamedtuplestorescan.c
+++ b/src/backend/executor/nodeNamedtuplestorescan.c
@@ -63,9 +63,11 @@ NamedTuplestoreScanRecheck(NamedTuplestoreScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecNamedTuplestoreScan(NamedTuplestoreScanState *node)
+static TupleTableSlot *
+ExecNamedTuplestoreScan(PlanState *pstate)
{
+ NamedTuplestoreScanState *node = castNode(NamedTuplestoreScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) NamedTuplestoreScanNext,
(ExecScanRecheckMtd) NamedTuplestoreScanRecheck);
@@ -97,6 +99,7 @@ ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflag
scanstate = makeNode(NamedTuplestoreScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecNamedTuplestoreScan;
enr = get_ENR(estate->es_queryEnv, node->enrname);
if (!enr)
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index bedc374..4447b7c 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -57,9 +57,10 @@
* are prepared to return the first tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecNestLoop(NestLoopState *node)
+static TupleTableSlot *
+ExecNestLoop(PlanState *pstate)
{
+ NestLoopState *node = castNode(NestLoopState, pstate);
NestLoop *nl;
PlanState *innerPlan;
PlanState *outerPlan;
@@ -275,6 +276,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
nlstate = makeNode(NestLoopState);
nlstate->js.ps.plan = (Plan *) node;
nlstate->js.ps.state = estate;
+ nlstate->js.ps.ExecProcNode = ExecNestLoop;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c
index 3b69c7a..d93462c 100644
--- a/src/backend/executor/nodeProjectSet.c
+++ b/src/backend/executor/nodeProjectSet.c
@@ -39,9 +39,10 @@ static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing);
* returning functions).
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecProjectSet(ProjectSetState *node)
+static TupleTableSlot *
+ExecProjectSet(PlanState *pstate)
{
+ ProjectSetState *node = castNode(ProjectSetState, pstate);
TupleTableSlot *outerTupleSlot;
TupleTableSlot *resultSlot;
PlanState *outerPlan;
@@ -215,6 +216,7 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
state = makeNode(ProjectSetState);
state->ps.plan = (Plan *) node;
state->ps.state = estate;
+ state->ps.ExecProcNode = ExecProjectSet;
state->pending_srf_tuples = false;
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index 2802fff..a64dd13 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -66,9 +66,10 @@ build_hash_table(RecursiveUnionState *rustate)
* 2.6 go back to 2.2
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecRecursiveUnion(RecursiveUnionState *node)
+static TupleTableSlot *
+ExecRecursiveUnion(PlanState *pstate)
{
+ RecursiveUnionState *node = castNode(RecursiveUnionState, pstate);
PlanState *outerPlan = outerPlanState(node);
PlanState *innerPlan = innerPlanState(node);
RecursiveUnion *plan = (RecursiveUnion *) node->ps.plan;
@@ -172,6 +173,7 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags)
rustate = makeNode(RecursiveUnionState);
rustate->ps.plan = (Plan *) node;
rustate->ps.state = estate;
+ rustate->ps.ExecProcNode = ExecRecursiveUnion;
rustate->eqfunctions = NULL;
rustate->hashfunctions = NULL;
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index f007f46..4c879d8 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -64,9 +64,10 @@
* 'nil' if the constant qualification is not satisfied.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecResult(ResultState *node)
+static TupleTableSlot *
+ExecResult(PlanState *pstate)
{
+ ResultState *node = castNode(ResultState, pstate);
TupleTableSlot *outerTupleSlot;
PlanState *outerPlan;
ExprContext *econtext;
@@ -191,6 +192,7 @@ ExecInitResult(Result *node, EState *estate, int eflags)
resstate = makeNode(ResultState);
resstate->ps.plan = (Plan *) node;
resstate->ps.state = estate;
+ resstate->ps.ExecProcNode = ExecResult;
resstate->rs_done = false;
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index b710ef7..9c74a83 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -96,10 +96,12 @@ SampleRecheck(SampleScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSampleScan(SampleScanState *node)
+static TupleTableSlot *
+ExecSampleScan(PlanState *pstate)
{
- return ExecScan((ScanState *) node,
+ SampleScanState *node = castNode(SampleScanState, pstate);
+
+ return ExecScan(&node->ss,
(ExecScanAccessMtd) SampleNext,
(ExecScanRecheckMtd) SampleRecheck);
}
@@ -153,6 +155,7 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
scanstate = makeNode(SampleScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecSampleScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 307df87..5c49d4c 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -121,10 +121,12 @@ SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSeqScan(SeqScanState *node)
+static TupleTableSlot *
+ExecSeqScan(PlanState *pstate)
{
- return ExecScan((ScanState *) node,
+ SeqScanState *node = castNode(SeqScanState, pstate);
+
+ return ExecScan(&node->ss,
(ExecScanAccessMtd) SeqNext,
(ExecScanRecheckMtd) SeqRecheck);
}
@@ -177,6 +179,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
scanstate = makeNode(SeqScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecSeqScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 56c5643..571cbf8 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -180,9 +180,10 @@ set_output_count(SetOpState *setopstate, SetOpStatePerGroup pergroup)
* ExecSetOp
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecSetOp(SetOpState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecSetOp(PlanState *pstate)
{
+ SetOpState *node = castNode(SetOpState, pstate);
SetOp *plannode = (SetOp *) node->ps.plan;
TupleTableSlot *resultTupleSlot = node->ps.ps_ResultTupleSlot;
@@ -485,6 +486,7 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags)
setopstate = makeNode(SetOpState);
setopstate->ps.plan = (Plan *) node;
setopstate->ps.state = estate;
+ setopstate->ps.ExecProcNode = ExecSetOp;
setopstate->eqfunctions = NULL;
setopstate->hashfunctions = NULL;
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index 799a4e9..aae4150 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -35,9 +35,10 @@
* -- the outer child is prepared to return the first tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSort(SortState *node)
+static TupleTableSlot *
+ExecSort(PlanState *pstate)
{
+ SortState *node = castNode(SortState, pstate);
EState *estate;
ScanDirection dir;
Tuplesortstate *tuplesortstate;
@@ -165,6 +166,7 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
sortstate = makeNode(SortState);
sortstate->ss.ps.plan = (Plan *) node;
sortstate->ss.ps.state = estate;
+ sortstate->ss.ps.ExecProcNode = ExecSort;
/*
* We must have random access to the sort output to do backward scan or
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index ae18470..088c929 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -79,9 +79,11 @@ SubqueryRecheck(SubqueryScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSubqueryScan(SubqueryScanState *node)
+static TupleTableSlot *
+ExecSubqueryScan(PlanState *pstate)
{
+ SubqueryScanState *node = castNode(SubqueryScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) SubqueryNext,
(ExecScanRecheckMtd) SubqueryRecheck);
@@ -109,6 +111,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
subquerystate = makeNode(SubqueryScanState);
subquerystate->ss.ps.plan = (Plan *) node;
subquerystate->ss.ps.state = estate;
+ subquerystate->ss.ps.ExecProcNode = ExecSubqueryScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index 2859363..b03d2ef 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -93,9 +93,11 @@ TableFuncRecheck(TableFuncScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecTableFuncScan(TableFuncScanState *node)
+static TupleTableSlot *
+ExecTableFuncScan(PlanState *pstate)
{
+ TableFuncScanState *node = castNode(TableFuncScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) TableFuncNext,
(ExecScanRecheckMtd) TableFuncRecheck);
@@ -128,6 +130,7 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
scanstate = makeNode(TableFuncScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecTableFuncScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index c122473..0ee76e7 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -445,9 +445,11 @@ TidRecheck(TidScanState *node, TupleTableSlot *slot)
* -- tidPtr is -1.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecTidScan(TidScanState *node)
+static TupleTableSlot *
+ExecTidScan(PlanState *pstate)
{
+ TidScanState *node = castNode(TidScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) TidNext,
(ExecScanRecheckMtd) TidRecheck);
@@ -519,6 +521,7 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
tidstate = makeNode(TidScanState);
tidstate->ss.ps.plan = (Plan *) node;
tidstate->ss.ps.state = estate;
+ tidstate->ss.ps.ExecProcNode = ExecTidScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index db78c88..621fdd9 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -43,9 +43,10 @@
* ExecUnique
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecUnique(UniqueState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecUnique(PlanState *pstate)
{
+ UniqueState *node = castNode(UniqueState, pstate);
Unique *plannode = (Unique *) node->ps.plan;
TupleTableSlot *resultTupleSlot;
TupleTableSlot *slot;
@@ -125,6 +126,7 @@ ExecInitUnique(Unique *node, EState *estate, int eflags)
uniquestate = makeNode(UniqueState);
uniquestate->ps.plan = (Plan *) node;
uniquestate->ps.state = estate;
+ uniquestate->ps.ExecProcNode = ExecUnique;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index 9ee776c..6eacaed 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -185,9 +185,11 @@ ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecValuesScan(ValuesScanState *node)
+static TupleTableSlot *
+ExecValuesScan(PlanState *pstate)
{
+ ValuesScanState *node = castNode(ValuesScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) ValuesNext,
(ExecScanRecheckMtd) ValuesRecheck);
@@ -218,6 +220,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
scanstate = makeNode(ValuesScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecValuesScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 9da35ac..80be460 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1587,9 +1587,10 @@ update_frametailpos(WindowObject winobj, TupleTableSlot *slot)
* returned rows is exactly the same as its outer subplan's result.
* -----------------
*/
-TupleTableSlot *
-ExecWindowAgg(WindowAggState *winstate)
+static TupleTableSlot *
+ExecWindowAgg(PlanState *pstate)
{
+ WindowAggState *winstate = castNode(WindowAggState, pstate);
ExprContext *econtext;
int i;
int numfuncs;
@@ -1790,6 +1791,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
winstate = makeNode(WindowAggState);
winstate->ss.ps.plan = (Plan *) node;
winstate->ss.ps.state = estate;
+ winstate->ss.ps.ExecProcNode = ExecWindowAgg;
/*
* Create expression contexts. We need two, one for per-input-tuple
diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c
index d7616be..d5ffadd 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -77,9 +77,11 @@ WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecWorkTableScan(WorkTableScanState *node)
+static TupleTableSlot *
+ExecWorkTableScan(PlanState *pstate)
{
+ WorkTableScanState *node = castNode(WorkTableScanState, pstate);
+
/*
* On the first call, find the ancestor RecursiveUnion's state via the
* Param slot reserved for it. (We can't do this during node init because
@@ -144,6 +146,7 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
scanstate = makeNode(WorkTableScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
scanstate->rustate = NULL; /* we'll set this later */
/*
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 59c28b7..60326f9 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -225,14 +225,31 @@ extern void EvalPlanQualBegin(EPQState *epqstate, EState *parentestate);
extern void EvalPlanQualEnd(EPQState *epqstate);
/*
- * prototypes from functions in execProcnode.c
+ * functions in execProcnode.c
*/
extern PlanState *ExecInitNode(Plan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecProcNode(PlanState *node);
extern Node *MultiExecProcNode(PlanState *node);
extern void ExecEndNode(PlanState *node);
extern bool ExecShutdownNode(PlanState *node);
+
+/* ----------------------------------------------------------------
+ * ExecProcNode
+ *
+ * Execute the given node to return a(nother) tuple.
+ * ----------------------------------------------------------------
+ */
+#ifndef FRONTEND
+static inline TupleTableSlot *
+ExecProcNode(PlanState *node)
+{
+ if (node->chgParam != NULL) /* something changed? */
+ ExecReScan(node); /* let ReScan handle this */
+
+ return node->ExecProcNode(node);
+}
+#endif
+
/*
* prototypes from functions in execExpr.c
*/
diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h
index fa11ba9..eff5af9 100644
--- a/src/include/executor/nodeAgg.h
+++ b/src/include/executor/nodeAgg.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern AggState *ExecInitAgg(Agg *node, EState *estate, int eflags);
-extern TupleTableSlot *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 ee0b6ad..4e38a13 100644
--- a/src/include/executor/nodeAppend.h
+++ b/src/include/executor/nodeAppend.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern AppendState *ExecInitAppend(Append *node, EState *estate, int eflags);
-extern TupleTableSlot *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 f477d1c..c77694c 100644
--- a/src/include/executor/nodeBitmapHeapscan.h
+++ b/src/include/executor/nodeBitmapHeapscan.h
@@ -18,7 +18,6 @@
#include "access/parallel.h"
extern BitmapHeapScanState *ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecEndBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecReScanBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecBitmapHeapEstimate(BitmapHeapScanState *node,
diff --git a/src/include/executor/nodeCtescan.h b/src/include/executor/nodeCtescan.h
index 397bdfd..d2fbcbd 100644
--- a/src/include/executor/nodeCtescan.h
+++ b/src/include/executor/nodeCtescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern CteScanState *ExecInitCteScan(CteScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 e81bcf7..a1cc63a 100644
--- a/src/include/executor/nodeCustom.h
+++ b/src/include/executor/nodeCustom.h
@@ -21,7 +21,6 @@
*/
extern CustomScanState *ExecInitCustomScan(CustomScan *custom_scan,
EState *estate, int eflags);
-extern TupleTableSlot *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 3ff4ecd..0b66259 100644
--- a/src/include/executor/nodeForeignscan.h
+++ b/src/include/executor/nodeForeignscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern ForeignScanState *ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 5e830eb..aaa9d8c 100644
--- a/src/include/executor/nodeFunctionscan.h
+++ b/src/include/executor/nodeFunctionscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 b000693..189bd70 100644
--- a/src/include/executor/nodeGather.h
+++ b/src/include/executor/nodeGather.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern GatherState *ExecInitGather(Gather *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecGather(GatherState *node);
extern void ExecEndGather(GatherState *node);
extern void ExecShutdownGather(GatherState *node);
extern void ExecReScanGather(GatherState *node);
diff --git a/src/include/executor/nodeGatherMerge.h b/src/include/executor/nodeGatherMerge.h
index 14b31a0..0154d73 100644
--- a/src/include/executor/nodeGatherMerge.h
+++ b/src/include/executor/nodeGatherMerge.h
@@ -19,7 +19,6 @@
extern GatherMergeState *ExecInitGatherMerge(GatherMerge *node,
EState *estate,
int eflags);
-extern TupleTableSlot *ExecGatherMerge(GatherMergeState *node);
extern void ExecEndGatherMerge(GatherMergeState *node);
extern void ExecReScanGatherMerge(GatherMergeState *node);
extern void ExecShutdownGatherMerge(GatherMergeState *node);
diff --git a/src/include/executor/nodeGroup.h b/src/include/executor/nodeGroup.h
index 7358b61..b0d7e31 100644
--- a/src/include/executor/nodeGroup.h
+++ b/src/include/executor/nodeGroup.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern GroupState *ExecInitGroup(Group *node, EState *estate, int eflags);
-extern TupleTableSlot *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 8052f27..3ae556f 100644
--- a/src/include/executor/nodeHash.h
+++ b/src/include/executor/nodeHash.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern HashState *ExecInitHash(Hash *node, EState *estate, int eflags);
-extern TupleTableSlot *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 541c81e..7469bfb 100644
--- a/src/include/executor/nodeHashjoin.h
+++ b/src/include/executor/nodeHashjoin.h
@@ -18,7 +18,6 @@
#include "storage/buffile.h"
extern HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *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 cf227da..c8a709c 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -18,7 +18,6 @@
#include "access/parallel.h"
extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 0118234..1668e34 100644
--- a/src/include/executor/nodeIndexscan.h
+++ b/src/include/executor/nodeIndexscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern IndexScanState *ExecInitIndexScan(IndexScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 7bb20d9..db65b55 100644
--- a/src/include/executor/nodeLimit.h
+++ b/src/include/executor/nodeLimit.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern LimitState *ExecInitLimit(Limit *node, EState *estate, int eflags);
-extern TupleTableSlot *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 6b90756..c9d05b8 100644
--- a/src/include/executor/nodeLockRows.h
+++ b/src/include/executor/nodeLockRows.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern LockRowsState *ExecInitLockRows(LockRows *node, EState *estate, int eflags);
-extern TupleTableSlot *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 f69abbc..4b3c257 100644
--- a/src/include/executor/nodeMaterial.h
+++ b/src/include/executor/nodeMaterial.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MaterialState *ExecInitMaterial(Material *node, EState *estate, int eflags);
-extern TupleTableSlot *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 3cc6ef5..a0ccbae 100644
--- a/src/include/executor/nodeMergeAppend.h
+++ b/src/include/executor/nodeMergeAppend.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MergeAppendState *ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags);
-extern TupleTableSlot *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 32df25a..d20e415 100644
--- a/src/include/executor/nodeMergejoin.h
+++ b/src/include/executor/nodeMergejoin.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *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 5a406f2..a2e7af9 100644
--- a/src/include/executor/nodeModifyTable.h
+++ b/src/include/executor/nodeModifyTable.h
@@ -16,7 +16,6 @@
#include "nodes/execnodes.h"
extern ModifyTableState *ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecModifyTable(ModifyTableState *node);
extern void ExecEndModifyTable(ModifyTableState *node);
extern void ExecReScanModifyTable(ModifyTableState *node);
diff --git a/src/include/executor/nodeNamedtuplestorescan.h b/src/include/executor/nodeNamedtuplestorescan.h
index 7f72fbe..395d978 100644
--- a/src/include/executor/nodeNamedtuplestorescan.h
+++ b/src/include/executor/nodeNamedtuplestorescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern NamedTuplestoreScanState *ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecNamedTuplestoreScan(NamedTuplestoreScanState *node);
extern void ExecEndNamedTuplestoreScan(NamedTuplestoreScanState *node);
extern void ExecReScanNamedTuplestoreScan(NamedTuplestoreScanState *node);
diff --git a/src/include/executor/nodeNestloop.h b/src/include/executor/nodeNestloop.h
index 8e0fcc1..0d6486c 100644
--- a/src/include/executor/nodeNestloop.h
+++ b/src/include/executor/nodeNestloop.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecNestLoop(NestLoopState *node);
extern void ExecEndNestLoop(NestLoopState *node);
extern void ExecReScanNestLoop(NestLoopState *node);
diff --git a/src/include/executor/nodeProjectSet.h b/src/include/executor/nodeProjectSet.h
index 2f6999e..a0b0521 100644
--- a/src/include/executor/nodeProjectSet.h
+++ b/src/include/executor/nodeProjectSet.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ProjectSetState *ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecProjectSet(ProjectSetState *node);
extern void ExecEndProjectSet(ProjectSetState *node);
extern void ExecReScanProjectSet(ProjectSetState *node);
diff --git a/src/include/executor/nodeRecursiveunion.h b/src/include/executor/nodeRecursiveunion.h
index f0eba05..e6ce1b4 100644
--- a/src/include/executor/nodeRecursiveunion.h
+++ b/src/include/executor/nodeRecursiveunion.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern RecursiveUnionState *ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags);
-extern TupleTableSlot *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 61d3cb2..20e0063 100644
--- a/src/include/executor/nodeResult.h
+++ b/src/include/executor/nodeResult.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ResultState *ExecInitResult(Result *node, EState *estate, int eflags);
-extern TupleTableSlot *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 ed06e77..607bbd9 100644
--- a/src/include/executor/nodeSamplescan.h
+++ b/src/include/executor/nodeSamplescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SampleScanState *ExecInitSampleScan(SampleScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 06e0686..0fba79f 100644
--- a/src/include/executor/nodeSeqscan.h
+++ b/src/include/executor/nodeSeqscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern SeqScanState *ExecInitSeqScan(SeqScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 af85977..c15f945 100644
--- a/src/include/executor/nodeSetOp.h
+++ b/src/include/executor/nodeSetOp.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate, int eflags);
-extern TupleTableSlot *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 1d2b713..ed0e9db 100644
--- a/src/include/executor/nodeSort.h
+++ b/src/include/executor/nodeSort.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SortState *ExecInitSort(Sort *node, EState *estate, int eflags);
-extern TupleTableSlot *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 c852e29..710e050 100644
--- a/src/include/executor/nodeSubqueryscan.h
+++ b/src/include/executor/nodeSubqueryscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SubqueryScanState *ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSubqueryScan(SubqueryScanState *node);
extern void ExecEndSubqueryScan(SubqueryScanState *node);
extern void ExecReScanSubqueryScan(SubqueryScanState *node);
diff --git a/src/include/executor/nodeTableFuncscan.h b/src/include/executor/nodeTableFuncscan.h
index c58156e..c4672c0 100644
--- a/src/include/executor/nodeTableFuncscan.h
+++ b/src/include/executor/nodeTableFuncscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern TableFuncScanState *ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecTableFuncScan(TableFuncScanState *node);
extern void ExecEndTableFuncScan(TableFuncScanState *node);
extern void ExecReScanTableFuncScan(TableFuncScanState *node);
diff --git a/src/include/executor/nodeTidscan.h b/src/include/executor/nodeTidscan.h
index d07ed7c..e68aaf3 100644
--- a/src/include/executor/nodeTidscan.h
+++ b/src/include/executor/nodeTidscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern TidScanState *ExecInitTidScan(TidScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 3d0ac9d..008774a 100644
--- a/src/include/executor/nodeUnique.h
+++ b/src/include/executor/nodeUnique.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern UniqueState *ExecInitUnique(Unique *node, EState *estate, int eflags);
-extern TupleTableSlot *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 c28bb1a..772a5e9 100644
--- a/src/include/executor/nodeValuesscan.h
+++ b/src/include/executor/nodeValuesscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ValuesScanState *ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 db1ad60..1c17730 100644
--- a/src/include/executor/nodeWindowAgg.h
+++ b/src/include/executor/nodeWindowAgg.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern WindowAggState *ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags);
-extern TupleTableSlot *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 c222d9f..df05e75 100644
--- a/src/include/executor/nodeWorktablescan.h
+++ b/src/include/executor/nodeWorktablescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern WorkTableScanState *ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags);
-extern TupleTableSlot *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 85fac8a..35c28a6 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -818,6 +818,18 @@ typedef struct DomainConstraintState
* ----------------------------------------------------------------
*/
+struct PlanState;
+
+/* ----------------
+ * ExecProcNodeMtd
+ *
+ * This is the method called by ExecProcNode to return the next tuple
+ * from an executor node. It returns NULL, or an empty TupleTableSlot,
+ * if no more tuples are available.
+ * ----------------
+ */
+typedef TupleTableSlot *(*ExecProcNodeMtd) (struct PlanState *pstate);
+
/* ----------------
* PlanState node
*
@@ -835,6 +847,10 @@ typedef struct PlanState
* nodes point to one EState for the whole
* top-level plan */
+ ExecProcNodeMtd ExecProcNode; /* function to return next tuple */
+ ExecProcNodeMtd ExecProcNodeReal; /* actual function, if above is a
+ * wrapper */
+
Instrumentation *instrument; /* Optional runtime stats for this node */
WorkerInstrumentation *worker_instrument; /* per-worker instrumentation */
Hi,
On 2017-07-29 16:14:08 -0400, Tom Lane wrote:
Andres Freund <andres@anarazel.de> writes:
[ 0002-Move-ExecProcNode-from-dispatch-to-function-pointer-.patch ]
Here's a reviewed version of this patch.
Thanks! I pushed both now.
I added dummy ExecProcNodeMtd functions to the various node types that
lacked them because they expect to be called through MultiExecProcNode
instead. In the old coding, trying to call ExecProcNode on one of those
node types would have led to a useful error message; as you had it,
it'd have dumped core, which is not an improvement.
Ok, makes sense.
Also, I removed the ExecReScan stanza from ExecProcNodeFirst; that
should surely be redundant, because we should only get to that function
through ExecProcNode(). If somehow it's not redundant, please add a
comment explaining why not.
Makes sense too.
Some other minor cosmetic changes, mostly comment wordsmithing.
Thanks!
Julien, could you quickly verify that everything's good for you now too?
Regards,
Andres
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 31/07/2017 01:47, Andres Freund wrote:
Julien, could you quickly verify that everything's good for you now too?
I just checked on current HEAD
(cc9f08b6b813e30789100b6b34110d8be1090ba0) and everything's good for me.
Thanks!
--
Julien Rouhaud
http://dalibo.com - http://dalibo.org
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Jul 28, 2017 at 02:42:06PM -0400, Robert Haas wrote:
On Fri, Jul 28, 2017 at 12:29 PM, Noah Misch <noah@leadboat.com> wrote:
Your colleagues achieve compliance despite uncertainty; for inspiration, I
recommend examining Alvaro's status updates as examples of this. The policy
currently governs your open items even if you disagree with it.
Thanks for resolving this open item.
I emphatically agree with that. If the RMT is to accomplish its
purpose, it must be able to exert authority even when an individual
contributor doesn't like the decisions it makes.On the other hand, nothing in the open item policy the current RMT has
adopted prohibits you from using judgement about when and how
vigorously to enforce that policy in any particular case, and I would
encourage you to do so.
I understand. When it comes to open item regulation, the aspects that keep me
up at night are completeness and fairness. Minimizing list traffic about
non-compliant open items is third priority at best. Furthermore, it takes an
expensive and subjective calculation to determine whether a policy-violating
open item is progressing well. I will keep an eye out for minor policy
violations that I can ignore cheaply and fairly.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers