diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 300dc5f3fa46be01bb33dbe17ec7d6c9bf49555a..e5f1b3130760c7bd44df7191f0e455409b077614 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.180 2008/10/06 20:29:38 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.181 2008/11/19 01:10:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -224,7 +224,6 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
 	QueryDesc  *queryDesc;
 	instr_time	starttime;
 	double		totaltime = 0;
-	ExplainState *es;
 	StringInfoData buf;
 	int			eflags;
 
@@ -265,17 +264,9 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
 		totaltime += elapsed_time(&starttime);
 	}
 
-	es = (ExplainState *) palloc0(sizeof(ExplainState));
-
-	es->printTList = stmt->verbose;
-	es->printAnalyze = stmt->analyze;
-	es->pstmt = queryDesc->plannedstmt;
-	es->rtable = queryDesc->plannedstmt->rtable;
-
+	/* Create textual dump of plan tree */
 	initStringInfo(&buf);
-	explain_outNode(&buf,
-					queryDesc->plannedstmt->planTree, queryDesc->planstate,
-					NULL, 0, es);
+	ExplainPrintPlan(&buf, queryDesc, stmt->analyze, stmt->verbose);
 
 	/*
 	 * If we ran the command, run any AFTER triggers it queued.  (Note this
@@ -290,7 +281,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
 	}
 
 	/* Print info about runtime of triggers */
