From 266c0fba36117e1d9cb8efe47a051bcace3a6eb6 Mon Sep 17 00:00:00 2001
From: Alex Zhao <alexyuzhao@gmail.com>
Date: Wed, 13 Nov 2019 12:49:01 +1100
Subject: [PATCH] pg_stat_sql

---
 doc/src/sgml/config.sgml                      |  15 +
 doc/src/sgml/monitoring.sgml                  |  42 +++
 src/backend/catalog/system_views.sql          |   4 +
 src/backend/postmaster/pgstat.c               |  57 ++-
 src/backend/storage/ipc/ipci.c                |   2 +
 src/backend/storage/lmgr/lwlocknames.txt      |   1 +
 src/backend/tcop/postgres.c                   |  18 +-
 src/backend/tcop/utility.c                    | 523 ++++++++++++++++++++++++--
 src/backend/utils/adt/pgstatfuncs.c           |  61 +++
 src/backend/utils/misc/guc.c                  |  10 +-
 src/backend/utils/misc/postgresql.conf.sample |   1 +
 src/include/catalog/pg_proc.dat               |   9 +-
 src/include/pgstat.h                          |  16 +-
 src/include/tcop/utility.h                    | 201 ++++++++++
 src/test/regress/expected/rules.out           |   3 +
 src/test/regress/expected/stats.out           |  64 ++++
 src/test/regress/sql/stats.sql                |  24 ++
 17 files changed, 1020 insertions(+), 31 deletions(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index f837703..e43988d 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -6983,6 +6983,21 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
       </listitem>
      </varlistentry>
 
+    <varlistentry id="guc-track-statement-statistics" xreflabel="track_statement_statistics">
+    <term><varname>track_statement_statistics</varname> (<type>boolean</type>)
+    <indexterm>
+    <primary><varname>track_statement_statistics</varname> configuration parameter</primary>
+    </indexterm>
+    </term>
+    <listitem>
+    <para>
+        Enables collection of different SQL statement statistics that are
+        executed on the instance. This parameter is off by default. Only
+        superusers can change this setting.
+    </para>
+    </listitem>
+    </varlistentry>
+
      <varlistentry id="guc-stats-temp-directory" xreflabel="stats_temp_directory">
       <term><varname>stats_temp_directory</varname> (<type>string</type>)
       <indexterm>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 901fee9..3514833 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -361,6 +361,13 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      </row>
 
      <row>
+      <entry><structname>pg_stat_sql</structname>><indexterm><primary>pg_stat_sql</primary></indexterm></entry>
+      <entry>Shows statistics about the SQL statements that are
+       executed on the instance.
+       See <xref linkend='pg-stat-sql-view'/> for details.</entry>
+     </row>
+
+     <row>
       <entry><structname>pg_stat_progress_cluster</structname><indexterm><primary>pg_stat_progress_cluster</primary></indexterm></entry>
       <entry>One row for each backend running
        <command>CLUSTER</command> or <command>VACUUM FULL</command>, showing current progress.
@@ -3185,6 +3192,39 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
    controls exactly which functions are tracked.
   </para>
 
+  <table id="pg-stat-sql-view" xreflabel="pg_stat_sql">
+   <title><structname>pg_stat_sql</structname> View</title>
+   <tgroup cols="3">
+    <thead>
+    <row>
+      <entry>Column</entry>
+      <entry>Type</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+   <tbody>
+    <row>
+     <entry><structfield>tag</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>Tag of the SQL statement</entry>
+    </row>
+    <row>
+     <entry><structfield>count</structfield></entry>
+     <entry><type>bigint</type></entry>
+     <entry>Number of times the SQL statement is executed</entry>
+    </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+  <para>
+   The <structname>pg_stat_sql</structname> view will contain statistics
+   about number of SQL statements that are executed on the instance.
+   The <xref linkend="guc-track-statement-statistics"/> parameter controls the SQL statement
+   execution statistics.
+  </para>
+
  </sect2>
 
  <sect2 id="monitoring-stats-functions">
@@ -3280,6 +3320,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
        counters shown in the <structname>pg_stat_bgwriter</structname> view.
        Calling <literal>pg_stat_reset_shared('archiver')</literal> will zero all the
        counters shown in the <structname>pg_stat_archiver</structname> view.
+       Calling <literal>pg_stat_reset_shared('sqlstmt')</literal> will zero all the
+       counters shown in the <structname>pg_stat_sql</structname> view.
       </entry>
      </row>
 
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 4456fef..598c1d3 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1063,6 +1063,10 @@ REVOKE ALL ON pg_subscription FROM public;
 GRANT SELECT (subdbid, subname, subowner, subenabled, subslotname, subpublications)
     ON pg_subscription TO public;
 
+CREATE VIEW pg_stat_sql AS
+    SELECT * FROM pg_stat_sql();
+
+REVOKE EXECUTE ON FUNCTION pg_stat_sql() FROM public;
 
 --
 -- We have a few function definitions in here, too.
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index fabcf31..90dfd90 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -122,6 +122,7 @@
  */
 bool		pgstat_track_activities = false;
 bool		pgstat_track_counts = false;
+bool		pgstat_track_statement_statistics = false;
 int			pgstat_track_functions = TRACK_FUNC_OFF;
 int			pgstat_track_activity_query_size = 1024;
 
@@ -140,6 +141,13 @@ char	   *pgstat_stat_tmpname = NULL;
  */
 PgStat_MsgBgWriter BgWriterStats;
 
+
+/*
+ * Global SQL statement counters gathered that are stored in
+ * shared memory.
+ */
+uint64* pgstat_sql_counts = NULL;
+
 /* ----------
  * Local data
  * ----------
@@ -629,6 +637,32 @@ startup_failed:
 	SetConfigOption("track_counts", "off", PGC_INTERNAL, PGC_S_OVERRIDE);
 }
 
+
+/*
+ * Initialization of shared memory for pgstat_sql_count
+ */
+Size
+pgstat_sql_shmem_size(void)
+{
+	return sizeof(uint64) * PGSTAT_SQLSTMT_SIZE;
+}
+
+void
+pgstat_sql_shmem_init(void)
+{
+	bool		foundWALWrites;
+
+	pgstat_sql_counts = (uint64 *)
+		ShmemInitStruct("pgstat sql counter", pgstat_sql_shmem_size(), &foundWALWrites);
+
+	if (!foundWALWrites)
+	{
+		MemSet(pgstat_sql_counts, 0, pgstat_sql_shmem_size());
+	}
+}
+
+
+
 /*
  * subroutine for pgstat_reset_all
  */
@@ -1339,11 +1373,21 @@ pgstat_reset_shared_counters(const char *target)
 		msg.m_resettarget = RESET_ARCHIVER;
 	else if (strcmp(target, "bgwriter") == 0)
 		msg.m_resettarget = RESET_BGWRITER;
+	else if (strcmp(target, "sqlstmt") == 0)
+	{
+		/*
+		 * Reset the pgstat sql counters. These statistics are not reset
+		 * by the stats collector because they reside in shared memory.
+		 */
+		LWLockAcquire(WALWriteLock, LW_EXCLUSIVE);
+		memset(pgstat_sql_counts, 0, pgstat_sql_shmem_size());
+		LWLockRelease(WALWriteLock);
+	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("unrecognized reset target: \"%s\"", target),
-				 errhint("Target must be \"archiver\" or \"bgwriter\".")));
+				 errhint("Target must be \"archiver\" or \"bgwriter\" or \"sqlstmt\".")));
 
 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSHAREDCOUNTER);
 	pgstat_send(&msg, sizeof(msg));
@@ -4413,6 +4457,17 @@ pgstat_send_bgwriter(void)
 }
 
 
+/*
+ * Count SQL statement for pg_stat_sql view
+ */
+void
+pgstat_count_sqlstmt(StatSqlType sqlType)
+{
+	LWLockAcquire(PGSTATSqlLock, LW_EXCLUSIVE);
+	pgstat_sql_counts[sqlType] += 1;
+	LWLockRelease(PGSTATSqlLock);
+}
+
 /* ----------
  * PgstatCollectorMain() -
  *
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 4829953..380e2fe 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -147,6 +147,7 @@ CreateSharedMemoryAndSemaphores(void)
 		size = add_size(size, BTreeShmemSize());
 		size = add_size(size, SyncScanShmemSize());
 		size = add_size(size, AsyncShmemSize());
+		size = add_size(size, pgstat_sql_shmem_size());
 #ifdef EXEC_BACKEND
 		size = add_size(size, ShmemBackendArraySize());
 #endif
@@ -212,6 +213,7 @@ CreateSharedMemoryAndSemaphores(void)
 	 * Set up xlog, clog, and buffers
 	 */
 	XLOGShmemInit();
+	pgstat_sql_shmem_init();
 	CLOGShmemInit();
 	CommitTsShmemInit();
 	SUBTRANSShmemInit();
diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt
index db47843..50214d6 100644
--- a/src/backend/storage/lmgr/lwlocknames.txt
+++ b/src/backend/storage/lmgr/lwlocknames.txt
@@ -49,3 +49,4 @@ MultiXactTruncationLock				41
 OldSnapshotTimeMapLock				42
 LogicalRepWorkerLock				43
 CLogTruncationLock					44
+PGSTATSqlLock						45
\ No newline at end of file
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index d7a72c0..4957e21 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1063,6 +1063,7 @@ exec_simple_query(const char *query_string)
 		RawStmt    *parsetree = lfirst_node(RawStmt, parsetree_item);
 		bool		snapshot_set = false;
 		const char *commandTag;
+		StatSqlType eSqlType;
 		char		completionTag[COMPLETION_TAG_BUFSIZE];
 		MemoryContext per_parsetree_context = NULL;
 		List	   *querytree_list,
@@ -1077,8 +1078,7 @@ exec_simple_query(const char *query_string)
 		 * do any special start-of-SQL-command processing needed by the
 		 * destination.
 		 */
-		commandTag = CreateCommandTag(parsetree->stmt);
-
+		commandTag = CreateCommandTagType(parsetree->stmt, &eSqlType);
 		set_ps_display(commandTag, false);
 
 		BeginCommand(commandTag, dest);
@@ -1234,6 +1234,12 @@ exec_simple_query(const char *query_string)
 
 		PortalDrop(portal, false);
 
