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;
+
+ track_sql (boolean)
+
+ track_sql> configuration parameter
+
+
+
+
+ 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.
+
+
+
+
stats_temp_directory (string)
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
VACUUM>, showing current progress.
See .
+
+
+ pg_stat_sql>pg_stat_sql
+ One row only, showing statistics about the SQL statements that are
+ executed on the instance.
+ See for details.
+
@@ -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.
+
+ pg_stat_sql View
+
+
+
+ Column
+ Type
+ Description
+
+
+
+
+
+ insert>
+ bigint>
+ Number of insert SQL statements executed
+
+
+ delete>
+ bigint>
+ Number of delete SQL statements executed
+
+
+ update>
+ bigint>
+ Number of update SQL statements executed
+
+
+ select>
+ bigint>
+ Number of select SQL statements executed
+
+
+ declar_cursor>
+ bigint>
+ Number of declare_cursor SQL statements executed
+
+
+ close>
+ bigint>
+ Number of close SQL statements executed
+
+
+ create>
+ bigint>
+ Number of create SQL statements executed
+
+
+ drop>
+ bigint>
+ Number of drop SQL statements executed
+
+
+ alter>
+ bigint>
+ Number of alter SQL statements executed
+
+
+ import>
+ bigint>
+ Number of import SQL statements executed
+
+
+ truncate>
+ bigint>
+ Number of truncate SQL statements executed
+
+
+ copy>
+ bigint>
+ Number of copy SQL statements executed
+
+
+ grant>
+ bigint>
+ Number of grant SQL statements executed
+
+
+ revoke>
+ bigint>
+ Number of revoke SQL statements executed
+
+
+ cluster>
+ bigint>
+ Number of cluster SQL statements executed
+
+
+ vacuum>
+ bigint>
+ Number of vacuum SQL statements executed
+
+
+ analyze>
+ bigint>
+ Number of analyze SQL statements executed
+
+
+ refresh>
+ bigint>
+ Number of refresh SQL statements executed
+
+
+ lock>
+ bigint>
+ Number of lock SQL statements executed
+
+
+ checkpoint>
+ bigint>
+ Number of checkpoint SQL statements executed
+
+
+ reindex>
+ bigint>
+ Number of reindex SQL statements executed
+
+
+ deallocate>
+ bigint>
+ Number of deallocate SQL statements executed
+
+
+ others>
+ bigint>
+ Number of others SQL statements executed
+
+
+ stats_reset>
+ timestamp with time zone
+ Time at which these statistics were last reset
+
+
+
+
+
+
+ The pg_stat_sql view will contain only
+ one row, showing statistics about number of SQL statements that are
+ executed on the instance. The parameter
+ controls the SQL statement execution statistics.
+
+
+
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