-	if (es->printAnalyze)
+	if (stmt->analyze)
 	{
 		ResultRelInfo *rInfo;
 		bool		show_relname;
@@ -335,7 +326,34 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
 	do_text_output_multiline(tstate, buf.data);
 
 	pfree(buf.data);
-	pfree(es);
+}
+
+/*
+ * ExplainPrintPlan -
+ *	  convert a QueryDesc's plan tree to text and append it to 'str'
+ *
+ * 'analyze' means to include runtime instrumentation results
+ * 'verbose' means a verbose printout (currently, it shows targetlists)
+ *
+ * NB: will not work on utility statements
+ */
+void
+ExplainPrintPlan(StringInfo str, QueryDesc *queryDesc,
+				 bool analyze, bool verbose)
+{
+	ExplainState	es;
+
+	Assert(queryDesc->plannedstmt != NULL);
+
+	memset(&es, 0, sizeof(es));
+	es.printTList = verbose;
+	es.printAnalyze = analyze;
+	es.pstmt = queryDesc->plannedstmt;
+	es.rtable = queryDesc->plannedstmt->rtable;
+
+	explain_outNode(str,
+					queryDesc->plannedstmt->planTree, queryDesc->planstate,
+					NULL, 0, &es);
 }
 
 /*
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 6d389319fcc87f911a7160ecdbf6736368362034..f63ea4e9ebad1030aab932700f9f72e8c68679a8 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.317 2008/11/16 17:34:28 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.318 2008/11/19 01:10:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -60,8 +60,10 @@
 #include "utils/tqual.h"
 
 
-/* Hook for plugins to get control in ExecutorRun() */
-ExecutorRun_hook_type ExecutorRun_hook = NULL;
+/* Hooks for plugins to get control in ExecutorStart/Run/End() */
+ExecutorStart_hook_type	ExecutorStart_hook = NULL;
+ExecutorRun_hook_type	ExecutorRun_hook = NULL;
+ExecutorEnd_hook_type	ExecutorEnd_hook = NULL;
 
 typedef struct evalPlanQual
 {
@@ -129,10 +131,24 @@ static void intorel_destroy(DestReceiver *self);
  *
  * NB: the CurrentMemoryContext when this is called will become the parent
  * of the per-query context used for this Executor invocation.
+ *
+ * We provide a function hook variable that lets loadable plugins
+ * get control when ExecutorStart is called.  Such a plugin would
+ * normally call standard_ExecutorStart().
+ *
  * ----------------------------------------------------------------
  */
 void
 ExecutorStart(QueryDesc *queryDesc, int eflags)
+{
+	if (ExecutorStart_hook)
+		(*ExecutorStart_hook) (queryDesc, eflags);
+	else
+		standard_ExecutorStart(queryDesc, eflags);
+}
+
+void
+standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
 {
 	EState	   *estate;
 	MemoryContext oldcontext;
@@ -263,6 +279,10 @@ standard_ExecutorRun(QueryDesc *queryDesc,
 	 */
 	oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
 
+	/* Allow instrumentation of ExecutorRun overall runtime */
+	if (queryDesc->totaltime)
+		InstrStartNode(queryDesc->totaltime);
+
 	/*
 	 * extract information from the query descriptor and the query feature.
 	 */
@@ -298,6 +318,9 @@ standard_ExecutorRun(QueryDesc *queryDesc,
 	if (sendTuples)
 		(*dest->rShutdown) (dest);
 
+	if (queryDesc->totaltime)
+		InstrStopNode(queryDesc->totaltime, estate->es_processed);
+
 	MemoryContextSwitchTo(oldcontext);
 }
 
@@ -306,10 +329,24 @@ standard_ExecutorRun(QueryDesc *queryDesc,
  *
  *		This routine must be called at the end of execution of any
  *		query plan
+ *
+ *		We provide a function hook variable that lets loadable plugins
+ *		get control when ExecutorEnd is called.  Such a plugin would
+ *		normally call standard_ExecutorEnd().
+ *
  * ----------------------------------------------------------------
  */
 void
 ExecutorEnd(QueryDesc *queryDesc)
+{
+	if (ExecutorEnd_hook)
+		(*ExecutorEnd_hook) (queryDesc);
+	else
+		standard_ExecutorEnd(queryDesc);
+}
+
+void
+standard_ExecutorEnd(QueryDesc *queryDesc)
 {
 	EState	   *estate;
 	MemoryContext oldcontext;
@@ -353,6 +390,7 @@ ExecutorEnd(QueryDesc *queryDesc)
 	queryDesc->tupDesc = NULL;
 	queryDesc->estate = NULL;
 	queryDesc->planstate = NULL;
+	queryDesc->totaltime = NULL;
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index c13f0cda7e7656ee148e79afe62aa1f15984aff7..f382c737214c6c3a0287e1c0c87e18d5e7ddfdee 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.124 2008/08/01 13:16:09 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.125 2008/11/19 01:10:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -82,6 +82,7 @@ CreateQueryDesc(PlannedStmt *plannedstmt,
 	qd->tupDesc = NULL;
 	qd->estate = NULL;
 	qd->planstate = NULL;
+	qd->totaltime = NULL;
 
 	return qd;
 }
@@ -110,6 +111,7 @@ CreateUtilityQueryDesc(Node *utilitystmt,
 	qd->tupDesc = NULL;
 	qd->estate = NULL;
 	qd->planstate = NULL;
+	qd->totaltime = NULL;
 
 	return qd;
 }
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 143003f384445450509af35d43c3cc88baeee61c..3e967527bfe2f05ba50f2195ad6ee695d0803fed 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.477 2008/11/11 02:42:32 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.478 2008/11/19 01:10:23 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -2687,6 +2687,7 @@ static int	GUCNestLevel = 0;	/* 1 when in main transaction */
 
 static int	guc_var_compare(const void *a, const void *b);
 static int	guc_name_compare(const char *namea, const char *nameb);
+static void InitializeOneGUCOption(struct config_generic *gconf);
 static void push_old_value(struct config_generic * gconf, GucAction action);
 static void ReportGUCOption(struct config_generic * record);
 static void ShowGUCConfigOption(const char *name, DestReceiver *dest);
@@ -3194,113 +3195,7 @@ InitializeGUCOptions(void)
 	 */
 	for (i = 0; i < num_guc_variables; i++)
 	{
-		struct config_generic *gconf = guc_variables[i];
-
-		gconf->status = 0;
-		gconf->reset_source = PGC_S_DEFAULT;
-		gconf->source = PGC_S_DEFAULT;
-		gconf->stack = NULL;
-		gconf->sourcefile = NULL;
-		gconf->sourceline = 0;
-
-		switch (gconf->vartype)
-		{
-			case PGC_BOOL:
-				{
-					struct config_bool *conf = (struct config_bool *) gconf;
-
-					if (conf->assign_hook)
-						if (!(*conf->assign_hook) (conf->boot_val, true,
-												   PGC_S_DEFAULT))
-							elog(FATAL, "failed to initialize %s to %d",
-								 conf->gen.name, (int) conf->boot_val);
-					*conf->variable = conf->reset_val = conf->boot_val;
-					break;
-				}
-			case PGC_INT:
-				{
-					struct config_int *conf = (struct config_int *) gconf;
-
-					Assert(conf->boot_val >= conf->min);
-					Assert(conf->boot_val <= conf->max);
-					if (conf->assign_hook)
-						if (!(*conf->assign_hook) (conf->boot_val, true,
-												   PGC_S_DEFAULT))
-							elog(FATAL, "failed to initialize %s to %d",
-								 conf->gen.name, conf->boot_val);
-					*conf->variable = conf->reset_val = conf->boot_val;
-					break;
-				}
-			case PGC_REAL:
-				{
-					struct config_real *conf = (struct config_real *) gconf;
-
-					Assert(conf->boot_val >= conf->min);
-					Assert(conf->boot_val <= conf->max);
-					if (conf->assign_hook)
-						if (!(*conf->assign_hook) (conf->boot_val, true,
-												   PGC_S_DEFAULT))
-							elog(FATAL, "failed to initialize %s to %g",
-								 conf->gen.name, conf->boot_val);
-					*conf->variable = conf->reset_val = conf->boot_val;
-					break;
-				}
-			case PGC_STRING:
-				{
-					struct config_string *conf = (struct config_string *) gconf;
-					char	   *str;
-
-					*conf->variable = NULL;
-					conf->reset_val = NULL;
-
-					if (conf->boot_val == NULL)
-					{
-						/* leave the value NULL, do not call assign hook */
-						break;
-					}
-
-					str = guc_strdup(FATAL, conf->boot_val);
-					conf->reset_val = str;
-
-					if (conf->assign_hook)
-					{
-						const char *newstr;
-
-						newstr = (*conf->assign_hook) (str, true,
-													   PGC_S_DEFAULT);
-						if (newstr == NULL)
-						{
-							elog(FATAL, "failed to initialize %s to \"%s\"",
-								 conf->gen.name, str);
-						}
-						else if (newstr != str)
-						{
-							free(str);
-
-							/*
-							 * See notes in set_config_option about casting
-							 */
-							str = (char *) newstr;
-							conf->reset_val = str;
-						}
-					}
-					*conf->variable = str;
-					break;
-				}
-			case PGC_ENUM:
-				{
-					struct config_enum *conf = (struct config_enum *) gconf;
-
-					if (conf->assign_hook)
-						if (!(*conf->assign_hook) (conf->boot_val, true,
-												   PGC_S_DEFAULT))
-							elog(FATAL, "failed to initialize %s to %s",
-								 conf->gen.name, 
-								 config_enum_lookup_by_value(conf, conf->boot_val));
-					*conf->variable = conf->reset_val = conf->boot_val;
-					break;
-				}
-		}
+		InitializeOneGUCOption(guc_variables[i]);
 	}
 
 	guc_dirty = false;
@@ -3356,6 +3251,119 @@ InitializeGUCOptions(void)
 	}
 }
 
+/*
+ * Initialize one GUC option variable to its compiled-in default.
+ */
+static void
+InitializeOneGUCOption(struct config_generic *gconf)
+{
+	gconf->status = 0;
+	gconf->reset_source = PGC_S_DEFAULT;
+	gconf->source = PGC_S_DEFAULT;
+	gconf->stack = NULL;
+	gconf->sourcefile = NULL;
+	gconf->sourceline = 0;
+
+	switch (gconf->vartype)
+	{
+		case PGC_BOOL:
+		{
+			struct config_bool *conf = (struct config_bool *) gconf;
+
+			if (conf->assign_hook)
+				if (!(*conf->assign_hook) (conf->boot_val, true,
+										   PGC_S_DEFAULT))
+					elog(FATAL, "failed to initialize %s to %d",
+						 conf->gen.name, (int) conf->boot_val);
+			*conf->variable = conf->reset_val = conf->boot_val;
+			break;
+		}
+		case PGC_INT:
+		{
+			struct config_int *conf = (struct config_int *) gconf;
+
+			Assert(conf->boot_val >= conf->min);
+			Assert(conf->boot_val <= conf->max);
+			if (conf->assign_hook)
+				if (!(*conf->assign_hook) (conf->boot_val, true,
+										   PGC_S_DEFAULT))
+					elog(FATAL, "failed to initialize %s to %d",
+						 conf->gen.name, conf->boot_val);
+			*conf->variable = conf->reset_val = conf->boot_val;
+			break;
+		}
+		case PGC_REAL:
+		{
+			struct config_real *conf = (struct config_real *) gconf;
+
+			Assert(conf->boot_val >= conf->min);
+			Assert(conf->boot_val <= conf->max);
+			if (conf->assign_hook)
+				if (!(*conf->assign_hook) (conf->boot_val, true,
+										   PGC_S_DEFAULT))
+					elog(FATAL, "failed to initialize %s to %g",
+						 conf->gen.name, conf->boot_val);
+			*conf->variable = conf->reset_val = conf->boot_val;
+			break;
+		}
+		case PGC_STRING:
+		{
+			struct config_string *conf = (struct config_string *) gconf;
+			char	   *str;
+
+			*conf->variable = NULL;
+			conf->reset_val = NULL;
+
+			if (conf->boot_val == NULL)
+			{
+				/* leave the value NULL, do not call assign hook */
+				break;
+			}
+
+			str = guc_strdup(FATAL, conf->boot_val);
+			conf->reset_val = str;
+
+			if (conf->assign_hook)
+			{
+				const char *newstr;
+
+				newstr = (*conf->assign_hook) (str, true,
+											   PGC_S_DEFAULT);
+				if (newstr == NULL)
+				{
+					elog(FATAL, "failed to initialize %s to \"%s\"",
+						 conf->gen.name, str);
+				}
+				else if (newstr != str)
+				{
+					free(str);
+
+					/*
+					 * See notes in set_config_option about casting
+					 */
+					str = (char *) newstr;
+					conf->reset_val = str;
+				}
+			}
+			*conf->variable = str;
+			break;
+		}
+		case PGC_ENUM:
+		{
+			struct config_enum *conf = (struct config_enum *) gconf;
+
+			if (conf->assign_hook)
+				if (!(*conf->assign_hook) (conf->boot_val, true,
+										   PGC_S_DEFAULT))
+					elog(FATAL, "failed to initialize %s to %s",
+						 conf->gen.name, 
+						 config_enum_lookup_by_value(conf, conf->boot_val));
+			*conf->variable = conf->reset_val = conf->boot_val;
+			break;
+		}
+	}
+}
+
 
 /*
  * Select the configuration files and data directory to be used, and
@@ -5618,6 +5626,7 @@ init_custom_variable(const char *name,
 					 const char *short_desc,
 					 const char *long_desc,
 					 GucContext context,
+					 int flags,
 					 enum config_type type,
 					 size_t sz)
 {
@@ -5631,6 +5640,7 @@ init_custom_variable(const char *name,
 	gen->group = CUSTOM_OPTIONS;
 	gen->short_desc = short_desc;
 	gen->long_desc = long_desc;
+	gen->flags = flags;
 	gen->vartype = type;
 
 	return gen;
@@ -5649,6 +5659,9 @@ define_custom_variable(struct config_generic * variable)
 	struct config_string *pHolder;
 	struct config_generic **res;
 
+	/*
+	 * See if there's a placeholder by the same name.
+	 */
 	res = (struct config_generic **) bsearch((void *) &nameAddr,
 											 (void *) guc_variables,
 											 num_guc_variables,
@@ -5656,7 +5669,11 @@ define_custom_variable(struct config_generic * variable)
 											 guc_var_compare);
 	if (res == NULL)
 	{
-		/* No placeholder to replace, so just add it */
+		/*
+		 * No placeholder to replace, so we can just add it ... but first,
+		 * make sure it's initialized to its default value.
+		 */
+		InitializeOneGUCOption(variable);
 		add_guc_variable(variable, ERROR);
 		return;
 	}
@@ -5672,6 +5689,13 @@ define_custom_variable(struct config_generic * variable)
 	Assert((*res)->vartype == PGC_STRING);
 	pHolder = (struct config_string *) (*res);
 
+	/*
+	 * First, set the variable to its default value.  We must do this even
+	 * though we intend to immediately apply a new value, since it's possible
+	 * that the new value is invalid.
+	 */
+	InitializeOneGUCOption(variable);
+
 	/*
 	 * Replace the placeholder. We aren't changing the name, so no re-sorting
 	 * is necessary
@@ -5683,7 +5707,7 @@ define_custom_variable(struct config_generic * variable)
 	 *
 	 * XXX this is not really good enough --- it should be a nontransactional
 	 * assignment, since we don't want it to roll back if the current xact
-	 * fails later.
+	 * fails later.  (Or do we?)
 	 */
 	value = *pHolder->variable;
 
@@ -5707,18 +5731,20 @@ DefineCustomBoolVariable(const char *name,
 						 const char *short_desc,
 						 const char *long_desc,
 						 bool *valueAddr,
+						 bool bootValue,
 						 GucContext context,
+						 int flags,
 						 GucBoolAssignHook assign_hook,
 						 GucShowHook show_hook)
 {
 	struct config_bool *var;
 
 	var = (struct config_bool *)
-		init_custom_variable(name, short_desc, long_desc, context,
+		init_custom_variable(name, short_desc, long_desc, context, flags,
 							 PGC_BOOL, sizeof(struct config_bool));
 	var->variable = valueAddr;
-	var->boot_val = *valueAddr;
-	var->reset_val = *valueAddr;
+	var->boot_val = bootValue;
+	var->reset_val = bootValue;
 	var->assign_hook = assign_hook;
 	var->show_hook = show_hook;
 	define_custom_variable(&var->gen);
@@ -5729,20 +5755,22 @@ DefineCustomIntVariable(const char *name,
 						const char *short_desc,
 						const char *long_desc,
 						int *valueAddr,
+						int bootValue,
 						int minValue,
 						int maxValue,
 						GucContext context,
+						int flags,
 						GucIntAssignHook assign_hook,
 						GucShowHook show_hook)
 {
 	struct config_int *var;
 
 	var = (struct config_int *)
-		init_custom_variable(name, short_desc, long_desc, context,
+		init_custom_variable(name, short_desc, long_desc, context, flags,
 							 PGC_INT, sizeof(struct config_int));
 	var->variable = valueAddr;
-	var->boot_val = *valueAddr;
-	var->reset_val = *valueAddr;
+	var->boot_val = bootValue;
+	var->reset_val = bootValue;
 	var->min = minValue;
 	var->max = maxValue;
 	var->assign_hook = assign_hook;
@@ -5755,20 +5783,22 @@ DefineCustomRealVariable(const char *name,
 						 const char *short_desc,
 						 const char *long_desc,
 						 double *valueAddr,
+						 double bootValue,
 						 double minValue,
 						 double maxValue,
 						 GucContext context,
+						 int flags,
 						 GucRealAssignHook assign_hook,
 						 GucShowHook show_hook)
 {
 	struct config_real *var;
 
 	var = (struct config_real *)
-		init_custom_variable(name, short_desc, long_desc, context,
+		init_custom_variable(name, short_desc, long_desc, context, flags,
 							 PGC_REAL, sizeof(struct config_real));
 	var->variable = valueAddr;
-	var->boot_val = *valueAddr;
-	var->reset_val = *valueAddr;
+	var->boot_val = bootValue;
+	var->reset_val = bootValue;
 	var->min = minValue;
 	var->max = maxValue;
 	var->assign_hook = assign_hook;
@@ -5781,17 +5811,19 @@ DefineCustomStringVariable(const char *name,
 						   const char *short_desc,
 						   const char *long_desc,
 						   char **valueAddr,
+						   const char *bootValue,
 						   GucContext context,
+						   int flags,
 						   GucStringAssignHook assign_hook,
 						   GucShowHook show_hook)
 {
 	struct config_string *var;
 
 	var = (struct config_string *)
-		init_custom_variable(name, short_desc, long_desc, context,
+		init_custom_variable(name, short_desc, long_desc, context, flags,
 							 PGC_STRING, sizeof(struct config_string));
 	var->variable = valueAddr;
-	var->boot_val = *valueAddr;
+	var->boot_val = bootValue;
 	/* we could probably do without strdup, but keep it like normal case */
 	if (var->boot_val)
 		var->reset_val = guc_strdup(ERROR, var->boot_val);
@@ -5805,19 +5837,21 @@ DefineCustomEnumVariable(const char *name,
 						 const char *short_desc,
 						 const char *long_desc,
 						 int *valueAddr,
+						 int bootValue,
 						 const struct config_enum_entry *options,
 						 GucContext context,
+						 int flags,
 						 GucEnumAssignHook assign_hook,
 						 GucShowHook show_hook)
 {
 	struct config_enum *var;
 
 	var = (struct config_enum *)
-		init_custom_variable(name, short_desc, long_desc, context,
+		init_custom_variable(name, short_desc, long_desc, context, flags,
 							 PGC_ENUM, sizeof(struct config_enum));
 	var->variable = valueAddr;
-	var->boot_val = *valueAddr;
-	var->reset_val = *valueAddr;
+	var->boot_val = bootValue;
+	var->reset_val = bootValue;
 	var->options = options;
 	var->assign_hook = assign_hook;
 	var->show_hook = show_hook;
diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h
index 1006f7193824cda6b0f9172e8503765728f500ce..ca7aefb3895e1ae2adcbd177d256f7cde34092a6 100644
--- a/src/include/commands/explain.h
+++ b/src/include/commands/explain.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/explain.h,v 1.35 2008/01/01 19:45:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/explain.h,v 1.36 2008/11/19 01:10:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -41,4 +41,7 @@ extern void ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
 extern void ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
 			   ExplainStmt *stmt, TupOutputState *tstate);
 
+extern void ExplainPrintPlan(StringInfo str, QueryDesc *queryDesc,
+							 bool analyze, bool verbose);
+
 #endif   /* EXPLAIN_H */
diff --git a/src/include/executor/execdesc.h b/src/include/executor/execdesc.h
index 4f386029874a7f8557b5971064e3ddb95da82d52..2ffccc783f433b9b8207667b850144446424979b 100644
--- a/src/include/executor/execdesc.h
+++ b/src/include/executor/execdesc.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/execdesc.h,v 1.37 2008/01/01 19:45:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/execdesc.h,v 1.38 2008/11/19 01:10:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,6 +47,9 @@ typedef struct QueryDesc
 	TupleDesc	tupDesc;		/* descriptor for result tuples */
 	EState	   *estate;			/* executor's query-wide state */
 	PlanState  *planstate;		/* tree of per-plan-node state */
+
+	/* This is always set NULL by the core system, but plugins can change it */
+	struct Instrumentation *totaltime;	/* total time spent in ExecutorRun */
 } QueryDesc;
 
 /* in pquery.c */
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 2fdaddda4dabe4c7dc1fd09834fca12b3af5e9bf..47792df10c96f0c2e0a41c6ba97da4a4c6d2a7ca 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.152 2008/10/31 21:07:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.153 2008/11/19 01:10:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -60,12 +60,20 @@
 	((*(expr)->evalfunc) (expr, econtext, isNull, isDone))
 
 
+/* Hook for plugins to get control in ExecutorStart() */
+typedef void (*ExecutorStart_hook_type) (QueryDesc *queryDesc, int eflags);
+extern PGDLLIMPORT ExecutorStart_hook_type ExecutorStart_hook;
+
 /* Hook for plugins to get control in ExecutorRun() */
 typedef void (*ExecutorRun_hook_type) (QueryDesc *queryDesc,
 									   ScanDirection direction,
 									   long count);
 extern PGDLLIMPORT ExecutorRun_hook_type ExecutorRun_hook;
 
+/* Hook for plugins to get control in ExecutorEnd() */
+typedef void (*ExecutorEnd_hook_type) (QueryDesc *queryDesc);
+extern PGDLLIMPORT ExecutorEnd_hook_type ExecutorEnd_hook;
+
 
 /*
  * prototypes from functions in execAmi.c
@@ -140,11 +148,13 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
  * prototypes from functions in execMain.c
  */
 extern void ExecutorStart(QueryDesc *queryDesc, int eflags);
+extern void standard_ExecutorStart(QueryDesc *queryDesc, int eflags);
 extern void ExecutorRun(QueryDesc *queryDesc,
 						ScanDirection direction, long count);
 extern void standard_ExecutorRun(QueryDesc *queryDesc,
 								 ScanDirection direction, long count);
 extern void ExecutorEnd(QueryDesc *queryDesc);
+extern void standard_ExecutorEnd(QueryDesc *queryDesc);
 extern void ExecutorRewind(QueryDesc *queryDesc);
 extern void InitResultRelInfo(ResultRelInfo *resultRelInfo,
 				  Relation resultRelationDesc,
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 87c383e1ebd34558e00ddeb0d05d9b3d33f9c1f2..e5066677b9f48b5791bbbe3a025869fcdf118e98 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -7,7 +7,7 @@
  * Copyright (c) 2000-2008, PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
- * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.98 2008/07/23 17:29:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.99 2008/11/19 01:10:23 tgl Exp $
  *--------------------------------------------------------------------
  */
 #ifndef GUC_H
@@ -122,6 +122,30 @@ typedef enum
 
 #define GUC_QUALIFIER_SEPARATOR '.'
 
+/*
+ * bit values in "flags" of a GUC variable
+ */
+#define GUC_LIST_INPUT			0x0001	/* input can be list format */
+#define GUC_LIST_QUOTE			0x0002	/* double-quote list elements */
+#define GUC_NO_SHOW_ALL			0x0004	/* exclude from SHOW ALL */
+#define GUC_NO_RESET_ALL		0x0008	/* exclude from RESET ALL */
+#define GUC_REPORT				0x0010	/* auto-report changes to client */
+#define GUC_NOT_IN_SAMPLE		0x0020	/* not in postgresql.conf.sample */
+#define GUC_DISALLOW_IN_FILE	0x0040	/* can't set in postgresql.conf */
+#define GUC_CUSTOM_PLACEHOLDER	0x0080	/* placeholder for custom variable */
+#define GUC_SUPERUSER_ONLY		0x0100	/* show only to superusers */
+#define GUC_IS_NAME				0x0200	/* limit string to NAMEDATALEN-1 */
+
+#define GUC_UNIT_KB				0x0400	/* value is in kilobytes */
+#define GUC_UNIT_BLOCKS			0x0800	/* value is in blocks */
+#define GUC_UNIT_XBLOCKS		0x0C00	/* value is in xlog blocks */
+#define GUC_UNIT_MEMORY			0x0C00	/* mask for KB, BLOCKS, XBLOCKS */
+
+#define GUC_UNIT_MS				0x1000	/* value is in milliseconds */
+#define GUC_UNIT_S				0x2000	/* value is in seconds */
+#define GUC_UNIT_MIN			0x4000	/* value is in minutes */
+#define GUC_UNIT_TIME			0x7000	/* mask for MS, S, MIN */
+
 /* GUC vars that are actually declared in guc.c, rather than elsewhere */
 extern bool log_duration;
 extern bool Debug_print_plan;
@@ -164,7 +188,9 @@ extern void DefineCustomBoolVariable(
 						 const char *short_desc,
 						 const char *long_desc,
 						 bool *valueAddr,
+						 bool bootValue,
 						 GucContext context,
+						 int flags,
 						 GucBoolAssignHook assign_hook,
 						 GucShowHook show_hook);
 
@@ -173,9 +199,11 @@ extern void DefineCustomIntVariable(
 						const char *short_desc,
 						const char *long_desc,
 						int *valueAddr,
+						int bootValue,
 						int minValue,
 						int maxValue,
 						GucContext context,
+						int flags,
 						GucIntAssignHook assign_hook,
 						GucShowHook show_hook);
 
@@ -184,9 +212,11 @@ extern void DefineCustomRealVariable(
 						 const char *short_desc,
 						 const char *long_desc,
 						 double *valueAddr,
+						 double bootValue,
 						 double minValue,
 						 double maxValue,
 						 GucContext context,
+						 int flags,
 						 GucRealAssignHook assign_hook,
 						 GucShowHook show_hook);
 
@@ -195,7 +225,9 @@ extern void DefineCustomStringVariable(
 						   const char *short_desc,
 						   const char *long_desc,
 						   char **valueAddr,
+						   const char *bootValue,
 						   GucContext context,
+						   int flags,
 						   GucStringAssignHook assign_hook,
 						   GucShowHook show_hook);
 
@@ -204,8 +236,10 @@ extern void DefineCustomEnumVariable(
 						   const char *short_desc,
 						   const char *long_desc,
 						   int *valueAddr,
+						   int bootValue,
 						   const struct config_enum_entry *options,
 						   GucContext context,
+						   int flags,
 						   GucEnumAssignHook assign_hook,
 						   GucShowHook show_hook);
 
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 0eca0f54a3b8c3d6e24c9c8bd2ec37579a4be348..338fb27f4ce053897b1f06d47680215a5f694d29 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -7,7 +7,7 @@
  *
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  *
- *	  $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.43 2008/09/30 10:52:14 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.44 2008/11/19 01:10:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -129,27 +129,7 @@ struct config_generic
 	int			sourceline;		/* line in source file */
 };
 
-/* bit values in flags field */
-#define GUC_LIST_INPUT			0x0001	/* input can be list format */
-#define GUC_LIST_QUOTE			0x0002	/* double-quote list elements */
-#define GUC_NO_SHOW_ALL			0x0004	/* exclude from SHOW ALL */
-#define GUC_NO_RESET_ALL		0x0008	/* exclude from RESET ALL */
-#define GUC_REPORT				0x0010	/* auto-report changes to client */
-#define GUC_NOT_IN_SAMPLE		0x0020	/* not in postgresql.conf.sample */
-#define GUC_DISALLOW_IN_FILE	0x0040	/* can't set in postgresql.conf */
-#define GUC_CUSTOM_PLACEHOLDER	0x0080	/* placeholder for custom variable */
-#define GUC_SUPERUSER_ONLY		0x0100	/* show only to superusers */
-#define GUC_IS_NAME				0x0200	/* limit string to NAMEDATALEN-1 */
-
-#define GUC_UNIT_KB				0x0400	/* value is in kilobytes */
-#define GUC_UNIT_BLOCKS			0x0800	/* value is in blocks */
-#define GUC_UNIT_XBLOCKS		0x0C00	/* value is in xlog blocks */
-#define GUC_UNIT_MEMORY			0x0C00	/* mask for KB, BLOCKS, XBLOCKS */
-
-#define GUC_UNIT_MS				0x1000	/* value is in milliseconds */
-#define GUC_UNIT_S				0x2000	/* value is in seconds */
-#define GUC_UNIT_MIN			0x4000	/* value is in minutes */
-#define GUC_UNIT_TIME			0x7000	/* mask for MS, S, MIN */
+/* bit values in flags field are defined in guc.h */
 
 /* bit values in status field */
 #define GUC_IS_IN_FILE		0x0001		/* found it in config file */
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 75eaf10134c2b9deffbc85f8fd18b5bc1afb49a4..a221b92a2f1a9697864ab90c3eeeba7afec727d3 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plperl.c - perl as a procedural language for PostgreSQL
  *
- *	  $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.141 2008/10/29 00:00:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.142 2008/11/19 01:10:24 tgl Exp $
  *
  **********************************************************************/
 
@@ -196,7 +196,8 @@ _PG_init(void)
 	  gettext_noop("If true, will compile trusted and untrusted perl code in strict mode"),
 							 NULL,
 							 &plperl_use_strict,
-							 PGC_USERSET,
+							 false,
+							 PGC_USERSET, 0,
 							 NULL, NULL);
 
 	EmitWarningsOnPlaceholders("plperl");