aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execProcnode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execProcnode.c')
-rw-r--r--src/backend/executor/execProcnode.c252
1 files changed, 66 insertions, 186 deletions
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 20fd9f822ed..396920c0a23 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 the 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))