diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index cd66abc..8231d28 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -5552,6 +5552,21 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-track-sql" xreflabel="track_sql">
+      <term><varname>track_sql</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>track_sql</> 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 0776428..ff0cb6d 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -513,6 +513,13 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       <command>VACUUM</>, showing current progress.
       See <xref linkend='vacuum-progress-reporting'>.</entry>
      </row>
+     
+     <row>
+      <entry><structname>pg_stat_sql</><indexterm><primary>pg_stat_sql</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the SQL statements that are
+       executed on the instance.
+       See <xref linkend="pg-stat-sql-view"> for details.</entry>
+     </row>
     </tbody>
    </tgroup>
   </table>
@@ -2222,6 +2229,150 @@ 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>insert</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of insert SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>delete</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of delete SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>update</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of update SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>select</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of select SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>declar_cursor</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of declare_cursor SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>close</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of close SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>create</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of create SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>drop</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of drop SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>alter</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of alter SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>import</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of import SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>truncate</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of truncate SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>copy</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of copy SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>grant</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of grant SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>revoke</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of revoke SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>cluster</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of cluster SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>vacuum</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of vacuum SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>analyze</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of analyze SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>refresh</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of refresh SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>lock</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of lock SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>checkpoint</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of checkpoint SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>reindex</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of reindex SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>deallocate</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of deallocate SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>others</></entry>
+     <entry><type>bigint</></entry>
+     <entry>Number of others SQL statements executed</entry>
+    </row>
+    <row>
+     <entry><structfield>stats_reset</></entry>
+     <entry><type>timestamp with time zone</type></entry>
+     <entry>Time at which these statistics were last reset</entry>
+    </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+  <para>
+   The <structname>pg_stat_sql</structname> view will contain only 
+   one row, showing statistics about number of SQL statements that are 
+   executed on the instance. The <xref linkend="guc-track-sql"> parameter
+   controls the SQL statement execution statistics.
+  </para>
+  
+  
  </sect2>
 
  <sect2 id="monitoring-stats-functions">
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index ada2142..0e39920 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -842,6 +842,35 @@ CREATE VIEW pg_replication_origin_status AS
 
 REVOKE ALL ON pg_replication_origin_status FROM public;
 
+CREATE VIEW pg_stat_sql AS
+    SELECT
+        pg_stat_get_insert_sqlstmt() AS insert,
+        pg_stat_get_delete_sqlstmt() AS delete,
+        pg_stat_get_update_sqlstmt() AS update,
+        pg_stat_get_select_sqlstmt() AS select,
+        pg_stat_get_declare_cursor_sqlstmt() AS declare_cursor,
+        pg_stat_get_close_sqlstmt() AS close,
+        pg_stat_get_create_sqlstmt() AS create,
+        pg_stat_get_drop_sqlstmt() AS drop,
+        pg_stat_get_alter_sqlstmt() AS alter,
+        pg_stat_get_import_sqlstmt() AS import,
+        pg_stat_get_truncate_sqlstmt() AS truncate,
+        pg_stat_get_copy_sqlstmt() AS copy,
+        pg_stat_get_grant_sqlstmt() AS grant,
+        pg_stat_get_revoke_sqlstmt() AS revoke,
+        pg_stat_get_cluster_sqlstmt() AS cluster,
+        pg_stat_get_vacuum_sqlstmt() AS vacuum,
+        pg_stat_get_analyze_sqlstmt() AS analyze,
+        pg_stat_get_refresh_sqlstmt() AS refresh,
+        pg_stat_get_lock_sqlstmt() AS lock,
+        pg_stat_get_checkpoint_sqlstmt() AS checkpoint,
+        pg_stat_get_reindex_sqlstmt() AS reindex,
+        pg_stat_get_deallocate_sqlstmt() AS deallocate,
+        pg_stat_get_others_sqlstmt() AS others,
+        pgx_stat_get_reset_time_sqlstmt() AS stats_reset;
+
+GRANT SELECT ON pg_stat_sql TO PUBLIC;
+
 --
 -- We have a few function definitions in here, too.
 -- At some point there might be enough to justify breaking them out into
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 8a2ce91..4cc5533 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -105,6 +105,7 @@
  */
 bool		pgstat_track_activities = false;
 bool		pgstat_track_counts = false;
+bool		pgstat_track_sql = false;
 int			pgstat_track_functions = TRACK_FUNC_OFF;
 int			pgstat_track_activity_query_size = 1024;
 
@@ -123,6 +124,13 @@ char	   *pgstat_stat_tmpname = NULL;
  */
 PgStat_MsgBgWriter BgWriterStats;
 
+/*
+ * SQL statistics counter.
+ * This counter is incremented by each SQL Statement,
+ * And then, sent to the stat collector process.
+ */
+PgStat_MsgSqlstmt SqlstmtStatsLocal;
+
 /* ----------
  * Local data
  * ----------
@@ -219,6 +227,7 @@ static int	localNumBackends = 0;
  */
 static PgStat_ArchiverStats archiverStats;
 static PgStat_GlobalStats globalStats;
+static PgStat_SqlStmtStats sqlstmtStats;
 
 /*
  * List of OIDs of databases we need to write out.  If an entry is InvalidOid,
@@ -267,6 +276,7 @@ static bool pgstat_db_requested(Oid databaseid);
 
 static void pgstat_send_tabstat(PgStat_MsgTabstat *tsmsg);
 static void pgstat_send_funcstats(void);
+static void pgstat_send_sqlstmt(void);
 static HTAB *pgstat_collect_oids(Oid catalogid);
 
 static PgStat_TableStatus *get_tabstat_entry(Oid rel_id, bool isshared);
@@ -293,6 +303,7 @@ static void pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len);
 static void pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len);
 static void pgstat_recv_deadlock(PgStat_MsgDeadlock *msg, int len);
 static void pgstat_recv_tempfile(PgStat_MsgTempFile *msg, int len);
+static void pgstat_recv_sqlstmt(PgStat_MsgSqlstmt * msg, int len);
 
 /* ------------------------------------------------------------
  * Public functions called from postmaster follow
@@ -826,6 +837,10 @@ pgstat_report_stat(bool force)
 
 	/* Now, send function statistics */
 	pgstat_send_funcstats();
