Index: src/backend/executor/execMain.c
===================================================================
--- src/backend/executor/execMain.c	(HEAD)
+++ src/backend/executor/execMain.c	(working copy)
@@ -67,14 +67,12 @@
 	struct evalPlanQual *free;	/* list of free PlanQual plans */
 } evalPlanQual;
 
+/* Hook for plugins to get control in ExecutorRun() */
+executor_hook_type executor_hook = NULL;
+
 /* decls for local routines only used within this module */
 static void InitPlan(QueryDesc *queryDesc, int eflags);
 static void ExecEndPlan(PlanState *planstate, EState *estate);
-static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
-			CmdType operation,
-			long numberTuples,
-			ScanDirection direction,
-			DestReceiver *dest);
 static void ExecSelect(TupleTableSlot *slot,
 		   DestReceiver *dest, EState *estate);
 static void ExecInsert(TupleTableSlot *slot, ItemPointer tupleid,
@@ -262,6 +260,8 @@
 	 */
 	if (ScanDirectionIsNoMovement(direction))
 		result = NULL;
+	else if (executor_hook)
+		result = executor_hook(queryDesc, direction, count);
 	else
 		result = ExecutePlan(estate,
 							 queryDesc->planstate,
@@ -1182,7 +1182,7 @@
  * user can see it
  * ----------------------------------------------------------------
  */
-static TupleTableSlot *
+TupleTableSlot *
 ExecutePlan(EState *estate,
 			PlanState *planstate,
 			CmdType operation,
Index: src/backend/nodes/copyfuncs.c
===================================================================
--- src/backend/nodes/copyfuncs.c	(HEAD)
+++ src/backend/nodes/copyfuncs.c	(working copy)
@@ -85,6 +85,7 @@
 	COPY_NODE_FIELD(rowMarks);
 	COPY_NODE_FIELD(relationOids);
 	COPY_SCALAR_FIELD(nParamExec);
+	COPY_SCALAR_FIELD(tag);
 
 	return newnode;
 }
Index: src/backend/nodes/outfuncs.c
===================================================================
--- src/backend/nodes/outfuncs.c	(HEAD)
+++ src/backend/nodes/outfuncs.c	(working copy)
@@ -252,6 +252,7 @@
 	WRITE_NODE_FIELD(rowMarks);
 	WRITE_NODE_FIELD(relationOids);
 	WRITE_INT_FIELD(nParamExec);
+	WRITE_INT_FIELD(tag);
 }
 
 /*
Index: src/include/executor/executor.h
===================================================================
--- src/include/executor/executor.h	(HEAD)
+++ src/include/executor/executor.h	(working copy)
@@ -138,6 +138,11 @@
 			ScanDirection direction, long count);
 extern void ExecutorEnd(QueryDesc *queryDesc);
 extern void ExecutorRewind(QueryDesc *queryDesc);
+extern TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
+			CmdType operation,
+			long numberTuples,
+			ScanDirection direction,
+			DestReceiver *dest);
 extern void InitResultRelInfo(ResultRelInfo *resultRelInfo,
 				  Relation resultRelationDesc,
 				  Index resultRelationIndex,
@@ -152,6 +157,11 @@
 extern PlanState *ExecGetActivePlanTree(QueryDesc *queryDesc);
 extern DestReceiver *CreateIntoRelDestReceiver(void);
 
+/* Hook for plugins to get control in ExecutorRun() */
+typedef TupleTableSlot *(*executor_hook_type) (QueryDesc *queryDesc,
+			ScanDirection direction, long count);
+extern PGDLLIMPORT executor_hook_type executor_hook;
+
 /*
  * prototypes from functions in execProcnode.c
  */
Index: src/include/nodes/plannodes.h
===================================================================
--- src/include/nodes/plannodes.h	(HEAD)
+++ src/include/nodes/plannodes.h	(working copy)
@@ -73,6 +73,8 @@
 	List	   *relationOids;	/* OIDs of relations the plan depends on */
 
 	int			nParamExec;		/* number of PARAM_EXEC Params used */
+
+	uint32		tag;			/* plan tag */
 } PlannedStmt;
 
 /* macro for fetching the Plan associated with a SubPlan node */