+		/*
+		 * Count SQL statement for pg_stat_sql view
+		 */
+		if (pgstat_track_statement_statistics)
+			pgstat_count_sqlstmt(eSqlType);
+
 		if (lnext(parsetree_list, parsetree_item) == NULL)
 		{
 			/*
@@ -2118,6 +2124,14 @@ exec_execute_message(const char *portal_name, long max_rows)
 
 	receiver->rDestroy(receiver);
 
+	/*
+	 * Count SQL Statement for pgx_stat_sql
+	 */
+	if (pgstat_track_statement_statistics && !execute_is_fetch)
+	{
+		pgstat_count_sqlstmt(T_Stat_EXECUTE);
+	}
+
 	if (completed)
 	{
 		if (is_xact_command)
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 6787d8e..3e4f433 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -85,6 +85,193 @@ static void ProcessUtilitySlow(ParseState *pstate,
 							   char *completionTag);
 static void ExecDropStmt(DropStmt *stmt, bool isTopLevel);
 
+const char* g_str_sql_type[] =
+{
+	[T_Stat_INSERT] = "INSERT",
+	[T_Stat_DELETE] = "DELETE",
+	[T_Stat_UPDATE] = "UPDATE",
+	[T_Stat_SELECT] = "SELECT",
+	[T_Stat_BEGIN] = "BEGIN",
+	[T_Stat_START_TRANSACTION] = "START TRANSACTION",
+	[T_Stat_COMMIT] = "COMMIT",
+	[T_Stat_ROLLBACK] = "ROLLBACK",
+	[T_Stat_SAVEPOINT] = "SAVEPOINT",
+	[T_Stat_RELEASE] = "RELEASE",
+	[T_Stat_PREPARE_TRANSACTION] = "PREPARE TRANSACTION",
+	[T_Stat_COMMIT_PREPARED] = "COMMIT PREPARED",
+	[T_Stat_ROLLBACK_PREPARED] = "ROLLBACK PREPARED",
+	[T_Stat_DECLARE_CURSOR] = "DECLARE CURSOR",
+	[T_Stat_CLOSE_CURSOR_ALL] = "CLOSE CURSOR ALL",
+	[T_Stat_CLOSE_CURSOR] = "CLOSE CURSOR",
+	[T_Stat_MOVE] = "MOVE",
+	[T_Stat_FETCH] = "FETCH",
+	[T_Stat_CREATE_DOMAIN] = "CREATE DOMAIN",
+	[T_Stat_CREATE_SCHEMA] = "CREATE SCHEMA",
+	[T_Stat_CREATE_TABLE] = "CREATE TABLE",
+	[T_Stat_CREATE_TABLESPACE] = "CREATE TABLESPACE",
+	[T_Stat_DROP_TABLESPACE] = "DROP TABLESPACE",
+	[T_Stat_ALTER_TABLESPACE] = "ALTER TABLESPACE",
+	[T_Stat_CREATE_EXTENSION] = "CREATE EXTENSION",
+	[T_Stat_ALTER_EXTENSION] = "ALTER EXTENSION",
+	[T_Stat_CREATE_FOREIGN_DATA_WRAPPER] = "CREATE FOREIGN DATA WRAPPER",
+	[T_Stat_ALTER_FOREIGN_DATA_WRAPPER] = "ALTER FOREIGN DATA WRAPPER",
+	[T_Stat_CREATE_SERVER] = "CREATE SERVER",
+	[T_Stat_ALTER_SERVER] = "ALTER SERVER",
+	[T_Stat_CREATE_USER_MAPPING] = "CREATE USER MAPPING",
+	[T_Stat_ALTER_USER_MAPPING] = "ALTER USER MAPPING",
+	[T_Stat_DROP_USER_MAPPING] = "DROP USER MAPPING",
+	[T_Stat_CREATE_FOREIGN_TABLE] = "CREATE FOREIGN TABLE",
+	[T_Stat_IMPORT_FOREIGN_SCHEMA] = "IMPORT FOREIGN SCHEMA",
+	[T_Stat_DROP_TABLE] = "DROP TABLE",
+	[T_Stat_DROP_SEQUENCE] = "DROP SEQUENCE",
+	[T_Stat_DROP_VIEW] = "DROP VIEW",
+	[T_Stat_DROP_MATERIALIZED_VIEW] = "DROP MATERIALIZED VIEW",
+	[T_Stat_DROP_INDEX] = "DROP INDEX",
+	[T_Stat_DROP_TYPE] = "DROP TYPE",
+	[T_Stat_DROP_DOMAIN] = "DROP DOMAIN",
+	[T_Stat_DROP_COLLATION] = "DROP COLLATION",
+	[T_Stat_DROP_CONVERSION] = "DROP CONVERSION",
+	[T_Stat_DROP_SCHEMA] = "DROP SCHEMA",
+	[T_Stat_DROP_TEXT_SEARCH_PARSER] = "DROP TEXT SEARCH PARSER",
+	[T_Stat_DROP_TEXT_SEARCH_DICTIONARY] = "DROP TEXT SEARCH DICTIONARY",
+	[T_Stat_DROP_TEXT_SEARCH_TEMPLATE] = "DROP TEXT SEARCH TEMPLATE",
+	[T_Stat_DROP_DROP_TEXT_SEARCH_CONFIGURATION] = "DROP TEXT SEARCH CONFIGURATION",
+	[T_Stat_DROP_DROP_FOREIGN_TABLE] = "DROP FOREIGN TABLE",
+	[T_Stat_DROP_EXTENSION] = "DROP EXTENSION",
+	[T_Stat_DROP_FUNCTION] = "DROP FUNCTION",
+	[T_Stat_DROP_PROCEDURE] = "DROP PROCEDURE",
+	[T_Stat_DROP_ROUTINE] = "DROP ROUTINE",
+	[T_Stat_DROP_AGGREGATE] = "DROP AGGREGATE",
+	[T_Stat_DROP_OPERATOR] = "DROP OPERATOR",
+	[T_Stat_DROP_LANGUAGE] = "DROP LANGUAGE",
+	[T_Stat_DROP_CAST] = "DROP CAST",
+	[T_Stat_DROP_TRIGGER] = "DROP TRIGGER",
+	[T_Stat_DROP_EVENT_TRIGGER] = "DROP EVENT TRIGGER",
+	[T_Stat_DROP_RULE] = "DROP RULE",
+	[T_Stat_DROP_FOREIGN_DATA_WRAPPER] = "DROP FOREIGN DATA WRAPPER",
+	[T_Stat_DROP_SERVER] = "DROP SERVER",
+	[T_Stat_DROP_OPERATOR_CLASS] = "DROP OPERATOR CLASS",
+	[T_Stat_DROP_OPERATOR_FAMILY] = "DROP OPERATOR FAMILY",
+	[T_Stat_DROP_POLICY] = "DROP POLICY",
+	[T_Stat_DROP_TRANSFORM] = "DROP TRANSFORM",
+	[T_Stat_DROP_ACCESS_METHOD] = "DROP ACCESS METHOD",
+	[T_Stat_DROP_PUBLICATION] = "DROP PUBLICATION",
+	[T_Stat_DROP_STATISTICS] = "DROP STATISTICS",
+	[T_Stat_TRUNCATE_TABLE] = "TRUNCATE TABLE",
+	[T_Stat_COMMENT] = "COMMENT",
+	[T_Stat_SECURITY_LABEL] = "SECURITY LABEL",
+	[T_Stat_COPY] = "COPY",
+	[T_Stat_ALTER_AGGREGATE] = "ALTER AGGREGATE",
+	[T_Stat_ALTER_TYPE] = "ALTER TYPE",
+	[T_Stat_ALTER_CAST] = "ALTER CAST",
+	[T_Stat_ALTER_COLLATION] = "ALTER COLLATION",
+	[T_Stat_ALTER_TABLE] = "ALTER TABLE",
+	[T_Stat_ALTER_CONVERSION] = "ALTER CONVERSION",
+	[T_Stat_ALTER_DATABASE] = "ALTER DATABASE",
+	[T_Stat_ALTER_DOMAIN] = "ALTER DOMAIN",
+	[T_Stat_ALTER_FOREIGN_TABLE] = "ALTER FOREIGN TABLE",
+	[T_Stat_ALTER_FUNCTION] = "ALTER FUNCTION",
+	[T_Stat_ALTER_INDEX] = "ALTER INDEX",
+	[T_Stat_ALTER_LANGUAGE] = "ALTER LANGUAGE",
+	[T_Stat_ALTER_LARGE_OBJECT] = "ALTER LARGE OBJECT",
+	[T_Stat_ALTER_OPERATOR_CLASS] = "ALTER OPERATOR CLASS",
+	[T_Stat_ALTER_OPERATOR] = "ALTER OPERATOR",
+	[T_Stat_ALTER_OPERATOR_FAMILY] = "ALTER OPERATOR FAMILY",
+	[T_Stat_ALTER_POLICY] = "ALTER POLICY",
+	[T_Stat_ALTER_PROCEDURE] = "ALTER PROCEDURE",
+	[T_Stat_ALTER_ROLE] = "ALTER ROLE",
+	[T_Stat_ALTER_ROUTINE] = "ALTER ROUTINE",
+	[T_Stat_ALTER_RULE] = "ALTER RULE",
+	[T_Stat_ALTER_SCHEMA] = "ALTER SCHEMA",
+	[T_Stat_ALTER_SEQUENCE] = "ALTER SEQUENCE",
+	[T_Stat_ALTER_TRIGGER] = "ALTER TRIGGER",
+	[T_Stat_ALTER_EVENT_TRIGGER] = "ALTER EVENT TRIGGER",
+	[T_Stat_ALTER_TEXT_SEARCH_CONFIGURATION] = "ALTER TEXT SEARCH CONFIGURATION",
+	[T_Stat_ALTER_TEXT_SEARCH_DICTIONARY] = "ALTER TEXT SEARCH DICTIONARY",
+	[T_Stat_ALTER_TEXT_SEARCH_PARSER] = "ALTER TEXT SEARCH PARSER",
+	[T_Stat_ALTER_TEXT_SEARCH_TEMPLATE] = "ALTER TEXT SEARCH TEMPLATE",
+	[T_Stat_ALTER_VIEW] = "ALTER VIEW",
+	[T_Stat_ALTER_MATERIALIZED_VIEW] = "ALTER MATERIALIZED VIEW",
+	[T_Stat_ALTER_PUBLICATION] = "ALTER PUBLICATION",
+	[T_Stat_ALTER_SUBSCRIPTION] = "ALTER SUBSCRIPTION",
+	[T_Stat_ALTER_STATISTICS] = "ALTER STATISTICS",
+	[T_Stat_GRANT] = "GRANT",
+	[T_Stat_REVOKE] = "REVOKE",
+	[T_Stat_GRANT_ROLE] = "GRANT ROLE",
+	[T_Stat_REVOKE_ROLE] = "REVOKE ROLE",
+	[T_Stat_ALTER_DEFAULT_PRIVILEGES] = "ALTER DEFAULT PRIVILEGES",
+	[T_Stat_CREATE_AGGREGATE] = "CREATE AGGREGATE",
+	[T_Stat_CREATE_OPERATOR] = "CREATE OPERATOR",
+	[T_Stat_CREATE_TYPE] = "CREATE TYPE",
+	[T_Stat_CREATE_TEXT_SEARCH_PARSER] = "CREATE TEXT SEARCH PARSER",
+	[T_Stat_CREATE_TEXT_SEARCH_DICTIONARY] = "CREATE TEXT SEARCH DICTIONARY",
+	[T_Stat_CREATE_TEXT_SEARCH_TEMPLATE] = "CREATE TEXT SEARCH TEMPLATE",
+	[T_Stat_CREATE_TEXT_SEARCH_CONFIGURATION] = "CREATE TEXT SEARCH CONFIGURATION",
+	[T_Stat_CREATE_COLLATION] = "CREATE COLLATION",
+	[T_Stat_CREATE_ACCESS_METHOD] = "CREATE ACCESS METHOD",
+	[T_Stat_CREATE_VIEW] = "CREATE VIEW",
+	[T_Stat_CREATE_PROCEDURE] = "CREATE PROCEDURE",
+	[T_Stat_CREATE_FUNCTION] = "CREATE FUNCTION",
+	[T_Stat_CREATE_INDEX] = "CREATE INDEX",
+	[T_Stat_CREATE_RULE] = "CREATE RULE",
+	[T_Stat_CREATE_SEQUENCE] = "CREATE SEQUENCE",
+	[T_Stat_DO] = "DO",
+	[T_Stat_CREATE_DATABASE] = "CREATE DATABASE",
+	[T_Stat_DROP_DATABASE] = "DROP DATABASE",
+	[T_Stat_NOTIFY] = "NOTIFY",
+	[T_Stat_LISTEN] = "LISTEN",
+	[T_Stat_UNLISTEN] = "UNLISTEN",
+	[T_Stat_LOAD] = "LOAD",
+	[T_Stat_CALL] = "CALL",
+	[T_Stat_CLUSTER] = "CLUSTER",
+	[T_Stat_VACUUM] = "VACUUM",
+	[T_Stat_ANALYZE] = "ANALYZE",
+	[T_Stat_EXPLAIN] = "EXPLAIN",
+	[T_Stat_SELECT_INTO] = "SELECT INTO",
+	[T_Stat_CREATE_TABLE_AS] = "CREATE TABLE AS",
+	[T_Stat_CREATE_MATERIALIZED_VIEW] = "CREATE MATERIALIZED VIEW",
+	[T_Stat_REFRESH_MATERIALIZED_VIEW] = "REFRESH MATERIALIZED VIEW",
+	[T_Stat_ALTER_SYSTEM] = "ALTER SYSTEM",
+	[T_Stat_SET] = "SET",
+	[T_Stat_RESET] = "RESET",
+	[T_Stat_SHOW] = "SHOW",
+	[T_Stat_DISCARD_ALL] = "DISCARD ALL",
+	[T_Stat_DISCARD_PLANS] = "DISCARD PLANS",
+	[T_Stat_DISCARD_TEMP] = "DISCARD TEMP",
+	[T_Stat_DISCARD_SEQUENCES] = "DISCARD SEQUENCES",
+	[T_Stat_CREATE_TRANSFORM] = "CREATE TRANSFORM",
+	[T_Stat_CREATE_TRIGGER] = "CREATE TRIGGER",
+	[T_Stat_CREATE_EVENT_TRIGGER] = "CREATE EVENT TRIGGER",
+	[T_Stat_CREATE_LANGUAGE] = "CREATE LANGUAGE",
+	[T_Stat_CREATE_ROLE] = "CREATE ROLE",
+	[T_Stat_DROP_ROLE] = "DROP ROLE",
+	[T_Stat_DROP_OWNED] = "DROP OWNED",
+	[T_Stat_REASSIGN_OWNED] = "REASSIGN OWNED",
+	[T_Stat_LOCK_TABLE] = "LOCK TABLE",
+	[T_Stat_SET_CONSTRAINTS] = "SET CONSTRAINTS",
+	[T_Stat_CHECKPOINT] = "CHECKPOINT",
+	[T_Stat_REINDEX] = "REINDEX",
+	[T_Stat_CREATE_CONVERSION] = "CREATE CONVERSION",
+	[T_Stat_CREATE_CAST] = "CREATE CAST",
+	[T_Stat_CREATE_OPERATOR_CLASS] = "CREATE OPERATOR CLASS",
+	[T_Stat_CREATE_OPERATOR_FAMILY] = "CREATE OPERATOR FAMILY",
+	[T_Stat_CREATE_POLICY] = "CREATE POLICY",
+	[T_Stat_CREATE_PUBLICATION] = "CREATE PUBLICATION",
+	[T_Stat_CREATE_SUBSCRIPTION] = "CREATE SUBSCRIPTION",
+	[T_Stat_DROP_SUBSCRIPTION] = "DROP SUBSCRIPTION",
+	[T_Stat_PREPARE] = "PREPARE",
+	[T_Stat_EXECUTE] = "EXECUTE",
+	[T_Stat_CREATE_STATISTICS] = "CREATE STATISTICS",
+	[T_Stat_DEALLOCATE_ALL] = "DEALLOCATE ALL",
+	[T_Stat_DEALLOCATE] = "DEALLOCATE",
+	[T_Stat_SELECT_FOR_KEY_SHARE] = "SELECT FOR KEY SHARE",
+	[T_Stat_SELECT_FOR_SHARE] = "SELECT FOR SHARE",
+	[T_Stat_SELECT_FOR_NO_KEY_UPDATE] = "SELECT FOR NO KEY UPDATE",
+	[T_Stat_SELECT_FOR_UPDATE] = "SELECT FOR UPDATE",
+	[T_Stat_UNKNOWN] = "???"
+};
+
+
 
 /*
  * CommandIsReadOnly: is an executable query read-only?
@@ -1939,13 +2126,13 @@ UtilityContainsQuery(Node *parsetree)
 
 
 /*
- * AlterObjectTypeCommandTag
- *		helper function for CreateCommandTag
+ * AlterObjectTypeCommandTagType
+ *		helper function for CreateCommandTagType
  *
  * This covers most cases where ALTER is used with an ObjectType enum.
  */
 static const char *
-AlterObjectTypeCommandTag(ObjectType objtype)
+AlterObjectTypeCommandTagType(ObjectType objtype, StatSqlType* pESqlType)
 {
 	const char *tag;
 
@@ -1953,128 +2140,169 @@ AlterObjectTypeCommandTag(ObjectType objtype)
 	{
 		case OBJECT_AGGREGATE:
 			tag = "ALTER AGGREGATE";
+			*pESqlType = T_Stat_ALTER_AGGREGATE;
 			break;
 		case OBJECT_ATTRIBUTE:
 			tag = "ALTER TYPE";
+			*pESqlType = T_Stat_ALTER_TYPE;
 			break;
 		case OBJECT_CAST:
 			tag = "ALTER CAST";
+			*pESqlType = T_Stat_ALTER_CAST;
 			break;
 		case OBJECT_COLLATION:
 			tag = "ALTER COLLATION";
+			*pESqlType = T_Stat_ALTER_COLLATION;
 			break;
 		case OBJECT_COLUMN:
 			tag = "ALTER TABLE";
+			*pESqlType = T_Stat_ALTER_TABLE;
 			break;
 		case OBJECT_CONVERSION:
 			tag = "ALTER CONVERSION";
+			*pESqlType = T_Stat_ALTER_CONVERSION;
 			break;
 		case OBJECT_DATABASE:
 			tag = "ALTER DATABASE";
+			*pESqlType = T_Stat_ALTER_DATABASE;
 			break;
 		case OBJECT_DOMAIN:
 		case OBJECT_DOMCONSTRAINT:
 			tag = "ALTER DOMAIN";
+			*pESqlType = T_Stat_ALTER_DOMAIN;
 			break;
 		case OBJECT_EXTENSION:
 			tag = "ALTER EXTENSION";
+			*pESqlType = T_Stat_ALTER_EXTENSION;
 			break;
 		case OBJECT_FDW:
 			tag = "ALTER FOREIGN DATA WRAPPER";
+			*pESqlType = T_Stat_ALTER_FOREIGN_DATA_WRAPPER;
 			break;
 		case OBJECT_FOREIGN_SERVER:
 			tag = "ALTER SERVER";
+			*pESqlType = T_Stat_ALTER_SERVER;
 			break;
 		case OBJECT_FOREIGN_TABLE:
 			tag = "ALTER FOREIGN TABLE";
+			*pESqlType = T_Stat_ALTER_FOREIGN_TABLE;
 			break;
 		case OBJECT_FUNCTION:
 			tag = "ALTER FUNCTION";
+			*pESqlType = T_Stat_ALTER_FUNCTION;
 			break;
 		case OBJECT_INDEX:
 			tag = "ALTER INDEX";
+			*pESqlType = T_Stat_ALTER_INDEX;
 			break;
 		case OBJECT_LANGUAGE:
 			tag = "ALTER LANGUAGE";
+			*pESqlType = T_Stat_ALTER_LANGUAGE;
 			break;
 		case OBJECT_LARGEOBJECT:
 			tag = "ALTER LARGE OBJECT";
+			*pESqlType = T_Stat_ALTER_LARGE_OBJECT;
 			break;
 		case OBJECT_OPCLASS:
 			tag = "ALTER OPERATOR CLASS";
+			*pESqlType = T_Stat_ALTER_OPERATOR_CLASS;
 			break;
 		case OBJECT_OPERATOR:
 			tag = "ALTER OPERATOR";
+			*pESqlType = T_Stat_ALTER_OPERATOR;
 			break;
 		case OBJECT_OPFAMILY:
 			tag = "ALTER OPERATOR FAMILY";
+			*pESqlType = T_Stat_ALTER_OPERATOR_FAMILY;
 			break;
 		case OBJECT_POLICY:
 			tag = "ALTER POLICY";
+			*pESqlType = T_Stat_ALTER_POLICY;
 			break;
 		case OBJECT_PROCEDURE:
 			tag = "ALTER PROCEDURE";
+			*pESqlType = T_Stat_ALTER_PROCEDURE;
 			break;
 		case OBJECT_ROLE:
 			tag = "ALTER ROLE";
+			*pESqlType = T_Stat_ALTER_ROLE;
 			break;
 		case OBJECT_ROUTINE:
 			tag = "ALTER ROUTINE";
+			*pESqlType = T_Stat_ALTER_ROUTINE;
 			break;
 		case OBJECT_RULE:
 			tag = "ALTER RULE";
+			*pESqlType = T_Stat_ALTER_RULE;
 			break;
 		case OBJECT_SCHEMA:
 			tag = "ALTER SCHEMA";
+			*pESqlType = T_Stat_ALTER_SCHEMA;
 			break;
 		case OBJECT_SEQUENCE:
 			tag = "ALTER SEQUENCE";
+			*pESqlType = T_Stat_ALTER_SEQUENCE;
 			break;
 		case OBJECT_TABLE:
 		case OBJECT_TABCONSTRAINT:
 			tag = "ALTER TABLE";
+			*pESqlType = T_Stat_ALTER_TABLE;
 			break;
 		case OBJECT_TABLESPACE:
 			tag = "ALTER TABLESPACE";
+			*pESqlType = T_Stat_ALTER_TABLESPACE;
 			break;
 		case OBJECT_TRIGGER:
 			tag = "ALTER TRIGGER";
+			*pESqlType = T_Stat_ALTER_TRIGGER;
 			break;
 		case OBJECT_EVENT_TRIGGER:
 			tag = "ALTER EVENT TRIGGER";
+			*pESqlType = T_Stat_ALTER_EVENT_TRIGGER;
 			break;
 		case OBJECT_TSCONFIGURATION:
 			tag = "ALTER TEXT SEARCH CONFIGURATION";
+			*pESqlType = T_Stat_ALTER_TEXT_SEARCH_CONFIGURATION;
 			break;
 		case OBJECT_TSDICTIONARY:
 			tag = "ALTER TEXT SEARCH DICTIONARY";
+			*pESqlType = T_Stat_ALTER_TEXT_SEARCH_DICTIONARY;
 			break;
 		case OBJECT_TSPARSER:
 			tag = "ALTER TEXT SEARCH PARSER";
+			*pESqlType = T_Stat_ALTER_TEXT_SEARCH_PARSER;
 			break;
 		case OBJECT_TSTEMPLATE:
 			tag = "ALTER TEXT SEARCH TEMPLATE";
+			*pESqlType = T_Stat_ALTER_TEXT_SEARCH_TEMPLATE;
 			break;
 		case OBJECT_TYPE:
 			tag = "ALTER TYPE";
+			*pESqlType = T_Stat_ALTER_TYPE;
 			break;
 		case OBJECT_VIEW:
 			tag = "ALTER VIEW";
+			*pESqlType = T_Stat_ALTER_VIEW;
 			break;
 		case OBJECT_MATVIEW:
 			tag = "ALTER MATERIALIZED VIEW";
+			*pESqlType = T_Stat_ALTER_MATERIALIZED_VIEW;
 			break;
 		case OBJECT_PUBLICATION:
 			tag = "ALTER PUBLICATION";
+			*pESqlType = T_Stat_ALTER_PUBLICATION;
 			break;
 		case OBJECT_SUBSCRIPTION:
 			tag = "ALTER SUBSCRIPTION";
+			*pESqlType = T_Stat_ALTER_SUBSCRIPTION;
 			break;
 		case OBJECT_STATISTIC_EXT:
 			tag = "ALTER STATISTICS";
+			*pESqlType = T_Stat_ALTER_STATISTICS;
 			break;
 		default:
 			tag = "???";
+			*pESqlType = T_Stat_UNKNOWN;
 			break;
 	}
 
@@ -2082,19 +2310,15 @@ AlterObjectTypeCommandTag(ObjectType objtype)
 }
 
 /*
- * CreateCommandTag
- *		utility to get a string representation of the command operation,
+ * CreateCommandType
+ *		utility to get a StatSqlType representation of the command operation,
  *		given either a raw (un-analyzed) parsetree, an analyzed Query,
  *		or a PlannedStmt.
- *
- * This must handle all command types, but since the vast majority
- * of 'em are utility commands, it seems sensible to keep it here.
- *
- * NB: all result strings must be shorter than COMPLETION_TAG_BUFSIZE.
- * Also, the result must point at a true constant (permanent storage).
+ *		This function is copy-and-modify from CreateCommandTag,
+ *		so if CreateCommandTag changed, this function should be changed accordingly.
  */
-const char *
-CreateCommandTag(Node *parsetree)
+const char*
+CreateCommandTagType(Node *parsetree, StatSqlType* pESqlType)
 {
 	const char *tag;
 
@@ -2102,24 +2326,28 @@ CreateCommandTag(Node *parsetree)
 	{
 			/* recurse if we're given a RawStmt */
 		case T_RawStmt:
-			tag = CreateCommandTag(((RawStmt *) parsetree)->stmt);
+			tag = CreateCommandTagType(((RawStmt *) parsetree)->stmt, pESqlType);
 			break;
 
 			/* raw plannable queries */
 		case T_InsertStmt:
 			tag = "INSERT";
+			*pESqlType = T_Stat_INSERT;
 			break;
 
 		case T_DeleteStmt:
 			tag = "DELETE";
+			*pESqlType = T_Stat_DELETE;
 			break;
 
 		case T_UpdateStmt:
 			tag = "UPDATE";
+			*pESqlType = T_Stat_UPDATE;
 			break;
 
 		case T_SelectStmt:
 			tag = "SELECT";
+			*pESqlType = T_Stat_SELECT;
 			break;
 
 			/* utility statements --- same whether raw or cooked */
@@ -2131,43 +2359,53 @@ CreateCommandTag(Node *parsetree)
 				{
 					case TRANS_STMT_BEGIN:
 						tag = "BEGIN";
+						*pESqlType = T_Stat_BEGIN;
 						break;
 
 					case TRANS_STMT_START:
 						tag = "START TRANSACTION";
+						*pESqlType = T_Stat_START_TRANSACTION;
 						break;
 
 					case TRANS_STMT_COMMIT:
 						tag = "COMMIT";
+						*pESqlType = T_Stat_COMMIT;
 						break;
 
 					case TRANS_STMT_ROLLBACK:
 					case TRANS_STMT_ROLLBACK_TO:
 						tag = "ROLLBACK";
+						*pESqlType = T_Stat_ROLLBACK;
 						break;
 
 					case TRANS_STMT_SAVEPOINT:
 						tag = "SAVEPOINT";
+						*pESqlType = T_Stat_SAVEPOINT;
 						break;
 
 					case TRANS_STMT_RELEASE:
 						tag = "RELEASE";
+						*pESqlType = T_Stat_RELEASE;
 						break;
 
 					case TRANS_STMT_PREPARE:
 						tag = "PREPARE TRANSACTION";
+						*pESqlType = T_Stat_PREPARE_TRANSACTION;
 						break;
 
 					case TRANS_STMT_COMMIT_PREPARED:
 						tag = "COMMIT PREPARED";
+						*pESqlType = T_Stat_COMMIT_PREPARED;
 						break;
 
 					case TRANS_STMT_ROLLBACK_PREPARED:
 						tag = "ROLLBACK PREPARED";
+						*pESqlType = T_Stat_ROLLBACK_PREPARED;
 						break;
 
 					default:
 						tag = "???";
+						*pESqlType = T_Stat_UNKNOWN;
 						break;
 				}
 			}
@@ -2175,6 +2413,7 @@ CreateCommandTag(Node *parsetree)
 
 		case T_DeclareCursorStmt:
 			tag = "DECLARE CURSOR";
+			*pESqlType = T_Stat_DECLARE_CURSOR;
 			break;
 
 		case T_ClosePortalStmt:
@@ -2182,90 +2421,114 @@ CreateCommandTag(Node *parsetree)
 				ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
 
 				if (stmt->portalname == NULL)
+				{
 					tag = "CLOSE CURSOR ALL";
+					*pESqlType = T_Stat_CLOSE_CURSOR_ALL;
+				}
 				else
+				{
 					tag = "CLOSE CURSOR";
+					*pESqlType = T_Stat_CLOSE_CURSOR;
+				}
 			}
 			break;
 
 		case T_FetchStmt:
 			{
 				FetchStmt  *stmt = (FetchStmt *) parsetree;
-
 				tag = (stmt->ismove) ? "MOVE" : "FETCH";
+				*pESqlType = (stmt->ismove) ? T_Stat_MOVE : T_Stat_FETCH;
 			}
 			break;
 
 		case T_CreateDomainStmt:
 			tag = "CREATE DOMAIN";
+			*pESqlType = T_Stat_CREATE_DOMAIN;
 			break;
 
 		case T_CreateSchemaStmt:
 			tag = "CREATE SCHEMA";
+			*pESqlType = T_Stat_CREATE_SCHEMA;
 			break;
 
 		case T_CreateStmt:
 			tag = "CREATE TABLE";
+			*pESqlType = T_Stat_CREATE_TABLE;
 			break;
 
 		case T_CreateTableSpaceStmt:
 			tag = "CREATE TABLESPACE";
+			*pESqlType = T_Stat_CREATE_TABLESPACE;
 			break;
 
 		case T_DropTableSpaceStmt:
 			tag = "DROP TABLESPACE";
+			*pESqlType = T_Stat_DROP_TABLESPACE;
 			break;
 
 		case T_AlterTableSpaceOptionsStmt:
 			tag = "ALTER TABLESPACE";
+			*pESqlType = T_Stat_ALTER_TABLESPACE;
 			break;
 
 		case T_CreateExtensionStmt:
 			tag = "CREATE EXTENSION";
+			*pESqlType = T_Stat_CREATE_EXTENSION;
 			break;
 
 		case T_AlterExtensionStmt:
 			tag = "ALTER EXTENSION";
+			*pESqlType = T_Stat_ALTER_EXTENSION;
 			break;
 
 		case T_AlterExtensionContentsStmt:
 			tag = "ALTER EXTENSION";
+			*pESqlType = T_Stat_ALTER_EXTENSION;
 			break;
 
 		case T_CreateFdwStmt:
 			tag = "CREATE FOREIGN DATA WRAPPER";
+			*pESqlType = T_Stat_CREATE_FOREIGN_DATA_WRAPPER;
 			break;
 
 		case T_AlterFdwStmt:
 			tag = "ALTER FOREIGN DATA WRAPPER";
+			*pESqlType = T_Stat_ALTER_FOREIGN_DATA_WRAPPER;
 			break;
 
 		case T_CreateForeignServerStmt:
 			tag = "CREATE SERVER";
+			*pESqlType = T_Stat_CREATE_SERVER;
 			break;
 
 		case T_AlterForeignServerStmt:
 			tag = "ALTER SERVER";
+			*pESqlType = T_Stat_ALTER_SERVER;
 			break;
 
 		case T_CreateUserMappingStmt:
 			tag = "CREATE USER MAPPING";
+			*pESqlType = T_Stat_CREATE_USER_MAPPING;
 			break;
 
 		case T_AlterUserMappingStmt:
 			tag = "ALTER USER MAPPING";
+			*pESqlType = T_Stat_ALTER_USER_MAPPING;
 			break;
 
 		case T_DropUserMappingStmt:
 			tag = "DROP USER MAPPING";
+			*pESqlType = T_Stat_DROP_USER_MAPPING;
 			break;
 
 		case T_CreateForeignTableStmt:
 			tag = "CREATE FOREIGN TABLE";
+			*pESqlType = T_Stat_CREATE_FOREIGN_TABLE;
 			break;
 
 		case T_ImportForeignSchemaStmt:
 			tag = "IMPORT FOREIGN SCHEMA";
+			*pESqlType = T_Stat_IMPORT_FOREIGN_SCHEMA;
 			break;
 
 		case T_DropStmt:
@@ -2273,128 +2536,168 @@ CreateCommandTag(Node *parsetree)
 			{
 				case OBJECT_TABLE:
 					tag = "DROP TABLE";
+					*pESqlType = T_Stat_DROP_TABLE;
 					break;
 				case OBJECT_SEQUENCE:
 					tag = "DROP SEQUENCE";
+					*pESqlType = T_Stat_DROP_SEQUENCE;
 					break;
 				case OBJECT_VIEW:
 					tag = "DROP VIEW";
+					*pESqlType = T_Stat_DROP_VIEW;
 					break;
 				case OBJECT_MATVIEW:
 					tag = "DROP MATERIALIZED VIEW";
+					*pESqlType = T_Stat_DROP_MATERIALIZED_VIEW;
 					break;
 				case OBJECT_INDEX:
 					tag = "DROP INDEX";
+					*pESqlType= T_Stat_DROP_INDEX;
 					break;
 				case OBJECT_TYPE:
 					tag = "DROP TYPE";
+					*pESqlType = T_Stat_DROP_TYPE;
 					break;
 				case OBJECT_DOMAIN:
 					tag = "DROP DOMAIN";
+					*pESqlType = T_Stat_DROP_DOMAIN;
 					break;
 				case OBJECT_COLLATION:
 					tag = "DROP COLLATION";
+					*pESqlType = T_Stat_DROP_COLLATION;
 					break;
 				case OBJECT_CONVERSION:
 					tag = "DROP CONVERSION";
+					*pESqlType = T_Stat_DROP_CONVERSION;
 					break;
 				case OBJECT_SCHEMA:
 					tag = "DROP SCHEMA";
+					*pESqlType = T_Stat_DROP_SCHEMA;
 					break;
 				case OBJECT_TSPARSER:
 					tag = "DROP TEXT SEARCH PARSER";
+					*pESqlType = T_Stat_DROP_TEXT_SEARCH_PARSER;
 					break;
 				case OBJECT_TSDICTIONARY:
 					tag = "DROP TEXT SEARCH DICTIONARY";
+					*pESqlType = T_Stat_DROP_TEXT_SEARCH_DICTIONARY;
 					break;
 				case OBJECT_TSTEMPLATE:
 					tag = "DROP TEXT SEARCH TEMPLATE";
+					*pESqlType = T_Stat_DROP_TEXT_SEARCH_TEMPLATE;
 					break;
 				case OBJECT_TSCONFIGURATION:
 					tag = "DROP TEXT SEARCH CONFIGURATION";
+					*pESqlType = T_Stat_DROP_DROP_TEXT_SEARCH_CONFIGURATION;
 					break;
 				case OBJECT_FOREIGN_TABLE:
 					tag = "DROP FOREIGN TABLE";
+					*pESqlType = T_Stat_DROP_DROP_FOREIGN_TABLE;
 					break;
 				case OBJECT_EXTENSION:
 					tag = "DROP EXTENSION";
+					*pESqlType = T_Stat_DROP_EXTENSION;
 					break;
 				case OBJECT_FUNCTION:
 					tag = "DROP FUNCTION";
+					*pESqlType = T_Stat_DROP_FUNCTION;
 					break;
 				case OBJECT_PROCEDURE:
 					tag = "DROP PROCEDURE";
+					*pESqlType = T_Stat_DROP_PROCEDURE;
 					break;
 				case OBJECT_ROUTINE:
 					tag = "DROP ROUTINE";
+					*pESqlType = T_Stat_DROP_ROUTINE;
 					break;
 				case OBJECT_AGGREGATE:
 					tag = "DROP AGGREGATE";
+					*pESqlType = T_Stat_DROP_AGGREGATE;
 					break;
 				case OBJECT_OPERATOR:
 					tag = "DROP OPERATOR";
+					*pESqlType = T_Stat_DROP_OPERATOR;
 					break;
 				case OBJECT_LANGUAGE:
 					tag = "DROP LANGUAGE";
+					*pESqlType = T_Stat_DROP_LANGUAGE;
 					break;
 				case OBJECT_CAST:
 					tag = "DROP CAST";
+					*pESqlType = T_Stat_DROP_CAST;
 					break;
 				case OBJECT_TRIGGER:
 					tag = "DROP TRIGGER";
+					*pESqlType = T_Stat_DROP_TRIGGER;
 					break;
 				case OBJECT_EVENT_TRIGGER:
 					tag = "DROP EVENT TRIGGER";
+					*pESqlType = T_Stat_DROP_EVENT_TRIGGER;
 					break;
 				case OBJECT_RULE:
 					tag = "DROP RULE";
+					*pESqlType = T_Stat_DROP_RULE;
 					break;
 				case OBJECT_FDW:
 					tag = "DROP FOREIGN DATA WRAPPER";
+					*pESqlType = T_Stat_DROP_FOREIGN_DATA_WRAPPER;
 					break;
 				case OBJECT_FOREIGN_SERVER:
 					tag = "DROP SERVER";
+					*pESqlType = T_Stat_DROP_SERVER;
 					break;
 				case OBJECT_OPCLASS:
 					tag = "DROP OPERATOR CLASS";
+					*pESqlType = T_Stat_DROP_OPERATOR_CLASS;
 					break;
 				case OBJECT_OPFAMILY:
 					tag = "DROP OPERATOR FAMILY";
+					*pESqlType = T_Stat_DROP_OPERATOR_FAMILY;
 					break;
 				case OBJECT_POLICY:
 					tag = "DROP POLICY";
+					*pESqlType = T_Stat_DROP_POLICY;
 					break;
 				case OBJECT_TRANSFORM:
 					tag = "DROP TRANSFORM";
+					*pESqlType = T_Stat_DROP_TRANSFORM;
 					break;
 				case OBJECT_ACCESS_METHOD:
 					tag = "DROP ACCESS METHOD";
+					*pESqlType = T_Stat_DROP_ACCESS_METHOD;
 					break;
 				case OBJECT_PUBLICATION:
 					tag = "DROP PUBLICATION";
+					*pESqlType = T_Stat_DROP_PUBLICATION;
 					break;
 				case OBJECT_STATISTIC_EXT:
 					tag = "DROP STATISTICS";
+					*pESqlType = T_Stat_DROP_STATISTICS;
 					break;
 				default:
 					tag = "???";
+					*pESqlType = T_Stat_UNKNOWN;
 			}
 			break;
 
 		case T_TruncateStmt:
 			tag = "TRUNCATE TABLE";
+			*pESqlType = T_Stat_TRUNCATE_TABLE;
 			break;
 
 		case T_CommentStmt:
 			tag = "COMMENT";
+			*pESqlType = T_Stat_TRUNCATE_TABLE;
 			break;
 
 		case T_SecLabelStmt:
 			tag = "SECURITY LABEL";
+			*pESqlType = T_Stat_SECURITY_LABEL;
 			break;
 
 		case T_CopyStmt:
 			tag = "COPY";
+			*pESqlType = T_Stat_COPY;
 			break;
 
 		case T_RenameStmt:
@@ -2402,34 +2705,35 @@ CreateCommandTag(Node *parsetree)
 			 * When the column is renamed, the command tag is created
 			 * from its relation type
 			 */
-			tag = AlterObjectTypeCommandTag(
+			tag = AlterObjectTypeCommandTagType(
 				((RenameStmt *) parsetree)->renameType == OBJECT_COLUMN ?
 				((RenameStmt *) parsetree)->relationType :
-				((RenameStmt *) parsetree)->renameType);
+				((RenameStmt *) parsetree)->renameType, pESqlType);
 			break;
 
 		case T_AlterObjectDependsStmt:
-			tag = AlterObjectTypeCommandTag(((AlterObjectDependsStmt *) parsetree)->objectType);
+			tag = AlterObjectTypeCommandTagType(((AlterObjectDependsStmt *) parsetree)->objectType, pESqlType);
 			break;
 
 		case T_AlterObjectSchemaStmt:
-			tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType);
+			tag = AlterObjectTypeCommandTagType(((AlterObjectSchemaStmt *) parsetree)->objectType, pESqlType);
 			break;
 
 		case T_AlterOwnerStmt:
-			tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType);
+			tag = AlterObjectTypeCommandTagType(((AlterOwnerStmt *) parsetree)->objectType, pESqlType);
 			break;
 
 		case T_AlterTableMoveAllStmt:
-			tag = AlterObjectTypeCommandTag(((AlterTableMoveAllStmt *) parsetree)->objtype);
+			tag = AlterObjectTypeCommandTagType(((AlterTableMoveAllStmt *) parsetree)->objtype, pESqlType);
 			break;
 
 		case T_AlterTableStmt:
-			tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind);
+			tag = AlterObjectTypeCommandTagType(((AlterTableStmt *) parsetree)->relkind, pESqlType);
 			break;
 
 		case T_AlterDomainStmt:
 			tag = "ALTER DOMAIN";
+			*pESqlType = T_Stat_ALTER_DOMAIN;
 			break;
 
 		case T_AlterFunctionStmt:
@@ -2437,15 +2741,19 @@ CreateCommandTag(Node *parsetree)
 			{
 				case OBJECT_FUNCTION:
 					tag = "ALTER FUNCTION";
+					*pESqlType = T_Stat_ALTER_FUNCTION;
 					break;
 				case OBJECT_PROCEDURE:
 					tag = "ALTER PROCEDURE";
+					*pESqlType = T_Stat_ALTER_PROCEDURE;
 					break;
 				case OBJECT_ROUTINE:
 					tag = "ALTER ROUTINE";
+					*pESqlType = T_Stat_ALTER_ROUTINE;
 					break;
 				default:
 					tag = "???";
+					*pESqlType = T_Stat_UNKNOWN;
 			}
 			break;
 
