diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index bf7d7f94fc8d2da9cda7355a7aa0c80caab078d6..e1011f3fe082c612159ae8eb0480c8a941dc9fc5 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -14,7 +14,7 @@
  * Copyright (c) 2008-2009, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/contrib/pg_stat_statements/pg_stat_statements.c,v 1.5 2009/07/27 04:09:55 tgl Exp $
+ *	  $PostgreSQL: pgsql/contrib/pg_stat_statements/pg_stat_statements.c,v 1.6 2009/12/01 01:08:45 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,6 +24,7 @@
 
 #include "access/hash.h"
 #include "catalog/pg_type.h"
+#include "commands/copy.h"
 #include "executor/executor.h"
 #include "executor/instrument.h"
 #include "mb/pg_wchar.h"
@@ -32,6 +33,7 @@
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/spin.h"
+#include "tcop/utility.h"
 #include "utils/builtins.h"
 #include "utils/hsearch.h"
 #include "utils/guc.h"
@@ -113,6 +115,7 @@ static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
 static ExecutorStart_hook_type prev_ExecutorStart = NULL;
 static ExecutorRun_hook_type prev_ExecutorRun = NULL;
 static ExecutorEnd_hook_type prev_ExecutorEnd = NULL;
+static ProcessUtility_hook_type prev_ProcessUtility = NULL;
 
 /* Links to shared memory state */
 static pgssSharedState *pgss = NULL;
@@ -124,10 +127,11 @@ typedef enum
 {
 	PGSS_TRACK_NONE,			/* track no statements */
 	PGSS_TRACK_TOP,				/* only top level statements */
-	PGSS_TRACK_ALL,				/* all statements, including nested ones */
+	PGSS_TRACK_ALL				/* all statements, including nested ones */
 } PGSSTrackLevel;
 
