diff -cprN HEAD/contrib/Makefile auto-explain/contrib/Makefile
*** HEAD/contrib/Makefile	Wed Jul 30 03:31:20 2008
--- auto-explain/contrib/Makefile	Mon Nov 10 17:55:49 2008
*************** include $(top_builddir)/src/Makefile.glo
*** 6,11 ****
--- 6,12 ----
  
  WANTED_DIRS = \
  		adminpack	\
+ 		auto_explain	\
  		btree_gist	\
  		chkpass		\
  		citext		\
diff -cprN HEAD/contrib/auto_explain/Makefile auto-explain/contrib/auto_explain/Makefile
*** HEAD/contrib/auto_explain/Makefile	Thu Jan  1 09:00:00 1970
--- auto-explain/contrib/auto_explain/Makefile	Mon Nov 10 17:29:01 2008
***************
*** 0 ****
--- 1,13 ----
+ MODULE_big = auto_explain
+ OBJS = auto_explain.o
+ 
+ ifdef USE_PGXS
+ PG_CONFIG = pg_config
+ PGXS := $(shell $(PG_CONFIG) --pgxs)
+ include $(PGXS)
+ else
+ subdir = contrib/auto_explain
+ top_builddir = ../..
+ include $(top_builddir)/src/Makefile.global
+ include $(top_srcdir)/contrib/contrib-global.mk
+ endif
diff -cprN HEAD/contrib/auto_explain/auto_explain.c auto-explain/contrib/auto_explain/auto_explain.c
*** HEAD/contrib/auto_explain/auto_explain.c	Thu Jan  1 09:00:00 1970
--- auto-explain/contrib/auto_explain/auto_explain.c	Mon Nov 10 17:52:03 2008
***************
*** 0 ****
--- 1,215 ----
+ /*
+  * auto_explain.c
+  */
+ #include "postgres.h"
+ 
+ #include "commands/explain.h"
+ #include "executor/instrument.h"
+ #include "miscadmin.h"
+ #include "utils/guc_tables.h"
+ 
+ PG_MODULE_MAGIC;
+ 
+ #define GUCNAME(name)		("explain." name)
+ 
+ static int		explain_log_min_duration = -1;	/* msec or -1 */
+ static bool		explain_log_analyze = false;
+ static bool		explain_log_verbose = false;
+ static bool		explain_log_nested = false;
+ 
+ static bool		toplevel = true;
+ static ExecutorRun_hook_type	prev_ExecutorRun = NULL;
+ 
+ void	_PG_init(void);
+ void	_PG_fini(void);
+ 
+ static void explain_ExecutorRun(QueryDesc *queryDesc,
+ 								ScanDirection direction,
+ 								long count);
+ static bool assign_log_min_duration(int newval, bool doit, GucSource source);
+ static bool assign_log_analyze(bool newval, bool doit, GucSource source);
+ static bool assign_log_verbose(bool newval, bool doit, GucSource source);
+ static bool assign_log_nested(bool newval, bool doit, GucSource source);
+ 
+ static struct config_int def_log_min_duration =
+ {
+ 	{
+ 		GUCNAME("log_min_duration"),
+ 		PGC_USERSET,
+ 		STATS_MONITORING,
+ 		"Sets the minimum execution time above which plans will be logged.",
+ 		"Zero prints all plans. -1 turns this feature off.",
+ 		GUC_UNIT_MS
+ 	},
+ 	&explain_log_min_duration,
+ 	-1, -1, INT_MAX / 1000, assign_log_min_duration, NULL
+ };
+ 
+ static struct config_bool def_log_analyze =
+ {
+ 	{
+ 		GUCNAME("log_analyze"),
+ 		PGC_USERSET,
+ 		STATS_MONITORING,
+ 		"Use EXPLAIN ANALYZE for plan logging."
+ 	},
+ 	&explain_log_analyze,
+ 	false, assign_log_analyze, NULL
+ };
+ 
+ static struct config_bool def_log_verbose =
+ {
+ 	{
+ 		GUCNAME("log_verbose"),
+ 		PGC_USERSET,
+ 		STATS_MONITORING,
+ 		"Use EXPLAIN VERBOSE for plan logging."
+ 	},
+ 	&explain_log_verbose,
+ 	false, assign_log_verbose, NULL
+ };
+ 
+ static struct config_bool def_log_nested_statements =
+ {
+ 	{
+ 		GUCNAME("log_nested_statements"),
+ 		PGC_USERSET,
+ 		STATS_MONITORING,
+ 		"Log nested statements."
+ 	},
+ 	&explain_log_nested,
+ 	false, assign_log_nested, NULL
+ };
+ 
+ void
+ _PG_init(void)
+ {
+ 	DefineCustomVariable(PGC_INT, &def_log_min_duration);
+ 	DefineCustomVariable(PGC_BOOL, &def_log_analyze);
+ 	DefineCustomVariable(PGC_BOOL, &def_log_verbose);
+ 	DefineCustomVariable(PGC_BOOL, &def_log_nested_statements);
+ 
+ 	/* install ExecutorRun_hook */
+ 	prev_ExecutorRun = ExecutorRun_hook;
+ 	ExecutorRun_hook = explain_ExecutorRun;
+ }
+ 
+ void
+ _PG_fini(void)
+ {
+ 	/* uninstall ExecutorRun_hook */
+ 	ExecutorRun_hook = prev_ExecutorRun;
+ }
+ 
+ void
+ explain_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, long count)
+ {
+ 	if ((toplevel || explain_log_nested) && explain_log_min_duration >= 0)
+ 	{
+ 		instr_time		starttime;
+ 		instr_time		duration;
+ 		double			msec;
+ 
+ 		/* Disable our hooks temporarily during the top-level query. */
+ 		toplevel = false;
+ 		PG_TRY();
+ 		{
+ 			INSTR_TIME_SET_CURRENT(starttime);
+ 
+ 			if (prev_ExecutorRun)
+ 				prev_ExecutorRun(queryDesc, direction, count);
+ 			else
+ 				standard_ExecutorRun(queryDesc, direction, count);
+ 
+ 			INSTR_TIME_SET_CURRENT(duration);
+ 			INSTR_TIME_SUBTRACT(duration, starttime);
+ 			msec = INSTR_TIME_GET_MILLISEC(duration);
+ 
+ 			/* Log plan if duration is exceeded. */
+ 			if (msec > explain_log_min_duration)
+ 			{
+ 				StringInfoData	buf;
+ 
+ 				initStringInfo(&buf);
+ 				ExplainOneResult(&buf, queryDesc,
+ 					queryDesc->doInstrument && explain_log_analyze,
+ 					explain_log_verbose);
+ 
+ 				/* Remove last line break */
+ 				if (buf.len > 0 && buf.data[buf.len - 1] == '\n')
+ 				{
+ 					buf.data[buf.len - 1] = '\0';
+ 					buf.len--;
+ 				}
+ 				ereport(LOG,
+ 						(errmsg("duration: %.3f ms  plan:\n%s",
+ 								msec, buf.data)));
+ 
+ 				pfree(buf.data);
+ 			}
+ 
+ 			toplevel = true;
+ 		}
+ 		PG_CATCH();
+ 		{
+ 			toplevel = true;
+ 			PG_RE_THROW();
+ 		}
+ 		PG_END_TRY();
+ 	}
+ 	else
+ 	{
+ 		/* ignore recursive executions, that are typically function calls */
+ 		if (prev_ExecutorRun)
+ 			prev_ExecutorRun(queryDesc, direction, count);
+ 		else
+ 			standard_ExecutorRun(queryDesc, direction, count);
+ 	}
+ }
+ 
+ /* Emulate PGC_SUSET for custom variables. */
+ static bool
+ suset_assign(GucSource source, const char *name)
+ {
+ 	if (source >= PGC_S_CLIENT && !superuser())
+ 	{
+ 		ereport(GUC_complaint_elevel(source),
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 				 errmsg("permission denied to set parameter \"%s\"", name)));
+ 		return false;
+ 	}
+ 
+ 	return true;
+ }
+ 
+ static bool
+ assign_log_min_duration(int newval, bool doit, GucSource source)
+ {
+ 	if (!suset_assign(source, GUCNAME("log_min_duration")))
+ 		return false;
+ 	if (doit)
+ 		force_instrument = (newval >= 0 && explain_log_analyze);
+ 	return true;
+ }
+ 
+ static bool
+ assign_log_analyze(bool newval, bool doit, GucSource source)
+ {
+ 	if (!suset_assign(source, GUCNAME("log_analyze")))
+ 		return false;
+ 	if (doit)
+ 		force_instrument = (explain_log_min_duration >= 0 && newval);
+ 	return true;
+ }
+ 
+ static bool
+ assign_log_verbose(bool newval, bool doit, GucSource source)
+ {
+ 	return suset_assign(source, GUCNAME("log_verbose"));
+ }
+ 
+ static bool
+ assign_log_nested(bool newval, bool doit, GucSource source)
+ {
+ 	return suset_assign(source, GUCNAME("log_nested_statements"));
+ }
diff -cprN HEAD/doc/src/sgml/auto-explain.sgml auto-explain/doc/src/sgml/auto-explain.sgml
*** HEAD/doc/src/sgml/auto-explain.sgml	Thu Jan  1 09:00:00 1970
--- auto-explain/doc/src/sgml/auto-explain.sgml	Mon Nov 10 17:43:33 2008
***************
*** 0 ****
--- 1,150 ----
+ <sect1 id="autoexplain">
+  <title>auto_explain</title>
+ 
+  <indexterm zone="autoexplain">
+   <primary>auto_explain</primary>
+  </indexterm>
+ 
+  <para>
+   The <filename>auto_explain</filename> module provides a means for
+   logging execution plans that execution times are longer than configuration.
+  </para>
+ 
+  <para>
+   You can <command>LOAD</> this module dynamically or preload it automatically with
+   <varname>shared_preload_libraries</> or <varname>local_preload_libraries</>.
+  </para>
+ 
+  <sect2>
+   <title>The <structname>auto_explain</structname> view</title>
+ 
+   <para>
+    The definitions of the columns exposed by the view are:
+   </para>
+ 
+   <para>
+    There is one row for each statement. Statements are grouped when they have
+    same SQL text, are in the same database, and are executed by the same user.
+   </para>
+ 
+   <para>
+    Because of security restriction, non-super users cannot see query strings
+    executed by other users.
+   </para>
+  </sect2>
+ 
+  <sect2>
+   <title>Configuration parameters</title>
+ 
+   <variablelist>
+    <varlistentry>
+     <term>
+      <varname>explain.log_min_duration</varname> (<type>integer</type>)
+     </term>
+     <listitem>
+      <para>
+       <varname>explain.log_min_duration</varname> is the minimum execution time
+       in milliseconds which execution plan will be logged. Setting this to zero
+       prints all plans. Minus-one (the default) disables logging plans.
+       For example, if you set it to <literal>250ms</literal> then all plan
+       that run 250ms or longer in executor will be logged.
+       Enabling this parameter can be helpful in tracking down unoptimized queries
+       in your applications. Only superusers can change this setting.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term>
+      <varname>explain.log_analyze</varname> (<type>boolean</type>)
+     </term>
+ 
+     <listitem>
+      <para>
+       <varname>explain.log_analyze</varname> enables to use EXPLAIN ANALYZE when
+       an execution plan is logged by <varname>explain.log_min_duration</varname>.
+       This parameter is off by default. Only superusers can change this setting.
+      </para>
+      <para>
+       NOTE: If you set the parameter on, instrument timers are enabled even if
+       you don't use EXPLAIN ANALYZE. This has some overhead to execute plans.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term>
+      <varname>explain.log_verbose</varname> (<type>boolean</type>)
+     </term>
+ 
+     <listitem>
+      <para>
+       <varname>explain.log_verbose</varname> enables to use EXPLAIN VERBOSE when
+       an execution plan is logged by <varname>explain.log_min_duration</varname>.
+       This parameter is off by default. Only superusers can change this setting.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term>
+      <varname>explain.log_nested_statements</varname> (<type>boolean</type>)
+     </term>
+ 
+     <listitem>
+      <para>
+       <varname>explain.log_nested_statements</varname> enables to log plans of
+       nested statements. If the value if off, only top-level plans are logged.
+       This parameter is off by default. Only superusers can change this setting.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+ 
+   <para>
+    If you set these explain.* parameters in your postgresql.conf,
+    you also need to add 'explain' in <varname>custom_variable_classes</>.
+   </para>
+ 
+   <programlisting>
+   # postgresql.conf
+   shared_preload_libraries = 'auto_explain'
+   
+   custom_variable_classes = 'explain'
+   explain.log_min_duration = 3s
+   </programlisting>
+  </sect2>
+ 
+  <sect2>
+   <title>Sample output</title>
+ 
+   <programlisting>
+   postgres=# LOAD 'auto_explain';
+   postgres=# SET explain.log_min_duration = 0;
+   postgres=# SELECT count(*)
+                FROM pg_class, pg_index
+               WHERE oid = indrelid AND indisunique;
+   
+   LOG:  duration: 0.986 ms  plan:
+           Aggregate  (cost=14.90..14.91 rows=1 width=0)
+             ->  Hash Join  (cost=3.91..14.70 rows=81 width=0)
+                   Hash Cond: (pg_class.oid = pg_index.indrelid)
+                   ->  Seq Scan on pg_class  (cost=0.00..8.27 rows=227 width=4)
+                   ->  Hash  (cost=2.90..2.90 rows=81 width=4)
+                         ->  Seq Scan on pg_index  (cost=0.00..2.90 rows=81 width=4)
+                               Filter: indisunique
+   STATEMENT:  SELECT count(*)
+             FROM pg_class, pg_index
+            WHERE oid = indrelid AND indisunique;
+   </programlisting>
+  </sect2>
+ 
+  <sect2>
+   <title>Authors</title>
+ 
+   <para>
+    Takahiro Itagaki <email>itagaki.takahiro@oss.ntt.co.jp</email>
+   </para>
+  </sect2>
+ 
+ </sect1>
diff -cprN HEAD/doc/src/sgml/contrib.sgml auto-explain/doc/src/sgml/contrib.sgml
*** HEAD/doc/src/sgml/contrib.sgml	Wed Jul 30 03:31:20 2008
--- auto-explain/doc/src/sgml/contrib.sgml	Mon Nov 10 17:55:49 2008
*************** psql -d dbname -f <replaceable>SHAREDIR<
*** 79,84 ****
--- 79,85 ----
   </para>
  
   &adminpack;