@@ -2454,6 +2762,7 @@ CreateCommandTag(Node *parsetree)
 				GrantStmt  *stmt = (GrantStmt *) parsetree;
 
 				tag = (stmt->is_grant) ? "GRANT" : "REVOKE";
+				*pESqlType = (stmt->is_grant) ? T_Stat_GRANT : T_Stat_REVOKE;
 			}
 			break;
 
@@ -2462,11 +2771,13 @@ CreateCommandTag(Node *parsetree)
 				GrantRoleStmt *stmt = (GrantRoleStmt *) parsetree;
 
 				tag = (stmt->is_grant) ? "GRANT ROLE" : "REVOKE ROLE";
+				*pESqlType = (stmt->is_grant) ? T_Stat_GRANT_ROLE : T_Stat_REVOKE_ROLE;
 			}
 			break;
 
 		case T_AlterDefaultPrivilegesStmt:
 			tag = "ALTER DEFAULT PRIVILEGES";
+			*pESqlType = T_Stat_ALTER_DEFAULT_PRIVILEGES;
 			break;
 
 		case T_DefineStmt:
@@ -2474,132 +2785,175 @@ CreateCommandTag(Node *parsetree)
 			{
 				case OBJECT_AGGREGATE:
 					tag = "CREATE AGGREGATE";
+					*pESqlType = T_Stat_CREATE_AGGREGATE;
 					break;
 				case OBJECT_OPERATOR:
 					tag = "CREATE OPERATOR";
+					*pESqlType = T_Stat_CREATE_OPERATOR;
 					break;
 				case OBJECT_TYPE:
 					tag = "CREATE TYPE";
+					*pESqlType = T_Stat_CREATE_TYPE;
 					break;
 				case OBJECT_TSPARSER:
 					tag = "CREATE TEXT SEARCH PARSER";
+					*pESqlType = T_Stat_CREATE_TEXT_SEARCH_PARSER;
 					break;
 				case OBJECT_TSDICTIONARY:
 					tag = "CREATE TEXT SEARCH DICTIONARY";
+					*pESqlType = T_Stat_CREATE_TEXT_SEARCH_DICTIONARY;
 					break;
 				case OBJECT_TSTEMPLATE:
 					tag = "CREATE TEXT SEARCH TEMPLATE";
+					*pESqlType = T_Stat_CREATE_TEXT_SEARCH_TEMPLATE;
 					break;
 				case OBJECT_TSCONFIGURATION:
 					tag = "CREATE TEXT SEARCH CONFIGURATION";
+					*pESqlType = T_Stat_CREATE_TEXT_SEARCH_CONFIGURATION;
 					break;
 				case OBJECT_COLLATION:
 					tag = "CREATE COLLATION";
+					*pESqlType = T_Stat_CREATE_COLLATION;
 					break;
 				case OBJECT_ACCESS_METHOD:
 					tag = "CREATE ACCESS METHOD";
+					*pESqlType = T_Stat_CREATE_ACCESS_METHOD;
 					break;
 				default:
 					tag = "???";
+					*pESqlType = T_Stat_UNKNOWN;
 			}
 			break;
 
 		case T_CompositeTypeStmt:
 			tag = "CREATE TYPE";