+
+	/* Now, send sql statistics */
+	if (pgstat_track_sql)
+		pgstat_send_sqlstmt();
 }
 
 /*
@@ -1252,11 +1267,13 @@ 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)
+		msg.m_resettarget = RESET_SQLSTMT;
 	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));
@@ -2465,6 +2482,21 @@ pgstat_fetch_global(void)
 	return &globalStats;
 }
 
+/*
+ * ---------
+ * pgstat_fetch_sqlstmt() -
+ *
+ *	Support function for the SQL-callable pgstat* functions. Returns
+ *	a pointer to the sql statement statistics struct.
+ * ---------
+ */
+PgStat_SqlStmtStats *
+pgstat_fetch_sqlstmt(void)
+{
+	backend_read_statsfile();
+
+	return &sqlstmtStats;
+}
 
 /* ------------------------------------------------------------
  * Functions for management of the shared-memory PgBackendStatus array
@@ -3456,6 +3488,37 @@ pgstat_send_bgwriter(void)
 	MemSet(&BgWriterStats, 0, sizeof(BgWriterStats));
 }
 
+/* ----------
+ * pgstat_send_sqlstmt(void)
+ *
+ *		Send SQL statement statistics to the collector
+ * ----------
+ */
+static void
+pgstat_send_sqlstmt(void)
+{
+	/* We assume this initializes to zeroes */
+	static const PgStat_MsgSqlstmt all_zeroes;
+
+	/*
+	 * This function can be called even if nothing at all has happened. In
+	 * this case, avoid sending a completely empty message to the stats
+	 * collector.
+	 */
+	if (memcmp(&SqlstmtStatsLocal, &all_zeroes, sizeof(PgStat_MsgSqlstmt)) == 0)
+		return;
+
+	/*
+	 * Prepare and send the message
+	 */
+	pgstat_setheader(&SqlstmtStatsLocal.m_hdr, PGSTAT_MTYPE_SQLSTMT);
+	pgstat_send(&SqlstmtStatsLocal, sizeof(SqlstmtStatsLocal));
+
+	/*
+	 * Clear out the statistics buffer, so it can be re-used.
+	 */
+	MemSet(&SqlstmtStatsLocal, 0, sizeof(SqlstmtStatsLocal));
+}
 
 /* ----------
  * PgstatCollectorMain() -
@@ -3672,6 +3735,9 @@ PgstatCollectorMain(int argc, char *argv[])
 					pgstat_recv_tempfile((PgStat_MsgTempFile *) &msg, len);
 					break;
 
+				case PGSTAT_MTYPE_SQLSTMT:
+					pgstat_recv_sqlstmt((PgStat_MsgSqlstmt *) & msg, len);
+					break;
 				default:
 					break;
 			}
@@ -3937,6 +4003,12 @@ pgstat_write_statsfiles(bool permanent, bool allDbs)
 	(void) rc;					/* we'll check for error with ferror */
 
 	/*
+	 * Write Sql statement stats struct
+	 */
+	rc = fwrite(&sqlstmtStats, sizeof(PgStat_SqlStmtStats), 1, fpout);
+	(void) rc;					/* we'll check for error with ferror */
+
+	/*
 	 * Walk through the database table.
 	 */
 	hash_seq_init(&hstat, pgStatDBHash);
@@ -4193,6 +4265,7 @@ pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep)
 	 */
 	memset(&globalStats, 0, sizeof(globalStats));
 	memset(&archiverStats, 0, sizeof(archiverStats));
+	memset(&sqlstmtStats, 0, sizeof(sqlstmtStats));
 
 	/*
 	 * Set the current timestamp (will be kept only in case we can't load an
@@ -4200,6 +4273,7 @@ pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep)
 	 */
 	globalStats.stat_reset_timestamp = GetCurrentTimestamp();
 	archiverStats.stat_reset_timestamp = globalStats.stat_reset_timestamp;
+	sqlstmtStats.stat_reset_timestamp = globalStats.stat_reset_timestamp;
 
 	/*
 	 * Try to open the stats file. If it doesn't exist, the backends simply
@@ -4252,6 +4326,16 @@ pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep)
 	}
 
 	/*
+	 * Read Sql statement stats struct
+	 */
+	if (fread(&sqlstmtStats, 1, sizeof(sqlstmtStats), fpin) != sizeof(sqlstmtStats))
+	{
+		ereport(pgStatRunningInCollector ? LOG : WARNING,
+				(errmsg("corrupted statistics file \"%s\"", statfile)));
+		goto done;
+	}
+
+	/*
 	 * We found an existing collector stats file. Read it and put all the
 	 * hashtable entries into place.
 	 */
