1717 *-------------------------------------------------------------------------
1818 */
1919/*
20- * INTERFACE ROUTINES
21- *ExecInitNode-initialize a plan node and its subplans
22- *ExecProcNode-get a tuple by executing the plan node
23- *ExecEndNode-shut down a plan node and its subplans
24- *
2520 * NOTES
2621 *This used to be three files. It is now all combined into
27- *one file so that it is easier to keepExecInitNode, ExecProcNode,
28- *and ExecEndNode in sync when new nodes are added.
22+ *one file so that it is easier to keepthe dispatch routines
23+ *in sync when new nodes are added.
2924 *
3025 * EXAMPLE
3126 *Suppose we want the age of the manager of the shoe department and
122117#include "miscadmin.h"
123118
124119
120+ static TupleTableSlot * ExecProcNodeFirst (PlanState * node );
121+ static TupleTableSlot * ExecProcNodeInstr (PlanState * node );
122+
123+
125124/* ------------------------------------------------------------------------
126125 *ExecInitNode
127126 *
@@ -149,6 +148,13 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
149148if (node == NULL )
150149return NULL ;
151150
151+ /*
152+ * Make sure there's enough stack available. Need to check here, in
153+ * addition to ExecProcNode() (via ExecProcNodeFirst()), to ensure the
154+ * stack isn't overrun while initializing the node tree.
155+ */
156+ check_stack_depth ();
157+
152158switch (nodeTag (node ))
153159{
154160/*
@@ -364,6 +370,13 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
364370break ;
365371}
366372
373+ /*
374+ * Add a wrapper around the ExecProcNode callback that checks stack depth
375+ * during the first execution.
376+ */
377+ result -> ExecProcNodeReal = result -> ExecProcNode ;
378+ result -> ExecProcNode = ExecProcNodeFirst ;
379+
367380/*
368381 * Initialize any initPlans present in this node. The planner put them in
369382 * a separate list for us.
@@ -388,195 +401,51 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
388401}
389402
390403
391- /* ----------------------------------------------------------------
392- *ExecProcNode
393- *
394- *Execute the given node to return a(nother) tuple.
395- * ----------------------------------------------------------------
404+ /*
405+ * ExecProcNode wrapper that performs some one-time checks, before calling
406+ * the relevant node method (possibly via an instrumentation wrapper).
396407 */
397- TupleTableSlot *
398- ExecProcNode (PlanState * node )
408+ static TupleTableSlot *
409+ ExecProcNodeFirst (PlanState * node )
399410{
400- TupleTableSlot * result ;
401-
402- if (node -> chgParam != NULL )/* something changed */
403- ExecReScan (node );/* let ReScan handle this */
411+ /*
412+ * Perform stack depth check during the first execution of the node. We
413+ * only do so the first time round because it turns out to not be cheap on
414+ * some common architectures (eg. x86). This relies on the assumption that
415+ * ExecProcNode calls for a given plan node will always be made at roughly
416+ * the same stack depth.
417+ */
418+ check_stack_depth ();
404419
420+ /*
421+ * If instrumentation is required, change the wrapper to one that just
422+ * does instrumentation. Otherwise we can dispense with all wrappers and
423+ * have ExecProcNode() directly call the relevant function from now on.
424+ */
405425if (node -> instrument )
406- InstrStartNode (node -> instrument );
407-
408- switch (nodeTag (node ))
409- {
410- /*
411- * control nodes
412- */
413- case T_ResultState :
414- result = ExecResult ((ResultState * )node );
415- break ;
416-
417- case T_ProjectSetState :
418- result = ExecProjectSet ((ProjectSetState * )node );
419- break ;
420-
421- case T_ModifyTableState :
422- result = ExecModifyTable ((ModifyTableState * )node );
423- break ;
424-
425- case T_AppendState :
426- result = ExecAppend ((AppendState * )node );
427- break ;
428-
429- case T_MergeAppendState :
430- result = ExecMergeAppend ((MergeAppendState * )node );
431- break ;
432-
433- case T_RecursiveUnionState :
434- result = ExecRecursiveUnion ((RecursiveUnionState * )node );
435- break ;
436-
437- /* BitmapAndState does not yield tuples */
438-
439- /* BitmapOrState does not yield tuples */
440-
441- /*
442- * scan nodes
443- */
444- case T_SeqScanState :
445- result = ExecSeqScan ((SeqScanState * )node );
446- break ;
447-
448- case T_SampleScanState :
449- result = ExecSampleScan ((SampleScanState * )node );
450- break ;
451-
452- case T_IndexScanState :
453- result = ExecIndexScan ((IndexScanState * )node );
454- break ;
455-
456- case T_IndexOnlyScanState :
457- result = ExecIndexOnlyScan ((IndexOnlyScanState * )node );
458- break ;
459-
460- /* BitmapIndexScanState does not yield tuples */
461-
462- case T_BitmapHeapScanState :
463- result = ExecBitmapHeapScan ((BitmapHeapScanState * )node );
464- break ;
465-
466- case T_TidScanState :
467- result = ExecTidScan ((TidScanState * )node );
468- break ;
469-
470- case T_SubqueryScanState :
471- result = ExecSubqueryScan ((SubqueryScanState * )node );
472- break ;
473-
474- case T_FunctionScanState :
475- result = ExecFunctionScan ((FunctionScanState * )node );
476- break ;
477-
478- case T_TableFuncScanState :
479- result = ExecTableFuncScan ((TableFuncScanState * )node );
480- break ;
481-
482- case T_ValuesScanState :
483- result = ExecValuesScan ((ValuesScanState * )node );
484- break ;
485-
486- case T_CteScanState :
487- result = ExecCteScan ((CteScanState * )node );
488- break ;
489-
490- case T_NamedTuplestoreScanState :
491- result = ExecNamedTuplestoreScan ((NamedTuplestoreScanState * )node );
492- break ;
493-
494- case T_WorkTableScanState :
495- result = ExecWorkTableScan ((WorkTableScanState * )node );
496- break ;
497-
498- case T_ForeignScanState :
499- result = ExecForeignScan ((ForeignScanState * )node );
500- break ;
501-
502- case T_CustomScanState :
503- result = ExecCustomScan ((CustomScanState * )node );
504- break ;
505-
506- /*
507- * join nodes
508- */
509- case T_NestLoopState :
510- result = ExecNestLoop ((NestLoopState * )node );
511- break ;
512-
513- case T_MergeJoinState :
514- result = ExecMergeJoin ((MergeJoinState * )node );
515- break ;
516-
517- case T_HashJoinState :
518- result = ExecHashJoin ((HashJoinState * )node );
519- break ;
520-
521- /*
522- * materialization nodes
523- */
524- case T_MaterialState :
525- result = ExecMaterial ((MaterialState * )node );
526- break ;
527-
528- case T_SortState :
529- result = ExecSort ((SortState * )node );
530- break ;
531-
532- case T_GroupState :
533- result = ExecGroup ((GroupState * )node );
534- break ;
426+ node -> ExecProcNode = ExecProcNodeInstr ;
427+ else
428+ node -> ExecProcNode = node -> ExecProcNodeReal ;
535429
536- case T_AggState :
537- result = ExecAgg ((AggState * )node );
538- break ;
539-
540- case T_WindowAggState :
541- result = ExecWindowAgg ((WindowAggState * )node );
542- break ;
543-
544- case T_UniqueState :
545- result = ExecUnique ((UniqueState * )node );
546- break ;
547-
548- case T_GatherState :
549- result = ExecGather ((GatherState * )node );
550- break ;
551-
552- case T_GatherMergeState :
553- result = ExecGatherMerge ((GatherMergeState * )node );
554- break ;
555-
556- case T_HashState :
557- result = ExecHash ((HashState * )node );
558- break ;
430+ return node -> ExecProcNode (node );
431+ }
559432
560- case T_SetOpState :
561- result = ExecSetOp ((SetOpState * )node );
562- break ;
563433
564- case T_LockRowsState :
565- result = ExecLockRows ((LockRowsState * )node );
566- break ;
434+ /*
435+ * ExecProcNode wrapper that performs instrumentation calls. By keeping
436+ * this a separate function, we avoid overhead in the normal case where
437+ * no instrumentation is wanted.
438+ */
439+ static TupleTableSlot *
440+ ExecProcNodeInstr (PlanState * node )
441+ {
442+ TupleTableSlot * result ;
567443
568- case T_LimitState :
569- result = ExecLimit ((LimitState * )node );
570- break ;
444+ InstrStartNode (node -> instrument );
571445
572- default :
573- elog (ERROR ,"unrecognized node type: %d" , (int )nodeTag (node ));
574- result = NULL ;
575- break ;
576- }
446+ result = node -> ExecProcNodeReal (node );
577447
578- if (node -> instrument )
579- InstrStopNode (node -> instrument ,TupIsNull (result ) ?0.0 :1.0 );
448+ InstrStopNode (node -> instrument ,TupIsNull (result ) ?0.0 :1.0 );
580449
581450return result ;
582451}
@@ -600,6 +469,8 @@ MultiExecProcNode(PlanState *node)
600469{
601470Node * result ;
602471
472+ check_stack_depth ();
473+
603474CHECK_FOR_INTERRUPTS ();
604475
605476if (node -> chgParam != NULL )/* something changed */
@@ -657,6 +528,13 @@ ExecEndNode(PlanState *node)
657528if (node == NULL )
658529return ;
659530
531+ /*
532+ * Make sure there's enough stack available. Need to check here, in
533+ * addition to ExecProcNode() (via ExecProcNodeFirst()), because it's not
534+ * guaranteed that ExecProcNode() is reached for all nodes.
535+ */
536+ check_stack_depth ();
537+
660538if (node -> chgParam != NULL )
661539{
662540bms_free (node -> chgParam );
@@ -855,6 +733,8 @@ ExecShutdownNode(PlanState *node)
855733if (node == NULL )
856734return false;
857735
736+ check_stack_depth ();
737+
858738planstate_tree_walker (node ,ExecShutdownNode ,NULL );
859739
860740switch (nodeTag (node ))