+			*pESqlType = T_Stat_CREATE_TYPE;
 			break;
 
 		case T_CreateEnumStmt:
 			tag = "CREATE TYPE";
+			*pESqlType = T_Stat_CREATE_TYPE;
 			break;
 
 		case T_CreateRangeStmt:
 			tag = "CREATE TYPE";
+			*pESqlType = T_Stat_CREATE_TYPE;
 			break;
 
 		case T_AlterEnumStmt:
 			tag = "ALTER TYPE";
+			*pESqlType = T_Stat_ALTER_TYPE;
 			break;
 
 		case T_ViewStmt:
 			tag = "CREATE VIEW";
+			*pESqlType = T_Stat_CREATE_VIEW;
 			break;
 
 		case T_CreateFunctionStmt:
 			if (((CreateFunctionStmt *) parsetree)->is_procedure)
+			{
 				tag = "CREATE PROCEDURE";
+				*pESqlType = T_Stat_CREATE_PROCEDURE;
+			}
 			else
+			{
 				tag = "CREATE FUNCTION";
+				*pESqlType = T_Stat_CREATE_FUNCTION;
+			}
 			break;
 
 		case T_IndexStmt:
 			tag = "CREATE INDEX";
+			*pESqlType = T_Stat_CREATE_INDEX;
 			break;
 
 		case T_RuleStmt:
 			tag = "CREATE RULE";
+			*pESqlType = T_Stat_CREATE_RULE;
 			break;
 
 		case T_CreateSeqStmt:
 			tag = "CREATE SEQUENCE";
+			*pESqlType = T_Stat_CREATE_SEQUENCE;
 			break;
 
 		case T_AlterSeqStmt:
 			tag = "ALTER SEQUENCE";
+			*pESqlType = T_Stat_ALTER_SEQUENCE;
 			break;
 
 		case T_DoStmt:
 			tag = "DO";
+			*pESqlType = T_Stat_DO;
 			break;
 
 		case T_CreatedbStmt:
 			tag = "CREATE DATABASE";
+			*pESqlType = T_Stat_CREATE_DATABASE;
 			break;
 
 		case T_AlterDatabaseStmt:
 			tag = "ALTER DATABASE";
+			*pESqlType = T_Stat_ALTER_DATABASE;
 			break;
 
 		case T_AlterDatabaseSetStmt:
 			tag = "ALTER DATABASE";
+			*pESqlType = T_Stat_ALTER_DATABASE;
 			break;
 
 		case T_DropdbStmt:
 			tag = "DROP DATABASE";
+			*pESqlType = T_Stat_DROP_DATABASE;
 			break;
 
 		case T_NotifyStmt:
 			tag = "NOTIFY";
+			*pESqlType = T_Stat_NOTIFY;
 			break;
 
 		case T_ListenStmt:
 			tag = "LISTEN";
+			*pESqlType = T_Stat_LISTEN;
 			break;
 
 		case T_UnlistenStmt:
 			tag = "UNLISTEN";
+			*pESqlType = T_Stat_UNLISTEN;
 			break;
 
 		case T_LoadStmt:
 			tag = "LOAD";
+			*pESqlType = T_Stat_LOAD;
 			break;
 
 		case T_CallStmt:
 			tag = "CALL";
+			*pESqlType = T_Stat_CALL;
 			break;
 
 		case T_ClusterStmt:
 			tag = "CLUSTER";
+			*pESqlType = T_Stat_CLUSTER;
 			break;
 
 		case T_VacuumStmt:
 			if (((VacuumStmt *) parsetree)->is_vacuumcmd)
+			{
 				tag = "VACUUM";
+				*pESqlType = T_Stat_VACUUM;
+			}
 			else
+			{
 				tag = "ANALYZE";
+				*pESqlType = T_Stat_ANALYZE;
+			}
 			break;
 
 		case T_ExplainStmt:
 			tag = "EXPLAIN";