@@ -4540,6 +4624,7 @@ pgstat_read_db_statsfile_timestamp(Oid databaseid, bool permanent,
 	PgStat_StatDBEntry dbentry;
 	PgStat_GlobalStats myGlobalStats;
 	PgStat_ArchiverStats myArchiverStats;
+	PgStat_SqlStmtStats mySqlstmtStats;
 	FILE	   *fpin;
 	int32		format_id;
 	const char *statfile = permanent ? PGSTAT_STAT_PERMANENT_FILENAME : pgstat_stat_filename;
@@ -4594,6 +4679,18 @@ pgstat_read_db_statsfile_timestamp(Oid databaseid, bool permanent,
 		return false;
 	}
 
+	/*
+	 * Read sql statement stats struct
+	 */
+	if (fread(&mySqlstmtStats, 1, sizeof(mySqlstmtStats),
+			  fpin) != sizeof(mySqlstmtStats))
+	{
+		ereport(pgStatRunningInCollector ? LOG : WARNING,
+				(errmsg("corrupted statistics file \"%s\"", statfile)));
+		FreeFile(fpin);
+		return false;
+	}
+
 	/* By default, we're going to return the timestamp of the global file. */
 	*ts = myGlobalStats.stats_timestamp;
 
@@ -5156,6 +5253,12 @@ pgstat_recv_resetsharedcounter(PgStat_MsgResetsharedcounter *msg, int len)
 		memset(&archiverStats, 0, sizeof(archiverStats));
 		archiverStats.stat_reset_timestamp = GetCurrentTimestamp();
 	}
+	else if (msg->m_resettarget == RESET_SQLSTMT)
+	{
+		/* Reset the archiver statistics for the cluster. */
+		memset(&sqlstmtStats, 0, sizeof(sqlstmtStats));
+		sqlstmtStats.stat_reset_timestamp = GetCurrentTimestamp();
+	}
 
 	/*
 	 * Presumably the sender of this message validated the target, don't
@@ -5336,6 +5439,40 @@ pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len)
 }
 
 /* ----------
+ * pgstat_recv_sqlstmt() -
+ *
+ *	Process a SQL statement statistics message.
+ * ----------
+ */
+static void
+pgstat_recv_sqlstmt(PgStat_MsgSqlstmt * msg, int len)
+{
+	sqlstmtStats.n_insert_sqlstmt += msg->n_insert_sqlstmt;
+	sqlstmtStats.n_delete_sqlstmt += msg->n_delete_sqlstmt;
+	sqlstmtStats.n_update_sqlstmt += msg->n_update_sqlstmt;
+	sqlstmtStats.n_select_sqlstmt += msg->n_select_sqlstmt;
+	sqlstmtStats.n_declare_cursor_sqlstmt += msg->n_declare_cursor_sqlstmt;
+	sqlstmtStats.n_close_sqlstmt += msg->n_close_sqlstmt;
+	sqlstmtStats.n_create_sqlstmt += msg->n_create_sqlstmt;
+	sqlstmtStats.n_drop_sqlstmt += msg->n_drop_sqlstmt;
+	sqlstmtStats.n_alter_sqlstmt += msg->n_alter_sqlstmt;
+	sqlstmtStats.n_import_sqlstmt += msg->n_import_sqlstmt;
+	sqlstmtStats.n_truncate_sqlstmt += msg->n_truncate_sqlstmt;
+	sqlstmtStats.n_copy_sqlstmt += msg->n_copy_sqlstmt;
+	sqlstmtStats.n_grant_sqlstmt += msg->n_grant_sqlstmt;
+	sqlstmtStats.n_revoke_sqlstmt += msg->n_revoke_sqlstmt;
+	sqlstmtStats.n_cluster_sqlstmt += msg->n_cluster_sqlstmt;
+	sqlstmtStats.n_vacuum_sqlstmt += msg->n_vacuum_sqlstmt;
+	sqlstmtStats.n_analyze_sqlstmt += msg->n_analyze_sqlstmt;
+	sqlstmtStats.n_refresh_sqlstmt += msg->n_refresh_sqlstmt;
+	sqlstmtStats.n_lock_sqlstmt += msg->n_lock_sqlstmt;
+	sqlstmtStats.n_checkpoint_sqlstmt += msg->n_checkpoint_sqlstmt;
+	sqlstmtStats.n_reindex_sqlstmt += msg->n_reindex_sqlstmt;
+	sqlstmtStats.n_deallocate_sqlstmt += msg->n_deallocate_sqlstmt;
+	sqlstmtStats.n_others_sqlstmt += msg->n_others_sqlstmt;
+}
+
+/* ----------
  * pgstat_recv_recoveryconflict() -
  *
  *	Process a RECOVERYCONFLICT message.
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 98ccbbb..620a6c9 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -41,6 +41,7 @@
 #include "access/xact.h"
 #include "catalog/pg_type.h"
 #include "commands/async.h"
+#include "commands/defrem.h"
 #include "commands/prepare.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -188,7 +189,7 @@ static bool IsTransactionStmtList(List *parseTrees);
 static void drop_unnamed_stmt(void);
 static void SigHupHandler(SIGNAL_ARGS);
 static void log_disconnections(int code, Datum arg);
-
+static void CountSQLStmtExecutions(Node *parsetree);
 
 /* ----------------------------------------------------------------
  *		routines to obtain user input
@@ -1102,6 +1103,12 @@ exec_simple_query(const char *query_string)
 
 		PortalDrop(portal, false);
 
+		/*
+		 * Count SQL statement for pg_stat_sql view
+		 */
+		if (pgstat_track_sql)
+			CountSQLStmtExecutions(parsetree);
+
 		if (IsA(parsetree, TransactionStmt))
 		{
 			/*
@@ -1983,6 +1990,29 @@ exec_execute_message(const char *portal_name, long max_rows)
 
 	(*receiver->rDestroy) (receiver);
 
+	/*
+	 * Count SQL Statement for pgx_stat_sql
+	 */
+	if (pgstat_track_sql)
+	{
+		CachedPlanSource *psrc = NULL;
+
+		if (portal->prepStmtName)
+		{
+			PreparedStatement *pstmt;
+
+			pstmt = FetchPreparedStatement(portal->prepStmtName, false);
+			if (pstmt)
+				psrc = pstmt->plansource;
+		}
+		else
+			psrc = unnamed_stmt_psrc;
+
+		if (psrc && !execute_is_fetch)	/* psrc should not be NULL here, just
+										 * for paranoia */
+			CountSQLStmtExecutions(psrc->raw_parse_tree);
+	}
+
 	if (completed)
 	{
 		if (is_xact_command)
@@ -4506,3 +4536,319 @@ log_disconnections(int code, Datum arg)
 					port->user_name, port->database_name, port->remote_host,
 				  port->remote_port[0] ? " port=" : "", port->remote_port)));
 }
