>From eb621897d1410079c6458bc4d1914d1345eb77bc Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Fri, 26 Jun 2015 15:12:16 +0900
Subject: [PATCH 1/3] Add infrastructure of pre-execution callbacks.

Some exec nodes have some work before plan tree execution.
This infrastructure provides such functionality
---
 src/backend/executor/execMain.c  | 32 ++++++++++++++++++++++++++++++++
 src/backend/executor/execUtils.c |  2 ++
 src/include/nodes/execnodes.h    | 22 ++++++++++++++++++++++
 3 files changed, 56 insertions(+)

diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index a1561ce..51a86b2 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -764,6 +764,35 @@ ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
 		PreventCommandIfParallelMode(CreateCommandTag((Node *) plannedstmt));
 }
 
+/*
+ * Register callbacks to be called just before plan execution.
+ */
+void
+RegisterPreExecCallback(PreExecCallback callback, EState *es, Node *nd,
+						void *arg)
+{
+	PreExecCallbackItem *item;
+
+	item = (PreExecCallbackItem*)
+		MemoryContextAlloc(es->es_query_cxt, sizeof(PreExecCallbackItem));
+	item->callback = callback;
+	item->node = nd;
+	item->arg = arg;
+
+	/* add the new node at the end of the chain */
+	item->next = es->es_preExecCallbacks;
+	es->es_preExecCallbacks = item;	
+}
+
+/* Execute registered pre-exec callbacks */
+void
+RunPreExecCallbacks(EState *es)
+{
+	PreExecCallbackItem *item;
+
+	for (item = es->es_preExecCallbacks ; item ; item = item->next)
+		item->callback(es, item->node);
+}
 
 /* ----------------------------------------------------------------
  *		InitPlan
@@ -956,6 +985,9 @@ InitPlan(QueryDesc *queryDesc, int eflags)
 	 */
 	planstate = ExecInitNode(plan, estate, eflags);
 
+	/* Execute pre-execution callbacks registered during ExecInitNode */
+	RunPreExecCallbacks(estate);
+
 	/*
 	 * Get the tuple descriptor describing the type of tuples to return.
 	 */
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 3c611b9..e80bc22 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -123,6 +123,8 @@ CreateExecutorState(void)
 
 	estate->es_rowMarks = NIL;
 
+	estate->es_preExecCallbacks = NULL;
+
 	estate->es_processed = 0;
 	estate->es_lastoid = InvalidOid;
 
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 541ee18..cb8d854 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -343,6 +343,26 @@ typedef struct ResultRelInfo
 	List	   *ri_onConflictSetWhere;
 } ResultRelInfo;
 
+struct EState;
+
+/* ----------------
+ *	  Pre-execute callbacks
+ * ----------------
+ */
+typedef void (*PreExecCallback) (struct EState *estate, Node *node);
+typedef struct PreExecCallbackItem
+{
+	struct PreExecCallbackItem *next;
+	PreExecCallback callback;		/* function to call just before execution
+									 * starts */
+	Node *node;						/* node to process  */
+	void *arg;						/* any extra arguments */
+} PreExecCallbackItem;
+
+void RegisterPreExecCallback(PreExecCallback callback, struct EState *es,
+							 Node *nd, void *arg);
+void RunPreExecCallbacks(struct EState *es);
+
 /* ----------------
  *	  EState information
  *
@@ -387,6 +407,8 @@ typedef struct EState
 
 	List	   *es_rowMarks;	/* List of ExecRowMarks */
 
+	PreExecCallbackItem	 *es_preExecCallbacks; /* pre-exec callbacks */
+
 	uint32		es_processed;	/* # of tuples processed */
 	Oid			es_lastoid;		/* last oid processed (by INSERT) */
 
-- 
1.8.3.1