+			*pESqlType = T_Stat_EXPLAIN;
 			break;
 
 		case T_CreateTableAsStmt:
@@ -2607,24 +2961,34 @@ CreateCommandTag(Node *parsetree)
 			{
 				case OBJECT_TABLE:
 					if (((CreateTableAsStmt *) parsetree)->is_select_into)
+					{
 						tag = "SELECT INTO";
+						*pESqlType = T_Stat_SELECT_INTO;
+					}
 					else
+					{
 						tag = "CREATE TABLE AS";
+						*pESqlType = T_Stat_CREATE_TABLE_AS;
+					}
 					break;
 				case OBJECT_MATVIEW:
 					tag = "CREATE MATERIALIZED VIEW";
+					*pESqlType = T_Stat_CREATE_MATERIALIZED_VIEW;
 					break;
 				default:
 					tag = "???";
+					*pESqlType = T_Stat_UNKNOWN;
 			}
 			break;
 
 		case T_RefreshMatViewStmt:
 			tag = "REFRESH MATERIALIZED VIEW";
+			*pESqlType = T_Stat_REFRESH_MATERIALIZED_VIEW;
 			break;
 
 		case T_AlterSystemStmt:
 			tag = "ALTER SYSTEM";
+			*pESqlType = T_Stat_ALTER_SYSTEM;
 			break;
 
 		case T_VariableSetStmt:
@@ -2635,18 +2999,22 @@ CreateCommandTag(Node *parsetree)
 				case VAR_SET_DEFAULT:
 				case VAR_SET_MULTI:
 					tag = "SET";
+					*pESqlType = T_Stat_SET;
 					break;
 				case VAR_RESET:
 				case VAR_RESET_ALL:
 					tag = "RESET";
+					*pESqlType = T_Stat_RESET;
 					break;
 				default:
 					tag = "???";
+					*pESqlType = T_Stat_UNKNOWN;
 			}
 			break;
 
 		case T_VariableShowStmt:
 			tag = "SHOW";
+			*pESqlType = T_Stat_SHOW;
 			break;
 
 		case T_DiscardStmt:
@@ -2654,163 +3022,204 @@ CreateCommandTag(Node *parsetree)
 			{
 				case DISCARD_ALL:
 					tag = "DISCARD ALL";
+					*pESqlType = T_Stat_DISCARD_ALL;
 					break;
 				case DISCARD_PLANS:
 					tag = "DISCARD PLANS";
+					*pESqlType = T_Stat_DISCARD_PLANS;
 					break;
 				case DISCARD_TEMP:
 					tag = "DISCARD TEMP";
+					*pESqlType = T_Stat_DISCARD_TEMP;
 					break;
 				case DISCARD_SEQUENCES:
 					tag = "DISCARD SEQUENCES";
+					*pESqlType = T_Stat_DISCARD_SEQUENCES;
 					break;
 				default:
 					tag = "???";
+					*pESqlType = T_Stat_UNKNOWN;
 			}
 			break;
 
 		case T_CreateTransformStmt:
 			tag = "CREATE TRANSFORM";
+			*pESqlType = T_Stat_CREATE_TRANSFORM;
 			break;
 
 		case T_CreateTrigStmt:
 			tag = "CREATE TRIGGER";
+			*pESqlType = T_Stat_CREATE_TRIGGER;
 			break;
 
 		case T_CreateEventTrigStmt:
 			tag = "CREATE EVENT TRIGGER";
+			*pESqlType = T_Stat_CREATE_EVENT_TRIGGER;
 			break;
 
 		case T_AlterEventTrigStmt:
 			tag = "ALTER EVENT TRIGGER";
+			*pESqlType = T_Stat_ALTER_EVENT_TRIGGER;
 			break;
 
 		case T_CreatePLangStmt:
 			tag = "CREATE LANGUAGE";
+			*pESqlType = T_Stat_CREATE_LANGUAGE;
 			break;
 
 		case T_CreateRoleStmt:
 			tag = "CREATE ROLE";
+			*pESqlType = T_Stat_CREATE_ROLE;
 			break;
 
 		case T_AlterRoleStmt:
 			tag = "ALTER ROLE";
+			*pESqlType = T_Stat_ALTER_ROLE;
 			break;
 
 		case T_AlterRoleSetStmt:
 			tag = "ALTER ROLE";
+			*pESqlType = T_Stat_ALTER_ROLE;
 			break;
 
 		case T_DropRoleStmt:
 			tag = "DROP ROLE";
+			*pESqlType = T_Stat_DROP_ROLE;
 			break;
 
 		case T_DropOwnedStmt:
 			tag = "DROP OWNED";
+			*pESqlType = T_Stat_DROP_OWNED;
 			break;
 
 		case T_ReassignOwnedStmt:
 			tag = "REASSIGN OWNED";
+			*pESqlType = T_Stat_REASSIGN_OWNED;
 			break;
 
 		case T_LockStmt:
 			tag = "LOCK TABLE";
+			*pESqlType = T_Stat_LOCK_TABLE;
 			break;
 
 		case T_ConstraintsSetStmt:
 			tag = "SET CONSTRAINTS";
+			*pESqlType = T_Stat_SET_CONSTRAINTS;
 			break;
 
 		case T_CheckPointStmt:
 			tag = "CHECKPOINT";
+			*pESqlType = T_Stat_CHECKPOINT;
 			break;
 
 		case T_ReindexStmt:
 			tag = "REINDEX";
+			*pESqlType = T_Stat_REINDEX;
 			break;
 
 		case T_CreateConversionStmt:
 			tag = "CREATE CONVERSION";
+			*pESqlType = T_Stat_CREATE_CONVERSION;
 			break;
 
 		case T_CreateCastStmt:
 			tag = "CREATE CAST";
+			*pESqlType = T_Stat_CREATE_CAST;
 			break;
 
 		case T_CreateOpClassStmt:
 			tag = "CREATE OPERATOR CLASS";
+			*pESqlType = T_Stat_CREATE_OPERATOR_CLASS;
 			break;
 
 		case T_CreateOpFamilyStmt:
 			tag = "CREATE OPERATOR FAMILY";
+			*pESqlType = T_Stat_CREATE_OPERATOR_FAMILY;
 			break;
 
 		case T_AlterOpFamilyStmt:
 			tag = "ALTER OPERATOR FAMILY";
+			*pESqlType = T_Stat_ALTER_OPERATOR_FAMILY;
 			break;
 
 		case T_AlterOperatorStmt:
 			tag = "ALTER OPERATOR";
+			*pESqlType = T_Stat_ALTER_OPERATOR;
 			break;
 
 		case T_AlterTSDictionaryStmt:
 			tag = "ALTER TEXT SEARCH DICTIONARY";
+			*pESqlType = T_Stat_ALTER_TEXT_SEARCH_DICTIONARY;
 			break;
 
 		case T_AlterTSConfigurationStmt:
 			tag = "ALTER TEXT SEARCH CONFIGURATION";
+			*pESqlType = T_Stat_ALTER_TEXT_SEARCH_CONFIGURATION;
 			break;
 
 		case T_CreatePolicyStmt:
 			tag = "CREATE POLICY";
+			*pESqlType = T_Stat_CREATE_POLICY;
 			break;
 
 		case T_AlterPolicyStmt:
 			tag = "ALTER POLICY";
+			*pESqlType = T_Stat_ALTER_POLICY;
 			break;
 
 		case T_CreateAmStmt:
 			tag = "CREATE ACCESS METHOD";
+			*pESqlType = T_Stat_CREATE_ACCESS_METHOD;
 			break;
 
 		case T_CreatePublicationStmt:
 			tag = "CREATE PUBLICATION";
+			*pESqlType = T_Stat_CREATE_PUBLICATION;
 			break;
 
 		case T_AlterPublicationStmt:
 			tag = "ALTER PUBLICATION";
+			*pESqlType = T_Stat_ALTER_PUBLICATION;
 			break;
 
 		case T_CreateSubscriptionStmt:
 			tag = "CREATE SUBSCRIPTION";
+			*pESqlType = T_Stat_CREATE_SUBSCRIPTION;
 			break;
 
 		case T_AlterSubscriptionStmt:
 			tag = "ALTER SUBSCRIPTION";
+			*pESqlType = T_Stat_ALTER_SUBSCRIPTION;
 			break;
 
 		case T_DropSubscriptionStmt:
 			tag = "DROP SUBSCRIPTION";
+			*pESqlType = T_Stat_DROP_SUBSCRIPTION;
 			break;
 
 		case T_AlterCollationStmt:
 			tag = "ALTER COLLATION";
+			*pESqlType = T_Stat_ALTER_COLLATION;
 			break;
 
 		case T_PrepareStmt:
 			tag = "PREPARE";
+			*pESqlType = T_Stat_PREPARE;
 			break;
 
 		case T_ExecuteStmt:
 			tag = "EXECUTE";
+			*pESqlType = T_Stat_EXECUTE;
 			break;
 
 		case T_CreateStatsStmt:
 			tag = "CREATE STATISTICS";
+			*pESqlType = T_Stat_CREATE_STATISTICS;
 			break;
 
 		case T_AlterStatsStmt:
 			tag = "ALTER STATISTICS";
+			*pESqlType = T_Stat_ALTER_STATISTICS;
 			break;
 
 		case T_DeallocateStmt:
@@ -2818,9 +3227,15 @@ CreateCommandTag(Node *parsetree)
 				DeallocateStmt *stmt = (DeallocateStmt *) parsetree;
 
 				if (stmt->name == NULL)
+				{
 					tag = "DEALLOCATE ALL";
+					*pESqlType = T_Stat_DEALLOCATE_ALL;
+				}
 				else
+				{
 					tag = "DEALLOCATE";
+					*pESqlType = T_Stat_DEALLOCATE;
+				}
 			}
 			break;
 
@@ -2845,40 +3260,50 @@ CreateCommandTag(Node *parsetree)
 							{
 								case LCS_FORKEYSHARE:
 									tag = "SELECT FOR KEY SHARE";
+									*pESqlType = T_Stat_SELECT_FOR_KEY_SHARE;
 									break;
 								case LCS_FORSHARE:
 									tag = "SELECT FOR SHARE";
+									*pESqlType = T_Stat_SELECT_FOR_SHARE;
 									break;
 								case LCS_FORNOKEYUPDATE:
 									tag = "SELECT FOR NO KEY UPDATE";
+									*pESqlType = T_Stat_SELECT_FOR_NO_KEY_UPDATE;
 									break;
 								case LCS_FORUPDATE:
 									tag = "SELECT FOR UPDATE";
+									*pESqlType = T_Stat_SELECT_FOR_UPDATE;
 									break;
 								default:
 									tag = "SELECT";
+									*pESqlType = T_Stat_SELECT;
 									break;
 							}
 						}
 						else
 							tag = "SELECT";
+							*pESqlType = T_Stat_SELECT;
 						break;
 					case CMD_UPDATE:
 						tag = "UPDATE";
+						*pESqlType = T_Stat_UPDATE;
 						break;
 					case CMD_INSERT:
 						tag = "INSERT";
+						*pESqlType = T_Stat_INSERT;
 						break;
 					case CMD_DELETE:
 						tag = "DELETE";
+						*pESqlType = T_Stat_DELETE;
 						break;
 					case CMD_UTILITY:
-						tag = CreateCommandTag(stmt->utilityStmt);
+						tag = CreateCommandTagType(stmt->utilityStmt, pESqlType);
 						break;
 					default:
 						elog(WARNING, "unrecognized commandType: %d",
 							 (int) stmt->commandType);
 						tag = "???";
+						*pESqlType = T_Stat_UNKNOWN;
 						break;
 				}
 			}