+
+
+/*
+ * Count SQL statement for pg_stat_sql view
+ */
+static void
+CountSQLStmtExecutions(Node *parsetree)
+{
+	/*
+	 * If pgstat_track_sql is true, parsetree should not be NULL. For safer,
+	 * Check NULL here.
+	 */
+	if (!parsetree)
+		return;
+
+	switch (nodeTag(parsetree))
+	{
+			/* raw plannable queries */
+		case T_InsertStmt:
+			SqlstmtStatsLocal.n_insert_sqlstmt++;
+			break;
+
+		case T_DeleteStmt:
+			SqlstmtStatsLocal.n_delete_sqlstmt++;
+			break;
+
+		case T_UpdateStmt:
+			SqlstmtStatsLocal.n_update_sqlstmt++;
+			break;
+
+		case T_SelectStmt:
+			SqlstmtStatsLocal.n_select_sqlstmt++;
+			break;
+
+		case T_DeclareCursorStmt:
+			SqlstmtStatsLocal.n_declare_cursor_sqlstmt++;
+			break;
+
+		case T_ClosePortalStmt:
+			SqlstmtStatsLocal.n_close_sqlstmt++;
+			break;
+
+		case T_CreateDomainStmt:
+		case T_CreateSchemaStmt:
+		case T_CreateStmt:
+		case T_CreateTableSpaceStmt:
+		case T_CreateExtensionStmt:
+		case T_CreateFdwStmt:
+		case T_CreateForeignServerStmt:
+		case T_CreateUserMappingStmt:
+		case T_CreateForeignTableStmt:
+		case T_DefineStmt:
+		case T_CompositeTypeStmt:
+		case T_CreateEnumStmt:
+		case T_CreateRangeStmt:
+		case T_ViewStmt:
+		case T_CreateFunctionStmt:
+		case T_IndexStmt:
+		case T_RuleStmt:
+		case T_CreateSeqStmt:
+		case T_CreatedbStmt:
+		case T_CreateTransformStmt:
+		case T_CreateTrigStmt:
+		case T_CreateEventTrigStmt:
+		case T_CreatePLangStmt:
+		case T_CreateRoleStmt:
+		case T_CreateConversionStmt:
+		case T_CreateCastStmt:
+		case T_CreateOpClassStmt:
+		case T_CreateOpFamilyStmt:
+		case T_CreatePolicyStmt:
+		case T_CreateAmStmt:
+			SqlstmtStatsLocal.n_create_sqlstmt++;
+			break;
+
+		case T_DropTableSpaceStmt:
+		case T_DropUserMappingStmt:
+		case T_DropStmt:
+		case T_DropdbStmt:
+		case T_DropRoleStmt:
+		case T_DropOwnedStmt:
+			SqlstmtStatsLocal.n_drop_sqlstmt++;
+			break;
+
+		case T_AlterTableSpaceOptionsStmt:
+		case T_AlterExtensionStmt:
+		case T_AlterExtensionContentsStmt:
+		case T_AlterFdwStmt:
+		case T_AlterForeignServerStmt:
+		case T_AlterUserMappingStmt:
+		case T_RenameStmt:
+		case T_AlterObjectDependsStmt:
+		case T_AlterObjectSchemaStmt:
+		case T_AlterOwnerStmt:
+		case T_AlterTableMoveAllStmt:
+		case T_AlterTableStmt:
+		case T_AlterDomainStmt:
+		case T_AlterFunctionStmt:
+		case T_AlterDefaultPrivilegesStmt:
+		case T_AlterEnumStmt:
+		case T_AlterSeqStmt:
+		case T_AlterDatabaseStmt:
+		case T_AlterDatabaseSetStmt:
+		case T_AlterSystemStmt:
+		case T_AlterEventTrigStmt:
+		case T_AlterRoleStmt:
+		case T_AlterRoleSetStmt:
+		case T_AlterOpFamilyStmt:
+		case T_AlterOperatorStmt:
+		case T_AlterTSDictionaryStmt:
+		case T_AlterTSConfigurationStmt:
+		case T_AlterPolicyStmt:
+			SqlstmtStatsLocal.n_alter_sqlstmt++;
+			break;
+
+		case T_ImportForeignSchemaStmt:
+			SqlstmtStatsLocal.n_import_sqlstmt++;
+			break;
+
+		case T_TruncateStmt:
+			SqlstmtStatsLocal.n_truncate_sqlstmt++;
+			break;
+
+		case T_CopyStmt:
+			SqlstmtStatsLocal.n_copy_sqlstmt++;
+			break;
+
+		case T_GrantStmt:
+			{
+				GrantStmt  *stmt = (GrantStmt *) parsetree;
+
+				if (stmt->is_grant)
+					SqlstmtStatsLocal.n_grant_sqlstmt++;
+				else
+					SqlstmtStatsLocal.n_revoke_sqlstmt++;
+			}
+			break;
+
+		case T_GrantRoleStmt:
+			{
+				GrantRoleStmt *stmt = (GrantRoleStmt *) parsetree;
+
+				if (stmt->is_grant)
+					SqlstmtStatsLocal.n_grant_sqlstmt++;
+				else
+					SqlstmtStatsLocal.n_revoke_sqlstmt++;
+			}
+			break;
+
+		case T_ClusterStmt:
+			SqlstmtStatsLocal.n_cluster_sqlstmt++;
+			break;
+
+		case T_VacuumStmt:
+			if (((VacuumStmt *) parsetree)->options & VACOPT_VACUUM)
+				SqlstmtStatsLocal.n_vacuum_sqlstmt++;
+			else
+				SqlstmtStatsLocal.n_analyze_sqlstmt++;
+			break;
+
+		case T_ExplainStmt:
+			{
+				ExplainStmt *stmt = (ExplainStmt *) parsetree;
+				bool		analyze = false;
+				ListCell   *lc;
+
+				/* Look through an EXPLAIN ANALYZE to the contained stmt */
+				foreach(lc, stmt->options)
+				{
+					DefElem    *opt = (DefElem *) lfirst(lc);
+
+					if (strcmp(opt->defname, "analyze") == 0)
+					{
+						analyze = defGetBoolean(opt);
+						break;
+					}
+				}
+				if (analyze)
+					CountSQLStmtExecutions(stmt->query);
+			}
+			break;
+
+		case T_CreateTableAsStmt:
+			switch (((CreateTableAsStmt *) parsetree)->relkind)
+			{
+				case OBJECT_TABLE:
+					if (((CreateTableAsStmt *) parsetree)->is_select_into)
+						SqlstmtStatsLocal.n_select_sqlstmt++;
+					else
+						SqlstmtStatsLocal.n_create_sqlstmt++;
+					break;
+				case OBJECT_MATVIEW:
+					SqlstmtStatsLocal.n_create_sqlstmt++;
+					break;
+				default:
+					SqlstmtStatsLocal.n_others_sqlstmt++;
+			}
+			break;
+
+		case T_RefreshMatViewStmt:
+			SqlstmtStatsLocal.n_refresh_sqlstmt++;
+			break;
+
+		case T_LockStmt:
+			SqlstmtStatsLocal.n_lock_sqlstmt++;
+			break;
+
+		case T_CheckPointStmt:
+			SqlstmtStatsLocal.n_checkpoint_sqlstmt++;
+			break;
+
+		case T_ReindexStmt:
+			SqlstmtStatsLocal.n_reindex_sqlstmt++;
+			break;
+
+		case T_ExecuteStmt:
+			{
+				ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
+				PreparedStatement *entry;
+
+				/* not our business to raise error */
+				entry = FetchPreparedStatement(stmt->name, false);
+				if (!entry || !entry->plansource)
+					break;
+				CountSQLStmtExecutions(entry->plansource->raw_parse_tree);
+			}
+			break;
+
+		case T_DeallocateStmt:
+			SqlstmtStatsLocal.n_deallocate_sqlstmt++;
+			break;
+
+			/* already-planned queries */
+		case T_PlannedStmt:
+			{
+				PlannedStmt *stmt = (PlannedStmt *) parsetree;
+
+				switch (stmt->commandType)
+				{
+					case CMD_SELECT:
+
+						/*
+						 * We take a little extra care here so that the result
+						 * will be useful for complaints about read-only
+						 * statements
+						 */
+						if (stmt->utilityStmt != NULL)
+						{
+							Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
+							SqlstmtStatsLocal.n_declare_cursor_sqlstmt++;
+						}
+						else
+							SqlstmtStatsLocal.n_select_sqlstmt++;
+						break;
+					case CMD_UPDATE:
+						SqlstmtStatsLocal.n_update_sqlstmt++;
+						break;
+					case CMD_INSERT:
+						SqlstmtStatsLocal.n_insert_sqlstmt++;
+						break;
+					case CMD_DELETE:
+						SqlstmtStatsLocal.n_delete_sqlstmt++;
+						break;
+					default:
+						SqlstmtStatsLocal.n_others_sqlstmt++;
+						break;
+				}
+			}
+			break;
+
+			/* parsed-and-rewritten-but-not-planned queries */
+		case T_Query:
+			{
+				Query	   *stmt = (Query *) parsetree;
+
+				switch (stmt->commandType)
+				{
+					case CMD_SELECT:
+
+						/*
+						 * We take a little extra care here so that the result
+						 * will be useful for complaints about read-only
+						 * statements
+						 */
+						if (stmt->utilityStmt != NULL)
+						{
+							Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
+							SqlstmtStatsLocal.n_declare_cursor_sqlstmt++;
+						}
+						else
+							SqlstmtStatsLocal.n_select_sqlstmt++;
+						break;
+					case CMD_UPDATE:
+						SqlstmtStatsLocal.n_revoke_sqlstmt++;
+						break;
+					case CMD_INSERT:
+						SqlstmtStatsLocal.n_revoke_sqlstmt++;
+						break;
+					case CMD_DELETE:
+						SqlstmtStatsLocal.n_revoke_sqlstmt++;
+						break;
+					case CMD_UTILITY:
+						CountSQLStmtExecutions(stmt->utilityStmt);
+						break;
+					default:
+						SqlstmtStatsLocal.n_others_sqlstmt++;
+						break;
+				}
+			}
+			break;
+
+		default:
+			SqlstmtStatsLocal.n_others_sqlstmt++;
+			break;
+	}
+}
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 2d3cf9e..bf68b33 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -129,6 +129,31 @@ extern Datum pg_stat_reset_shared(PG_FUNCTION_ARGS);
 extern Datum pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS);
 extern Datum pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS);
 