-static const struct config_enum_entry track_options[] = {
+static const struct config_enum_entry track_options[] =
+{
 	{"none", PGSS_TRACK_NONE, false},
 	{"top", PGSS_TRACK_TOP, false},
 	{"all", PGSS_TRACK_ALL, false},
@@ -136,6 +140,7 @@ static const struct config_enum_entry track_options[] = {
 
 static int	pgss_max;			/* max # statements to track */
 static int	pgss_track;			/* tracking level */
+static bool pgss_track_ddl;		/* whether to track ddl commands */
 static bool pgss_save;			/* whether to save stats across shutdown */
 
 
@@ -146,7 +151,9 @@ static bool pgss_save;			/* whether to save stats across shutdown */
 /*---- Function declarations ----*/
 
 void		_PG_init(void);
+#ifdef NOT_USED
 void		_PG_fini(void);
+#endif
 
 Datum		pg_stat_statements_reset(PG_FUNCTION_ARGS);
 Datum		pg_stat_statements(PG_FUNCTION_ARGS);
@@ -161,10 +168,12 @@ static void pgss_ExecutorRun(QueryDesc *queryDesc,
 				 ScanDirection direction,
 				 long count);
 static void pgss_ExecutorEnd(QueryDesc *queryDesc);
+static void pgss_ProcessUtility(Node *parsetree,
+			   const char *queryString, ParamListInfo params, bool isTopLevel,
+			   DestReceiver *dest, char *completionTag);
 static uint32 pgss_hash_fn(const void *key, Size keysize);
 static int	pgss_match_fn(const void *key1, const void *key2, Size keysize);
-static void pgss_store(const char *query,
-		   const Instrumentation *instr, uint32 rows);
+static void pgss_store(const char *query, double total_time, uint64 rows);
 static Size pgss_memsize(void);
 static pgssEntry *entry_alloc(pgssHashKey *key);
 static void entry_dealloc(void);
@@ -214,6 +223,16 @@ _PG_init(void)
 							 NULL,
 							 NULL);
 
+	DefineCustomBoolVariable("pg_stat_statements.track_ddl",
+			   "Selects whether DDL commands are tracked by pg_stat_statements.",
+							 NULL,
+							 &pgss_track_ddl,
+							 true,
+							 PGC_SUSET,
+							 0,
+							 NULL,
+							 NULL);
+
 	DefineCustomBoolVariable("pg_stat_statements.save",
 			   "Save pg_stat_statements statistics across server shutdowns.",
 							 NULL,
@@ -245,8 +264,11 @@ _PG_init(void)
 	ExecutorRun_hook = pgss_ExecutorRun;
 	prev_ExecutorEnd = ExecutorEnd_hook;
 	ExecutorEnd_hook = pgss_ExecutorEnd;
+	prev_ProcessUtility = ProcessUtility_hook;
+	ProcessUtility_hook = pgss_ProcessUtility;
 }
 
+#ifdef NOT_USED
 /*
  * Module unload callback
  */
@@ -257,8 +279,10 @@ _PG_fini(void)
 	ExecutorStart_hook = prev_ExecutorStart;
 	ExecutorRun_hook = prev_ExecutorRun;
 	ExecutorEnd_hook = prev_ExecutorEnd;
+	ProcessUtility_hook = prev_ProcessUtility;
 	shmem_startup_hook = prev_shmem_startup_hook;
 }
+#endif
 
 /*
  * shmem_startup hook: allocate or attach to shared memory,
@@ -539,7 +563,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
 		InstrEndLoop(queryDesc->totaltime);
 
 		pgss_store(queryDesc->sourceText,
-				   queryDesc->totaltime,
+				   queryDesc->totaltime->total,
 				   queryDesc->estate->es_processed);
 	}
 
@@ -549,6 +573,59 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
 		standard_ExecutorEnd(queryDesc);
 }
 
+/*
+ * ProcessUtility hook
+ */
+static void
+pgss_ProcessUtility(Node *parsetree, const char *queryString,
+					ParamListInfo params, bool isTopLevel,
+					DestReceiver *dest, char *completionTag)
+{
+	if (pgss_track_ddl && isTopLevel && pgss_enabled())
+	{
+		instr_time	start;
+		instr_time	duration;
+		uint64		rows = 0;
+
+		INSTR_TIME_SET_CURRENT(start);
+
+		nested_level++;
+		PG_TRY();
+		{
+			if (prev_ProcessUtility)
+				prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
+			else if ((nodeTag(parsetree)) == T_CopyStmt)
+			{
+				rows = DoCopy((CopyStmt *) parsetree, queryString);
+				if (completionTag)
+					snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
+							 "COPY " UINT64_FORMAT, rows);
+			}
+			else
+				standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
+			nested_level--;
+		}
+		PG_CATCH();
+		{
+			nested_level--;
+			PG_RE_THROW();
+		}
+		PG_END_TRY();
+
+		INSTR_TIME_SET_CURRENT(duration);
+		INSTR_TIME_SUBTRACT(duration, start);
+
+		pgss_store(queryString, INSTR_TIME_GET_DOUBLE(duration), rows);
+	}
+	else
+	{
+		if (prev_ProcessUtility)
+			prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
+		else
+			standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
+	}
+}
+
 /*
  * Calculate hash value for a key
  */
@@ -587,7 +664,7 @@ pgss_match_fn(const void *key1, const void *key2, Size keysize)
  * Store some statistics for a statement.
  */
 static void