+  &auto-explain;
   &btree-gist;
   &chkpass;
   &citext;
diff -cprN HEAD/doc/src/sgml/filelist.sgml auto-explain/doc/src/sgml/filelist.sgml
*** HEAD/doc/src/sgml/filelist.sgml	Wed Jul 30 03:31:20 2008
--- auto-explain/doc/src/sgml/filelist.sgml	Mon Nov 10 17:55:49 2008
***************
*** 92,97 ****
--- 92,98 ----
  <!-- contrib information -->
  <!entity contrib         SYSTEM "contrib.sgml">
  <!entity adminpack       SYSTEM "adminpack.sgml">
+ <!entity auto-explain    SYSTEM "auto-explain.sgml">
  <!entity btree-gist      SYSTEM "btree-gist.sgml">
  <!entity chkpass         SYSTEM "chkpass.sgml">
  <!entity citext          SYSTEM "citext.sgml">
diff -cprN HEAD/src/backend/commands/explain.c auto-explain/src/backend/commands/explain.c
*** HEAD/src/backend/commands/explain.c	Tue Oct  7 05:29:38 2008
--- auto-explain/src/backend/commands/explain.c	Mon Nov 10 17:55:49 2008
*************** ExplainOnePlan(PlannedStmt *plannedstmt,
*** 224,230 ****
  	QueryDesc  *queryDesc;
  	instr_time	starttime;
  	double		totaltime = 0;
- 	ExplainState *es;
  	StringInfoData buf;
  	int			eflags;
  
--- 224,229 ----
*************** ExplainOnePlan(PlannedStmt *plannedstmt,
*** 265,281 ****
  		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;
- 
  	initStringInfo(&buf);
! 	explain_outNode(&buf,
! 					queryDesc->plannedstmt->planTree, queryDesc->planstate,
! 					NULL, 0, es);
  
  	/*
  	 * If we ran the command, run any AFTER triggers it queued.  (Note this
--- 264,271 ----
  		totaltime += elapsed_time(&starttime);
  	}
  
  	initStringInfo(&buf);
! 	ExplainOneResult(&buf, queryDesc, stmt->analyze, stmt->verbose);
  
  	/*
  	 * If we ran the command, run any AFTER triggers it queued.  (Note this
*************** ExplainOnePlan(PlannedStmt *plannedstmt,
*** 290,296 ****
  	}
  
  	/* Print info about runtime of triggers */
! 	if (es->printAnalyze)
  	{
  		ResultRelInfo *rInfo;
  		bool		show_relname;
--- 280,286 ----
  	}
  
  	/* Print info about runtime of triggers */
! 	if (stmt->analyze)
  	{
  		ResultRelInfo *rInfo;
  		bool		show_relname;
*************** ExplainOnePlan(PlannedStmt *plannedstmt,
*** 335,341 ****
  	do_text_output_multiline(tstate, buf.data);
  
  	pfree(buf.data);
! 	pfree(es);
  }
  
  /*
--- 325,350 ----
  	do_text_output_multiline(tstate, buf.data);
  
  	pfree(buf.data);
! }
! 
! /*
!  * ExplainOneResult -
!  *	  converts a Plan node into ascii string and appends it to 'str'
!  */
! void
! ExplainOneResult(StringInfo str, QueryDesc *queryDesc,
! 				 bool analyze, bool verbose)
! {
! 	ExplainState	es = { 0 };
! 
! 	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 -cprN HEAD/src/backend/tcop/pquery.c auto-explain/src/backend/tcop/pquery.c
*** HEAD/src/backend/tcop/pquery.c	Fri Aug  1 22:16:09 2008
--- auto-explain/src/backend/tcop/pquery.c	Mon Nov 10 17:55:49 2008
***************
*** 32,38 ****
   * if there are several).
   */
  Portal		ActivePortal = NULL;
! 
  
  static void ProcessQuery(PlannedStmt *plan,
  			 ParamListInfo params,
--- 32,38 ----
   * if there are several).
   */
  Portal		ActivePortal = NULL;
! bool		force_instrument = false;
  
  static void ProcessQuery(PlannedStmt *plan,
  			 ParamListInfo params,
*************** CreateQueryDesc(PlannedStmt *plannedstmt
*** 76,82 ****
  	qd->crosscheck_snapshot = RegisterSnapshot(crosscheck_snapshot);
  	qd->dest = dest;			/* output dest */
  	qd->params = params;		/* parameter values passed into query */
! 	qd->doInstrument = doInstrument;	/* instrumentation wanted? */
  
  	/* null these fields until set by ExecutorStart */
  	qd->tupDesc = NULL;
--- 76,82 ----
  	qd->crosscheck_snapshot = RegisterSnapshot(crosscheck_snapshot);
  	qd->dest = dest;			/* output dest */
  	qd->params = params;		/* parameter values passed into query */
! 	qd->doInstrument = force_instrument || doInstrument;	/* instrumentation wanted? */
  
  	/* null these fields until set by ExecutorStart */
  	qd->tupDesc = NULL;
diff -cprN HEAD/src/backend/utils/misc/guc.c auto-explain/src/backend/utils/misc/guc.c
*** HEAD/src/backend/utils/misc/guc.c	Sun Nov  9 09:28:35 2008
--- auto-explain/src/backend/utils/misc/guc.c	Mon Nov 10 17:55:49 2008
*************** static const char *assign_pgstat_temp_di
*** 169,174 ****
--- 169,175 ----
  
  static char *config_enum_get_options(struct config_enum *record, 
  									 const char *prefix, const char *suffix);
+ static void initialize_option(struct config_generic *gconf);
  
  
  /*
*************** InitializeGUCOptions(void)
*** 3194,3305 ****
  	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;
! 				}
! 		}
  	}
  
  	guc_dirty = false;
--- 3195,3201 ----
  	for (i = 0; i < num_guc_variables; i++)
  	{
  		struct config_generic *gconf = guc_variables[i];
! 		initialize_option(gconf);
  	}
  
  	guc_dirty = false;
*************** InitializeGUCOptions(void)
*** 3355,3360 ****
--- 3251,3365 ----
  	}
  }
  
+ static void
+ initialize_option(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
*************** define_custom_variable(struct config_gen
*** 5656,5661 ****
--- 5661,5667 ----
  	if (res == NULL)
  	{
  		/* No placeholder to replace, so just add it */
+ 		initialize_option(variable);
  		add_guc_variable(variable, ERROR);
  		return;
  	}
*************** define_custom_variable(struct config_gen
*** 5690,5695 ****
--- 5696,5703 ----
  		set_config_option(name, value,
  						  pHolder->gen.context, pHolder->gen.source,
  						  GUC_ACTION_SET, true);
+ 	else
+ 		initialize_option(variable);
  
  	/*
  	 * Free up as much as we conveniently can of the placeholder structure
*************** DefineCustomEnumVariable(const char *nam
*** 5821,5826 ****
--- 5829,5857 ----
  	var->assign_hook = assign_hook;
  	var->show_hook = show_hook;
  	define_custom_variable(&var->gen);
+ }
+ 
+ static const int config_varsize[] =
+ {
+ 	sizeof(struct config_bool),
+ 	sizeof(struct config_int),
+ 	sizeof(struct config_real),
+ 	sizeof(struct config_string),
+ 	sizeof(struct config_enum),
+ };
+ 
+ void
+ DefineCustomVariable(enum config_type type, const void *variable)
+ {
+ 	int		size = config_varsize[type];
+ 	const struct config_generic	   *var = variable;
+ 	struct config_generic		   *gen;
+ 
+ 	gen = (struct config_generic *) guc_malloc(ERROR, size);
+ 	memcpy(gen, var, size);
+ 	gen->name = guc_strdup(ERROR, var->name);
+ 	gen->vartype = type;
+ 	define_custom_variable(gen);
  }
  
  void
diff -cprN HEAD/src/include/commands/explain.h auto-explain/src/include/commands/explain.h
*** HEAD/src/include/commands/explain.h	Wed Jan  2 04:45:57 2008
--- auto-explain/src/include/commands/explain.h	Mon Nov 10 17:55:49 2008
*************** extern void ExplainOneUtility(Node *util
*** 41,44 ****
--- 41,47 ----
  extern void ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
  			   ExplainStmt *stmt, TupOutputState *tstate);
  
+ extern void ExplainOneResult(StringInfo str, QueryDesc *queryDesc,
+ 							 bool analyze, bool verbose);
+ 
  #endif   /* EXPLAIN_H */
diff -cprN HEAD/src/include/executor/execdesc.h auto-explain/src/include/executor/execdesc.h
*** HEAD/src/include/executor/execdesc.h	Wed Jan  2 04:45:57 2008
--- auto-explain/src/include/executor/execdesc.h	Mon Nov 10 17:55:49 2008
***************
*** 20,25 ****
--- 20,27 ----
  #include "tcop/dest.h"
  
  
+ extern PGDLLIMPORT bool force_instrument;
+ 
  /* ----------------
   *		query descriptor:
   *
diff -cprN HEAD/src/include/utils/guc_tables.h auto-explain/src/include/utils/guc_tables.h
*** HEAD/src/include/utils/guc_tables.h	Tue Sep 30 19:52:14 2008
--- auto-explain/src/include/utils/guc_tables.h	Mon Nov 10 17:55:49 2008
*************** extern const char *config_enum_lookup_by
*** 242,246 ****
--- 242,247 ----
  extern bool config_enum_lookup_by_name(struct config_enum *record,
  									  const char *value, int *retval);
  
+ extern void DefineCustomVariable(enum config_type type, const void *variable);
  
  #endif   /* GUC_TABLES_H */