+extern Datum pg_stat_get_insert_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_delete_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_update_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_select_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_declare_cursor_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_close_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_create_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_drop_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_alter_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_import_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_truncate_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_copy_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_grant_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_revoke_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_cluster_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_vacuum_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_analyze_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_refresh_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_lock_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_checkpoint_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_reindex_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_deallocate_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_others_sqlstmt(PG_FUNCTION_ARGS);
+extern Datum pgx_stat_get_reset_time_sqlstmt(PG_FUNCTION_ARGS);
+
 /* Global bgwriter statistics, from bgwriter.c */
 extern PgStat_MsgBgWriter bgwriterStats;
 
@@ -1931,3 +1956,147 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 	PG_RETURN_DATUM(HeapTupleGetDatum(
 								   heap_form_tuple(tupdesc, values, nulls)));
 }
+
+Datum
+pg_stat_get_insert_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_insert_sqlstmt);
+}
+
+Datum
+pg_stat_get_delete_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_delete_sqlstmt);
+}
+
+Datum
+pg_stat_get_update_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_update_sqlstmt);
+}
+
+Datum
+pg_stat_get_select_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_select_sqlstmt);
+}
+
+Datum
+pg_stat_get_declare_cursor_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_declare_cursor_sqlstmt);
+}
+
+Datum
+pg_stat_get_close_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_close_sqlstmt);
+}
+
+Datum
+pg_stat_get_create_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_create_sqlstmt);
+}
+
+Datum
+pg_stat_get_drop_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_drop_sqlstmt);
+}
+
+Datum
+pg_stat_get_alter_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_alter_sqlstmt);
+}
+
+Datum
+pg_stat_get_import_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_import_sqlstmt);
+}
+
+Datum
+pg_stat_get_truncate_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_truncate_sqlstmt);
+}
+
+Datum
+pg_stat_get_copy_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_copy_sqlstmt);
+}
+
+Datum
+pg_stat_get_grant_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_grant_sqlstmt);
+}
+
+Datum
+pg_stat_get_revoke_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_revoke_sqlstmt);
+}
+
+Datum
+pg_stat_get_cluster_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_cluster_sqlstmt);
+}
+
+Datum
+pg_stat_get_vacuum_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_vacuum_sqlstmt);
+}
+
+Datum
+pg_stat_get_analyze_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_analyze_sqlstmt);
+}
+
+Datum
+pg_stat_get_refresh_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_refresh_sqlstmt);
+}
+
+Datum
+pg_stat_get_lock_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_lock_sqlstmt);
+}
+
+Datum
+pg_stat_get_checkpoint_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_checkpoint_sqlstmt);
+}
+
+Datum
+pg_stat_get_reindex_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_reindex_sqlstmt);
+}
+
+Datum
+pg_stat_get_deallocate_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_deallocate_sqlstmt);
+}
+
+Datum
+pg_stat_get_others_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_INT64(pgstat_fetch_sqlstmt()->n_others_sqlstmt);
+}
+
+Datum
+pgx_stat_get_reset_time_sqlstmt(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_sqlstmt()->stat_reset_timestamp);
+}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index ce4eef9..154276b 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1205,6 +1205,16 @@ static struct config_bool ConfigureNamesBool[] =
 	},
 
 	{
+		{"track_sql", PGC_SUSET, STATS_COLLECTOR,
+			gettext_noop("Collects timing statistics for database I/O activity."),
+			NULL
+		},
+		&pgstat_track_sql,
+		false,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"update_process_title", PGC_SUSET, PROCESS_TITLE,
 			gettext_noop("Updates the process title to show the active SQL command."),
 			gettext_noop("Enables updating of the process title every time a new SQL command is received by the server.")
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index e2d08ba..ea77476 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2896,6 +2896,57 @@ DESCR("statistics: total execution time of function in current transaction, in m
 DATA(insert OID = 3048 (  pg_stat_get_xact_function_self_time	PGNSP PGUID 12 1 0 0 0 f f f f t f v r 1 0 701 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_function_self_time _null_ _null_ _null_ ));
 DESCR("statistics: self execution time of function in current transaction, in msec");
 
+
+DATA(insert OID = 3401 (  pg_stat_get_insert_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_insert_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of insert sql statement executions");
+DATA(insert OID = 3402 (  pg_stat_get_delete_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_delete_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of delete sql statement executions");
+DATA(insert OID = 3403 (  pg_stat_get_update_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_update_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of update sql statement executions");
+DATA(insert OID = 3404 (  pg_stat_get_select_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_select_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of select sql statement executions");
+DATA(insert OID = 3405 (  pg_stat_get_declare_cursor_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_declare_cursor_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of declare cursor sql statement executions");
+DATA(insert OID = 3406 (  pg_stat_get_close_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_close_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of close sql statement executions");
+DATA(insert OID = 3407 (  pg_stat_get_create_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_create_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of create sql statement executions");
+DATA(insert OID = 3408 (  pg_stat_get_drop_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_drop_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of drop sql statement executions");
+DATA(insert OID = 3409 (  pg_stat_get_alter_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_alter_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of alter sql statement executions");
+DATA(insert OID = 3410 (  pg_stat_get_import_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_import_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of import sql statement executions");
+DATA(insert OID = 3411 (  pg_stat_get_truncate_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_truncate_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of truncate sql statement executions");
+DATA(insert OID = 3412 (  pg_stat_get_copy_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_copy_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of copy sql statement executions");
+DATA(insert OID = 3413 (  pg_stat_get_grant_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_grant_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of grant sql statement executions");
+DATA(insert OID = 3414 (  pg_stat_get_revoke_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_revoke_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of revoke sql statement executions");
+DATA(insert OID = 3415 (  pg_stat_get_cluster_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_cluster_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of cluster sql statement executions");
+DATA(insert OID = 3416 (  pg_stat_get_vacuum_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_vacuum_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of vacuum sql statement executions");
+DATA(insert OID = 3417 (  pg_stat_get_analyze_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_analyze_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of analyze sql statement executions");
+DATA(insert OID = 3418 (  pg_stat_get_refresh_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_refresh_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of refresh sql statement executions");
+DATA(insert OID = 3419 (  pg_stat_get_lock_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_lock_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of lock sql statement executions");
+DATA(insert OID = 3420 (  pg_stat_get_checkpoint_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_checkpoint_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of checkpoint sql statement executions");
+DATA(insert OID = 3421 (  pg_stat_get_reindex_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_reindex_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of reindex sql statement executions");
+DATA(insert OID = 3422 (  pg_stat_get_deallocate_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_deallocate_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of deallocate sql statement executions");
+DATA(insert OID = 3423 (  pg_stat_get_others_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_others_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of other sql statement executions");
+DATA(insert OID = 3424 (  pgx_stat_get_reset_time_sqlstmt	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ pgx_stat_get_reset_time_sqlstmt _null_ _null_ _null_ ));
+DESCR("statistics: number of other sql statement executions");
+
+
 DATA(insert OID = 3788 (  pg_stat_get_snapshot_timestamp PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 1184 "" _null_ _null_ _null_ _null_ _null_	pg_stat_get_snapshot_timestamp _null_ _null_ _null_ ));
 DESCR("statistics: timestamp of the current statistics snapshot");
 DATA(insert OID = 2230 (  pg_stat_clear_snapshot		PGNSP PGUID 12 1 0 0 0 f f f f f f v r 0 0 2278 "" _null_ _null_ _null_ _null_ _null_ pg_stat_clear_snapshot _null_ _null_ _null_ ));
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index dc3320d..44c6127 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -64,7 +64,8 @@ typedef enum StatMsgType
 	PGSTAT_MTYPE_FUNCPURGE,
 	PGSTAT_MTYPE_RECOVERYCONFLICT,
 	PGSTAT_MTYPE_TEMPFILE,
-	PGSTAT_MTYPE_DEADLOCK
+	PGSTAT_MTYPE_DEADLOCK,
+	PGSTAT_MTYPE_SQLSTMT
 } StatMsgType;
 
 /* ----------
@@ -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 */
@@ -530,6 +532,38 @@ typedef struct PgStat_MsgDeadlock
 	Oid			m_databaseid;
 } PgStat_MsgDeadlock;
 
+/* ----------
+ * PgStat_MsgSqlstmt			Sent by the sql to update statistics.
+ * ----------
+ */
+typedef struct PgStat_MsgSqlstmt
+{
+	PgStat_MsgHdr m_hdr;
+
+	PgStat_Counter 	n_insert_sqlstmt;
+	PgStat_Counter 	n_delete_sqlstmt;
+	PgStat_Counter 	n_update_sqlstmt;
+	PgStat_Counter 	n_select_sqlstmt;
+	PgStat_Counter 	n_declare_cursor_sqlstmt;
+	PgStat_Counter 	n_close_sqlstmt;
+	PgStat_Counter 	n_create_sqlstmt;
+	PgStat_Counter 	n_drop_sqlstmt;
+	PgStat_Counter 	n_alter_sqlstmt;
+	PgStat_Counter 	n_import_sqlstmt;
+	PgStat_Counter 	n_truncate_sqlstmt;
+	PgStat_Counter 	n_copy_sqlstmt;
+	PgStat_Counter 	n_grant_sqlstmt;
+	PgStat_Counter 	n_revoke_sqlstmt;
+	PgStat_Counter 	n_cluster_sqlstmt;
+	PgStat_Counter 	n_vacuum_sqlstmt;
+	PgStat_Counter 	n_analyze_sqlstmt;
+	PgStat_Counter 	n_refresh_sqlstmt;
+	PgStat_Counter 	n_lock_sqlstmt;
+	PgStat_Counter 	n_checkpoint_sqlstmt;
+	PgStat_Counter 	n_reindex_sqlstmt;
+	PgStat_Counter 	n_deallocate_sqlstmt;
+	PgStat_Counter 	n_others_sqlstmt;
+} PgStat_MsgSqlstmt;
 
 /* ----------
  * PgStat_Msg					Union over all possible messages.
@@ -555,6 +589,7 @@ typedef union PgStat_Msg
 	PgStat_MsgFuncpurge msg_funcpurge;
 	PgStat_MsgRecoveryConflict msg_recoveryconflict;
 	PgStat_MsgDeadlock msg_deadlock;
+	PgStat_MsgSqlstmt msg_sqlstmt;
 } PgStat_Msg;
 
 
@@ -566,7 +601,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
@@ -675,6 +710,34 @@ typedef struct PgStat_ArchiverStats
 	TimestampTz stat_reset_timestamp;
 } PgStat_ArchiverStats;
 
+typedef struct PgStat_SqlStmtStats
+{
+	PgStat_Counter 	n_insert_sqlstmt;
+	PgStat_Counter 	n_delete_sqlstmt;
+	PgStat_Counter 	n_update_sqlstmt;
+	PgStat_Counter 	n_select_sqlstmt;
+	PgStat_Counter 	n_declare_cursor_sqlstmt;
+	PgStat_Counter 	n_close_sqlstmt;
+	PgStat_Counter 	n_create_sqlstmt;
+	PgStat_Counter 	n_drop_sqlstmt;
+	PgStat_Counter 	n_alter_sqlstmt;
+	PgStat_Counter 	n_import_sqlstmt;
+	PgStat_Counter 	n_truncate_sqlstmt;
+	PgStat_Counter 	n_copy_sqlstmt;
+	PgStat_Counter 	n_grant_sqlstmt;
+	PgStat_Counter 	n_revoke_sqlstmt;
+	PgStat_Counter 	n_cluster_sqlstmt;
+	PgStat_Counter 	n_vacuum_sqlstmt;
+	PgStat_Counter 	n_analyze_sqlstmt;
+	PgStat_Counter 	n_refresh_sqlstmt;
+	PgStat_Counter 	n_lock_sqlstmt;
+	PgStat_Counter 	n_checkpoint_sqlstmt;
+	PgStat_Counter 	n_reindex_sqlstmt;
+	PgStat_Counter 	n_deallocate_sqlstmt;
+	PgStat_Counter 	n_others_sqlstmt;
+	TimestampTz stat_reset_timestamp;
+} PgStat_SqlStmtStats;
+
 /*
  * Global statistics kept in the stats collector
  */
@@ -918,6 +981,7 @@ typedef struct PgStat_FunctionCallUsage
  */
 extern bool pgstat_track_activities;
 extern bool pgstat_track_counts;
+extern bool pgstat_track_sql;
 extern int	pgstat_track_functions;
 extern PGDLLIMPORT int pgstat_track_activity_query_size;
 extern char *pgstat_stat_directory;
@@ -930,6 +994,11 @@ extern char *pgstat_stat_filename;
 extern PgStat_MsgBgWriter BgWriterStats;
 
 /*
+ * SQL statistics counter updated by each backend
+ */
+extern PgStat_MsgSqlstmt SqlstmtStatsLocal;
+
+/*
  * Updated by pgstat_count_buffer_*_time macros
  */
 extern PgStat_Counter pgStatBlockReadTime;
@@ -1141,5 +1210,6 @@ extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
 extern int	pgstat_fetch_stat_numbackends(void);
 extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void);
 extern PgStat_GlobalStats *pgstat_fetch_global(void);
+extern PgStat_SqlStmtStats *pgstat_fetch_sqlstmt(void);
 
 #endif   /* PGSTAT_H */
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 00700f2..b3c728d 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1795,6 +1795,30 @@ 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, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
      JOIN pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) ON ((s.pid = w.pid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
+pg_stat_sql| SELECT pg_stat_get_insert_sqlstmt() AS insert,
+    pg_stat_get_delete_sqlstmt() AS delete,
+    pg_stat_get_update_sqlstmt() AS update,
+    pg_stat_get_select_sqlstmt() AS "select",
+    pg_stat_get_declare_cursor_sqlstmt() AS declare_cursor,
+    pg_stat_get_close_sqlstmt() AS close,
+    pg_stat_get_create_sqlstmt() AS "create",
+    pg_stat_get_drop_sqlstmt() AS drop,
+    pg_stat_get_alter_sqlstmt() AS alter,
+    pg_stat_get_import_sqlstmt() AS import,
+    pg_stat_get_truncate_sqlstmt() AS truncate,
+    pg_stat_get_copy_sqlstmt() AS copy,
+    pg_stat_get_grant_sqlstmt() AS "grant",
+    pg_stat_get_revoke_sqlstmt() AS revoke,
+    pg_stat_get_cluster_sqlstmt() AS cluster,
+    pg_stat_get_vacuum_sqlstmt() AS vacuum,
+    pg_stat_get_analyze_sqlstmt() AS "analyze",
+    pg_stat_get_refresh_sqlstmt() AS refresh,
+    pg_stat_get_lock_sqlstmt() AS lock,
+    pg_stat_get_checkpoint_sqlstmt() AS checkpoint,
+    pg_stat_get_reindex_sqlstmt() AS reindex,
+    pg_stat_get_deallocate_sqlstmt() AS deallocate,
+    pg_stat_get_others_sqlstmt() AS others,
+    pgx_stat_get_reset_time_sqlstmt() AS stats_reset;
 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 a811265..3e41de4 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -4,6 +4,55 @@
 -- Must be run after tenk2 has been created (by create_table),
 -- populated (by create_misc) and indexed (by create_index).
 --
+-- pg_stat_sql
+SHOW track_sql; -- must be off
+ track_sql 
+-----------
+ off
+(1 row)
+
+SELECT pg_stat_sql.select, pg_stat_sql.others FROM pg_stat_sql;
+ select | others 
+--------+--------
+      0 |      0
+(1 row)
+
+SET track_sql TO ON;
+-- force the rate-limiting logic in pgstat_report_stat() to time out
+-- and send a message
+SELECT pg_sleep(1.0);
+ pg_sleep 
+----------
+ 
+(1 row)
+
+SELECT pg_stat_sql.select, pg_stat_sql.others FROM pg_stat_sql;
+ select | others 
+--------+--------
+      1 |      1
+(1 row)
+
+SET track_sql TO OFF;
+SELECT pg_stat_reset_shared('sqlstmt'); -- reset the counters
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+-- force the rate-limiting logic in pgstat_report_stat() to time out
+-- and send a message
+SELECT pg_sleep(1.0);
+ pg_sleep 
+----------
+ 
+(1 row)
+
+SELECT pg_stat_sql.select, pg_stat_sql.others FROM pg_stat_sql;
+ select | others 
+--------+--------
+      0 |      0
+(1 row)
+
 -- 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 b3e2efa..88e1d5e 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -5,6 +5,25 @@
 -- populated (by create_misc) and indexed (by create_index).
 --
 
+-- pg_stat_sql
+SHOW track_sql; -- must be off
+SELECT pg_stat_sql.select, pg_stat_sql.others FROM pg_stat_sql;
+
+SET track_sql TO ON;
+
+-- force the rate-limiting logic in pgstat_report_stat() to time out
+-- and send a message
+SELECT pg_sleep(1.0);
+SELECT pg_stat_sql.select, pg_stat_sql.others FROM pg_stat_sql;
+
+SET track_sql TO OFF;
+SELECT pg_stat_reset_shared('sqlstmt'); -- reset the counters
+
+-- force the rate-limiting logic in pgstat_report_stat() to time out
+-- and send a message
+SELECT pg_sleep(1.0);
+SELECT pg_stat_sql.select, pg_stat_sql.others FROM pg_stat_sql;
+
 -- conditio sine qua non
 SHOW track_counts;  -- must be on
 