@@ -2905,40 +3330,50 @@ CreateCommandTag(Node *parsetree)
 							{
 								case LCS_FORKEYSHARE:
 									tag = "SELECT FOR KEY SHARE";
+									*pESqlType = T_Stat_SELECT_FOR_KEY_SHARE;
 									break;
 								case LCS_FORSHARE:
 									tag = "SELECT FOR SHARE";
+									*pESqlType = T_Stat_SELECT_FOR_SHARE;
 									break;
 								case LCS_FORNOKEYUPDATE:
 									tag = "SELECT FOR NO KEY UPDATE";
+									*pESqlType = T_Stat_SELECT_FOR_NO_KEY_UPDATE;
 									break;
 								case LCS_FORUPDATE:
 									tag = "SELECT FOR UPDATE";
+									*pESqlType = T_Stat_SELECT_FOR_UPDATE;
 									break;
 								default:
 									tag = "???";
+									*pESqlType = T_Stat_UNKNOWN;
 									break;
 							}
 						}
 						else
 							tag = "SELECT";
+							*pESqlType = T_Stat_SELECT;
 						break;
 					case CMD_UPDATE:
 						tag = "UPDATE";
+						*pESqlType = T_Stat_UPDATE;
 						break;
 					case CMD_INSERT:
 						tag = "INSERT";
+						*pESqlType = T_Stat_INSERT;
 						break;
 					case CMD_DELETE:
 						tag = "DELETE";
+						*pESqlType = T_Stat_DELETE;
 						break;
 					case CMD_UTILITY:
-						tag = CreateCommandTag(stmt->utilityStmt);
+						tag = CreateCommandTagType(stmt->utilityStmt, pESqlType);
 						break;
 					default:
 						elog(WARNING, "unrecognized commandType: %d",
 							 (int) stmt->commandType);
 						tag = "???";
+						*pESqlType = T_Stat_UNKNOWN;
 						break;
 				}
 			}
@@ -2948,6 +3383,7 @@ CreateCommandTag(Node *parsetree)
 			elog(WARNING, "unrecognized node type: %d",
 				 (int) nodeTag(parsetree));
 			tag = "???";
+			*pESqlType = T_Stat_UNKNOWN;
 			break;
 	}
 
@@ -2956,6 +3392,45 @@ CreateCommandTag(Node *parsetree)
 
 
 /*
+ * CreateCommandTag
+ *		utility to get a string representation of the command operation,
+ *		given either a raw (un-analyzed) parsetree, an analyzed Query,
+ *		or a PlannedStmt.
+ *
+ * This must handle all command types, but since the vast majority
+ * of 'em are utility commands, it seems sensible to keep it here.
+ *
+ * NB: all result strings must be shorter than COMPLETION_TAG_BUFSIZE.
+ * Also, the result must point at a true constant (permanent storage).
+ */
+const char *
+CreateCommandTag(Node *parsetree)
+{
+	StatSqlType eType;
+	return CreateCommandTagType(parsetree, &eType);
+}
+
+
+/*
+ * CreateCommandType
+ *		utility to get a enum representation of the command operation,
+ *		given either a raw (un-analyzed) parsetree, an analyzed Query,
+ *		or a PlannedStmt.
+ *
+ * This must handle all command types, but since the vast majority
+ * of 'em are utility commands, it seems sensible to keep it here.
+ *
+ */
+StatSqlType
+CreateCommandType(Node *parsetree)
+{
+	StatSqlType eType;
+	CreateCommandTagType(parsetree, &eType);
+	return eType;
+}
+
+
+/*
  * GetCommandLogLevel
  *		utility to get the minimum log_statement level for a command,
  *		given either a raw (un-analyzed) parsetree, an analyzed Query,
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 05240bf..7618de7 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1970,3 +1970,64 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 	PG_RETURN_DATUM(HeapTupleGetDatum(
 									  heap_form_tuple(tupdesc, values, nulls)));
 }
+
+Datum
+pg_stat_sql(PG_FUNCTION_ARGS)
+{
+	TupleDesc	tupdesc;
+	Datum		values[2] = { 0, 0 };
+	bool		nulls[2] = { false, false };
+	ReturnSetInfo *rsi;
+	MemoryContext old_cxt;
+	Tuplestorestate *tuple_store;
+
+	/* Function call to let the backend read the stats file */
+	pgstat_fetch_global();
+
+	rsi = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	/* Check to see if caller supports us returning a tuplestore */
+	if (rsi == NULL || !IsA(rsi, ReturnSetInfo))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("set-valued function called in context that cannot accept a set")));
+	if (!(rsi->allowedModes & SFRM_Materialize))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("materialize mode required, but it is not " \
+						"allowed in this context")));
+
+	rsi->returnMode = SFRM_Materialize;
+
+	/* Build a tuple descriptor for our result type */
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
+
+	/* Build tuplestore to hold the result rows */
+	old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
+
+	tuple_store =
+		tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
+							  false, work_mem);
+	rsi->setDesc = tupdesc;
+	rsi->setResult = tuple_store;
+
+	MemoryContextSwitchTo(old_cxt);
+
+	for (int i = 0; i < PGSTAT_SQLSTMT_SIZE; i++)
+	{
+		HeapTuple	tuple;
+
+		if (pgstat_sql_counts[i] == 0)
+			continue;
+
+		/* Fill values and NULLs */
+		values[0] = CStringGetTextDatum(g_str_sql_type[i]);
+		values[1] = Int64GetDatum(pgstat_sql_counts[i]);
+
+		tuple = heap_form_tuple(tupdesc, values, nulls);
+		tuplestore_puttuple(tuple_store, tuple);
+	}
+
+	PG_RETURN_NULL();
+}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 4b3769b..22154d1 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1413,7 +1413,15 @@ static struct config_bool ConfigureNamesBool[] =
 		false,
 		NULL, NULL, NULL
 	},