-pgss_store(const char *query, const Instrumentation *instr, uint32 rows)
+pgss_store(const char *query, double total_time, uint64 rows)
 {
 	pgssHashKey key;
 	double		usage;
@@ -631,7 +708,7 @@ pgss_store(const char *query, const Instrumentation *instr, uint32 rows)
 
 		SpinLockAcquire(&e->mutex);
 		e->counters.calls += 1;
-		e->counters.total_time += instr->total;
+		e->counters.total_time += total_time;
 		e->counters.rows += rows;
 		e->counters.usage += usage;
 		SpinLockRelease(&e->mutex);
diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml
index 67e7256a4e415fdf7a36dcb42adcbee038dcd9ae..ffa2702537997810618b624a90221a289af80711 100644
--- a/doc/src/sgml/pgstatstatements.sgml
+++ b/doc/src/sgml/pgstatstatements.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/pgstatstatements.sgml,v 1.2 2009/05/18 11:08:24 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/pgstatstatements.sgml,v 1.3 2009/12/01 01:08:46 momjian Exp $ -->
 
 <sect1 id="pgstatstatements">
  <title>pg_stat_statements</title>
@@ -174,6 +174,23 @@
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term>
+     <varname>pg_stat_statements.track_ddl</varname> (<type>boolean</type>)
+    </term>
+
+    <listitem>
+     <para>
+      <varname>pg_stat_statements.track_ddl</varname> controls whether DDL
+      commands are counted by the module.
+      Specify <literal>on</> to track DDL commands, which excludes <command>SELECT</>,
+      <command>INSERT</>, <command>UPDATE</> and <command>DELETE</> statements.
+      The default value is <literal>on</>.
+      Only superusers can change this setting.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term>
      <varname>pg_stat_statements.save</varname> (<type>boolean</type>)
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 42071bfb6c1c278a1f500faa2a95794b518dbf4e..67333b1796a863a77e583b91af3a374010fe8dc7 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.318 2009/11/20 20:38:11 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.319 2009/12/01 01:08:46 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,6 +58,9 @@
 #include "utils/syscache.h"
 
 
+/* Hooks for plugins to get control in ProcessUtility() */
+ProcessUtility_hook_type ProcessUtility_hook = NULL;
+
 /*
  * Verify user has ownership of specified relation, else ereport.
  *
@@ -244,6 +247,10 @@ check_xact_readonly(Node *parsetree)
  * completionTag is only set nonempty if we want to return a nondefault status.
  *
  * completionTag may be NULL if caller doesn't want a status string.
+ *
+ * We provide a function hook variable that lets loadable plugins
+ * get control when ProcessUtility is called.  Such a plugin would
+ * normally call standard_ProcessUtility().
  */
 void
 ProcessUtility(Node *parsetree,
@@ -260,6 +267,20 @@ ProcessUtility(Node *parsetree,
 	if (completionTag)
 		completionTag[0] = '\0';
 
+	if (ProcessUtility_hook)
+		(*ProcessUtility_hook) (parsetree, queryString, params, isTopLevel, dest, completionTag);
+	else
+		standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
+}
+
+void
+standard_ProcessUtility(Node *parsetree,
+			   const char *queryString,
+			   ParamListInfo params,
+			   bool isTopLevel,
+			   DestReceiver *dest,
+			   char *completionTag)
+{
 	switch (nodeTag(parsetree))
 	{
 			/*
diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h
index d609b0ac4e95975b8f220af1ba47bde3c8327b33..ce3ee1fb0551379da22d1a4ded976df25ca531a4 100644
--- a/src/include/tcop/utility.h
+++ b/src/include/tcop/utility.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.35 2009/01/01 17:24:01 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.36 2009/12/01 01:08:46 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,9 +17,18 @@
 #include "tcop/tcopprot.h"
 
 
+/* Hook for plugins to get control in ProcessUtility() */
+typedef void (*ProcessUtility_hook_type) (Node *parsetree,
+			   const char *queryString, ParamListInfo params, bool isTopLevel,
+			   DestReceiver *dest, char *completionTag);
+extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook;
+
 extern void ProcessUtility(Node *parsetree, const char *queryString,
 			   ParamListInfo params, bool isTopLevel,
 			   DestReceiver *dest, char *completionTag);
+extern void standard_ProcessUtility(Node *parsetree, const char *queryString,
+			   ParamListInfo params, bool isTopLevel,
+			   DestReceiver *dest, char *completionTag);
 
 extern bool UtilityReturnsTuples(Node *parsetree);