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