-
+	{
+		{"track_statement_statistics", PGC_SUSET, STATS_COLLECTOR,
+			gettext_noop("Collects the counters of SQL statments."),
+			NULL
+		},
+		&pgstat_track_statement_statistics,
+		false,
+		NULL, NULL, NULL
+	},
 	{
 		{"update_process_title", PGC_SUSET, PROCESS_TITLE,
 			gettext_noop("Updates the process title to show the active SQL command."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index be02a76..4d460c5 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -566,6 +566,7 @@
 
 #track_activities = on
 #track_counts = on
+#track_statement_statistics = off
 #track_io_timing = off
 #track_functions = none			# none, pl, all
 #track_activity_query_size = 1024	# (change requires restart)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 58ea5b9..a41d572 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5476,7 +5476,14 @@
   proname => 'pg_stat_get_xact_function_self_time', provolatile => 'v',
   proparallel => 'r', prorettype => 'float8', proargtypes => 'oid',
   prosrc => 'pg_stat_get_xact_function_self_time' },
-
+{ oid => '4789',
+  descr => 'statistics: Show SQL statement statistics',
+  proname => 'pg_stat_sql', prorows => '1000', proretset => 't', provolatile => 'v',
+  proparallel => 'r', prorettype => 'record', proargtypes => '',
+  proallargtypes => '{text,int4}',
+  proargmodes => '{o,o}',
+  proargnames => '{tag,count}',
+  prosrc => 'pg_stat_sql' },
 { oid => '3788',
   descr => 'statistics: timestamp of the current statistics snapshot',
   proname => 'pg_stat_get_snapshot_timestamp', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index fe076d8..8cdbbd8 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -19,6 +19,7 @@
 #include "storage/proc.h"
 #include "utils/hsearch.h"
 #include "utils/relcache.h"
+#include "tcop/utility.h"
 
 
 /* ----------
@@ -119,7 +120,8 @@ typedef struct PgStat_TableCounts
 typedef enum PgStat_Shared_Reset_Target
 {
 	RESET_ARCHIVER,
-	RESET_BGWRITER
+	RESET_BGWRITER,
+	RESET_SQLSTMT
 } PgStat_Shared_Reset_Target;
 
 /* Possible object types for resetting single counters */
@@ -581,7 +583,7 @@ typedef union PgStat_Msg
  * ------------------------------------------------------------
  */
 
-#define PGSTAT_FILE_FORMAT_ID	0x01A5BC9D
+#define PGSTAT_FILE_FORMAT_ID	0x01A5BC9E
 
 /* ----------
  * PgStat_StatDBEntry			The collector's data per database
@@ -1210,6 +1212,7 @@ typedef struct PgStat_FunctionCallUsage
  */
 extern bool pgstat_track_activities;
 extern bool pgstat_track_counts;
+extern bool pgstat_track_statement_statistics;
 extern int	pgstat_track_functions;
 extern PGDLLIMPORT int pgstat_track_activity_query_size;
 extern char *pgstat_stat_directory;
@@ -1222,6 +1225,11 @@ extern char *pgstat_stat_filename;
 extern PgStat_MsgBgWriter BgWriterStats;
 
 /*
+ * SQL statement statistics counter
+ */
+extern uint64* pgstat_sql_counts;
+
+/*
  * Updated by pgstat_count_buffer_*_time macros
  */
 extern PgStat_Counter pgStatBlockReadTime;
@@ -1299,6 +1307,9 @@ extern void pgstat_initstats(Relation rel);
 
 extern char *pgstat_clip_activity(const char *raw_activity);
 
+extern Size pgstat_sql_shmem_size(void);
+extern void pgstat_sql_shmem_init(void);
+
 /* ----------
  * pgstat_report_wait_start() -
  *
@@ -1420,6 +1431,7 @@ extern void pgstat_twophase_postabort(TransactionId xid, uint16 info,
 
 extern void pgstat_send_archiver(const char *xlog, bool failed);
 extern void pgstat_send_bgwriter(void);
+extern void pgstat_count_sqlstmt(StatSqlType sqlType);
 
 /* ----------
  * Support functions for the SQL-callable functions to
diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h
index 5abcacf..9a9e867 100644
--- a/src/include/tcop/utility.h
+++ b/src/include/tcop/utility.h
@@ -25,6 +25,203 @@ typedef enum
 	PROCESS_UTILITY_SUBCOMMAND	/* a portion of a query */
 } ProcessUtilityContext;
 
+/* ----------
+ * The sql statement types for pg_stat_sql
+ * ----------
+ */
+typedef enum StatSqlType
+{
+	T_Stat_INSERT,
+	T_Stat_DELETE,
+	T_Stat_UPDATE,
+	T_Stat_SELECT,
+	T_Stat_BEGIN,
+	T_Stat_START_TRANSACTION,
+	T_Stat_COMMIT,
+	T_Stat_ROLLBACK,
+	T_Stat_SAVEPOINT,
+	T_Stat_RELEASE,
+	T_Stat_PREPARE_TRANSACTION,
+	T_Stat_COMMIT_PREPARED,
+	T_Stat_ROLLBACK_PREPARED,
+	T_Stat_DECLARE_CURSOR,
+	T_Stat_CLOSE_CURSOR_ALL,
+	T_Stat_CLOSE_CURSOR,
+	T_Stat_MOVE,
+	T_Stat_FETCH,
+	T_Stat_CREATE_DOMAIN,
+	T_Stat_CREATE_SCHEMA,
+	T_Stat_CREATE_TABLE,
+	T_Stat_CREATE_TABLESPACE,
+	T_Stat_DROP_TABLESPACE,
+	T_Stat_ALTER_TABLESPACE,
+	T_Stat_CREATE_EXTENSION,
+	T_Stat_ALTER_EXTENSION,
+	T_Stat_CREATE_FOREIGN_DATA_WRAPPER,
+	T_Stat_ALTER_FOREIGN_DATA_WRAPPER,
+	T_Stat_CREATE_SERVER,
+	T_Stat_ALTER_SERVER,
+	T_Stat_CREATE_USER_MAPPING,
+	T_Stat_ALTER_USER_MAPPING,
+	T_Stat_DROP_USER_MAPPING,
+	T_Stat_CREATE_FOREIGN_TABLE,
+	T_Stat_IMPORT_FOREIGN_SCHEMA,
+	T_Stat_DROP_TABLE,
+	T_Stat_DROP_SEQUENCE,
+	T_Stat_DROP_VIEW,
+	T_Stat_DROP_MATERIALIZED_VIEW,
+	T_Stat_DROP_INDEX,
+	T_Stat_DROP_TYPE,
+	T_Stat_DROP_DOMAIN,
+	T_Stat_DROP_COLLATION,
+	T_Stat_DROP_CONVERSION,
+	T_Stat_DROP_SCHEMA,
+	T_Stat_DROP_TEXT_SEARCH_PARSER,
+	T_Stat_DROP_TEXT_SEARCH_DICTIONARY,
+	T_Stat_DROP_TEXT_SEARCH_TEMPLATE,
+	T_Stat_DROP_DROP_TEXT_SEARCH_CONFIGURATION,
+	T_Stat_DROP_DROP_FOREIGN_TABLE,
+	T_Stat_DROP_EXTENSION,
+	T_Stat_DROP_FUNCTION,
+	T_Stat_DROP_PROCEDURE,
+	T_Stat_DROP_ROUTINE,
+	T_Stat_DROP_AGGREGATE,
+	T_Stat_DROP_OPERATOR,
+	T_Stat_DROP_LANGUAGE,
+	T_Stat_DROP_CAST,
+	T_Stat_DROP_TRIGGER,
+	T_Stat_DROP_EVENT_TRIGGER,
+	T_Stat_DROP_RULE,
+	T_Stat_DROP_FOREIGN_DATA_WRAPPER,
+	T_Stat_DROP_SERVER,
+	T_Stat_DROP_OPERATOR_CLASS,
+	T_Stat_DROP_OPERATOR_FAMILY,
+	T_Stat_DROP_POLICY,
+	T_Stat_DROP_TRANSFORM,
+	T_Stat_DROP_ACCESS_METHOD,
+	T_Stat_DROP_PUBLICATION,
+	T_Stat_DROP_STATISTICS,
+	T_Stat_TRUNCATE_TABLE,
+	T_Stat_COMMENT,
+	T_Stat_SECURITY_LABEL,
+	T_Stat_COPY,
+	T_Stat_ALTER_AGGREGATE,
+	T_Stat_ALTER_TYPE,
+	T_Stat_ALTER_CAST,
+	T_Stat_ALTER_COLLATION,
+	T_Stat_ALTER_TABLE,
+	T_Stat_ALTER_CONVERSION,
+	T_Stat_ALTER_DATABASE,
+	T_Stat_ALTER_DOMAIN,
+	T_Stat_ALTER_FOREIGN_TABLE,
+	T_Stat_ALTER_FUNCTION,
+	T_Stat_ALTER_INDEX,
+	T_Stat_ALTER_LANGUAGE,
+	T_Stat_ALTER_LARGE_OBJECT,
+	T_Stat_ALTER_OPERATOR_CLASS,
+	T_Stat_ALTER_OPERATOR,
+	T_Stat_ALTER_OPERATOR_FAMILY,
+	T_Stat_ALTER_POLICY,
+	T_Stat_ALTER_PROCEDURE,
+	T_Stat_ALTER_ROLE,
+	T_Stat_ALTER_ROUTINE,
+	T_Stat_ALTER_RULE,
+	T_Stat_ALTER_SCHEMA,
+	T_Stat_ALTER_SEQUENCE,
+	T_Stat_ALTER_TRIGGER,
+	T_Stat_ALTER_EVENT_TRIGGER,
+	T_Stat_ALTER_TEXT_SEARCH_CONFIGURATION,
+	T_Stat_ALTER_TEXT_SEARCH_DICTIONARY,
+	T_Stat_ALTER_TEXT_SEARCH_PARSER,
+	T_Stat_ALTER_TEXT_SEARCH_TEMPLATE,
+	T_Stat_ALTER_VIEW,
+	T_Stat_ALTER_MATERIALIZED_VIEW,
+	T_Stat_ALTER_PUBLICATION,
+	T_Stat_ALTER_SUBSCRIPTION,
+	T_Stat_ALTER_STATISTICS,
+	T_Stat_GRANT,
+	T_Stat_REVOKE,
+	T_Stat_GRANT_ROLE,
+	T_Stat_REVOKE_ROLE,
+	T_Stat_ALTER_DEFAULT_PRIVILEGES,
+	T_Stat_CREATE_AGGREGATE,
+	T_Stat_CREATE_OPERATOR,
+	T_Stat_CREATE_TYPE,
+	T_Stat_CREATE_TEXT_SEARCH_PARSER,
+	T_Stat_CREATE_TEXT_SEARCH_DICTIONARY,
+	T_Stat_CREATE_TEXT_SEARCH_TEMPLATE,
+	T_Stat_CREATE_TEXT_SEARCH_CONFIGURATION,
+	T_Stat_CREATE_COLLATION,
+	T_Stat_CREATE_ACCESS_METHOD,
+	T_Stat_CREATE_VIEW,
+	T_Stat_CREATE_PROCEDURE,
+	T_Stat_CREATE_FUNCTION,
+	T_Stat_CREATE_INDEX,
+	T_Stat_CREATE_RULE,
+	T_Stat_CREATE_SEQUENCE,
+	T_Stat_DO,
+	T_Stat_CREATE_DATABASE,
+	T_Stat_DROP_DATABASE,
+	T_Stat_NOTIFY,
+	T_Stat_LISTEN,
+	T_Stat_UNLISTEN,
+	T_Stat_LOAD,
+	T_Stat_CALL,
+	T_Stat_CLUSTER,
+	T_Stat_VACUUM,
+	T_Stat_ANALYZE,
+	T_Stat_EXPLAIN,
+	T_Stat_SELECT_INTO,
+	T_Stat_CREATE_TABLE_AS,
+	T_Stat_CREATE_MATERIALIZED_VIEW,
+	T_Stat_REFRESH_MATERIALIZED_VIEW,
+	T_Stat_ALTER_SYSTEM,
+	T_Stat_SET,
+	T_Stat_RESET,
+	T_Stat_SHOW,
+	T_Stat_DISCARD_ALL,
+	T_Stat_DISCARD_PLANS,
+	T_Stat_DISCARD_TEMP,
+	T_Stat_DISCARD_SEQUENCES,
+	T_Stat_CREATE_TRANSFORM,
+	T_Stat_CREATE_TRIGGER,
+	T_Stat_CREATE_EVENT_TRIGGER,
+	T_Stat_CREATE_LANGUAGE,
+	T_Stat_CREATE_ROLE,
+	T_Stat_DROP_ROLE,
+	T_Stat_DROP_OWNED,
+	T_Stat_REASSIGN_OWNED,
+	T_Stat_LOCK_TABLE,
+	T_Stat_SET_CONSTRAINTS,
+	T_Stat_CHECKPOINT,
+	T_Stat_REINDEX,
+	T_Stat_CREATE_CONVERSION,
+	T_Stat_CREATE_CAST,
+	T_Stat_CREATE_OPERATOR_CLASS,
+	T_Stat_CREATE_OPERATOR_FAMILY,
+	T_Stat_CREATE_POLICY,
+	T_Stat_CREATE_PUBLICATION,
+	T_Stat_CREATE_SUBSCRIPTION,
+	T_Stat_DROP_SUBSCRIPTION,
+	T_Stat_PREPARE,
+	T_Stat_EXECUTE,
+	T_Stat_CREATE_STATISTICS,
+	T_Stat_DEALLOCATE_ALL,
+	T_Stat_DEALLOCATE,
+	T_Stat_SELECT_FOR_KEY_SHARE,
+	T_Stat_SELECT_FOR_SHARE,
+	T_Stat_SELECT_FOR_NO_KEY_UPDATE,
+	T_Stat_SELECT_FOR_UPDATE,
+
+	T_Stat_UNKNOWN
+
+} StatSqlType;
+
+#define PGSTAT_SQLSTMT_SIZE (T_Stat_UNKNOWN + 1)
+
+extern const char* g_str_sql_type[];
+
+
 /* Hook for plugins to get control in ProcessUtility() */
 typedef void (*ProcessUtility_hook_type) (PlannedStmt *pstmt,
 										  const char *queryString, ProcessUtilityContext context,
@@ -50,6 +247,10 @@ extern Query *UtilityContainsQuery(Node *parsetree);
 
 extern const char *CreateCommandTag(Node *parsetree);
 
+extern StatSqlType CreateCommandType(Node *parsetree);
+
+extern const char* CreateCommandTagType(Node *parsetree, StatSqlType* pESqlType);
+
 extern LogStmtLevel GetCommandLogLevel(Node *parsetree);
 
 extern bool CommandIsReadOnly(PlannedStmt *pstmt);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 14e7214..a9dd290 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1956,6 +1956,9 @@ pg_stat_replication| SELECT s.pid,
    FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc)
      JOIN pg_stat_get_wal_senders() w(pid, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, write_lag, flush_lag, replay_lag, sync_priority, sync_state, reply_time) ON ((s.pid = w.pid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
+pg_stat_sql| SELECT pg_stat_sql.tag,
+    pg_stat_sql.count
+   FROM pg_stat_sql() pg_stat_sql(tag, count);
 pg_stat_ssl| SELECT s.pid,
     s.ssl,
     s.sslversion AS version,
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index b01e58b..50846c7 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -4,6 +4,70 @@
 -- Must be run after tenk2 has been created (by create_table),
 -- populated (by create_misc) and indexed (by create_index).
 --
+-- pg_stat_sql
+SET track_statement_statistics TO OFF;
+SELECT pg_stat_reset_shared('sqlstmt'); -- reset the counters
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT pg_sleep(1.0);
+ pg_sleep 
+----------
+ 
+(1 row)
+
+SELECT * FROM pg_stat_sql where tag='SELECT';
+ tag | count 
+-----+-------
+(0 rows)
+
+SET track_statement_statistics TO ON;
+CREATE TABLE t1 (c1 int);
+INSERT INTO t1 VALUES(1);
+INSERT INTO t1 VALUES(1);
+INSERT INTO t1 VALUES(1);
+DELETE FROM t1;
+SELECT * FROM pg_stat_sql;
+     tag      | count 
+--------------+-------
+ INSERT       |     3
+ DELETE       |     1
+ CREATE TABLE |     1
+ SET          |     1
+(4 rows)
+
+SELECT pg_sleep(1.0);
+ pg_sleep 
+----------
+ 
+(1 row)
+
+SELECT * FROM pg_stat_sql where tag='SELECT';
+  tag   | count 
+--------+-------
+ SELECT |     2
+(1 row)
+
+SET track_statement_statistics TO OFF;
+SELECT pg_stat_reset_shared('sqlstmt'); -- reset the counters
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT pg_sleep(1.0);
+ pg_sleep 
+----------
+ 
+(1 row)
+
+SELECT * FROM pg_stat_sql where tag='SELECT';
+ tag | count 
+-----+-------
+(0 rows)
+
 -- conditio sine qua non
 SHOW track_counts;  -- must be on
  track_counts 
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index feaaee6..48e88d3 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -4,6 +4,30 @@
 -- Must be run after tenk2 has been created (by create_table),
 -- populated (by create_misc) and indexed (by create_index).
 --
+-- pg_stat_sql
+SET track_statement_statistics TO OFF;
+SELECT pg_stat_reset_shared('sqlstmt'); -- reset the counters
+
+SELECT pg_sleep(1.0);
+SELECT * FROM pg_stat_sql where tag='SELECT';
+
+SET track_statement_statistics TO ON;
+
+CREATE TABLE t1 (c1 int);
+INSERT INTO t1 VALUES(1);
+INSERT INTO t1 VALUES(1);
+INSERT INTO t1 VALUES(1);
+DELETE FROM t1;
+SELECT * FROM pg_stat_sql;
+
+SELECT pg_sleep(1.0);
+SELECT * FROM pg_stat_sql where tag='SELECT';
+
+SET track_statement_statistics TO OFF;
+SELECT pg_stat_reset_shared('sqlstmt'); -- reset the counters
+
+SELECT pg_sleep(1.0);
+SELECT * FROM pg_stat_sql where tag='SELECT';
 
 -- conditio sine qua non
 SHOW track_counts;  -- must be on
-- 
1.8.3.1

