doc/src/sgml/config.sgml | 2 +-
doc/src/sgml/monitoring.sgml | 14 ++++
src/backend/access/heap/vacuumlazy.c | 2 +-
src/backend/access/nbtree/nbtsort.c | 2 +-
src/backend/catalog/system_views.sql | 1 +
src/backend/executor/execParallel.c | 24 ++++++-
src/backend/postmaster/autovacuum.c | 4 +-
src/backend/postmaster/pgstat.c | 57 +++++++++++++++-
src/backend/replication/logical/worker.c | 6 +-
src/backend/replication/walsender.c | 6 +-
src/backend/tcop/postgres.c | 58 ++++++++++++----
src/backend/utils/adt/pgstatfuncs.c | 114 +++++++++++++++++--------------
src/include/catalog/pg_proc.dat | 6 +-
src/include/pgstat.h | 11 ++-
src/test/modules/worker_spi/worker_spi.c | 8 +--
src/test/regress/expected/rules.out | 9 +--
16 files changed, 230 insertions(+), 94 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 7a7177c550..d2b415629b 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7230,7 +7230,7 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
Specifies the amount of memory reserved to store the text of the
currently executing command for each active session, for the
- pg_stat_activity.query field.
+ pg_stat_activity.query and individual_query fields.
If this value is specified without units, it is taken as bytes.
The default value is 1024 bytes.
This parameter can only be set at server start.
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 7dcddf478a..71782e9ffa 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -896,6 +896,20 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
+
+
+ individual_query text
+
+
+ Text of this backend's most recent individual query in case query contains multiple statements. If
+ state is active this field shows the
+ currently executing individual query. In all other states, it shows the last individual query
+ that was executed. By default the individual query text is truncated at 1024
+ bytes; this value can be changed via the parameter
+ .
+
+
+
backend_type text
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 1bbc4598f7..f9a0ca4bdf 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -3489,7 +3489,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
/* Set debug_query_string for individual workers */
sharedquery = shm_toc_lookup(toc, PARALLEL_VACUUM_KEY_QUERY_TEXT, false);
debug_query_string = sharedquery;
- pgstat_report_activity(STATE_RUNNING, debug_query_string);
+ pgstat_report_activity(STATE_RUNNING, debug_query_string, NULL);
/*
* Open table. The lock mode is the same as the leader process. It's
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index efee86784b..11494a2f7d 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -1810,7 +1810,7 @@ _bt_parallel_build_main(dsm_segment *seg, shm_toc *toc)
debug_query_string = sharedquery;
/* Report the query string from leader */
- pgstat_report_activity(STATE_RUNNING, debug_query_string);
+ pgstat_report_activity(STATE_RUNNING, debug_query_string, NULL);
/* Look up nbtree shared state */
btshared = shm_toc_lookup(toc, PARALLEL_KEY_BTREE_SHARED, false);
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 8625cbeab6..a411f8b548 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -759,6 +759,7 @@ CREATE VIEW pg_stat_activity AS
S.backend_xid,
s.backend_xmin,
S.query,
+ S.individual_query,
S.backend_type
FROM pg_stat_get_activity(NULL) AS S
LEFT JOIN pg_database AS D ON (S.datid = D.oid)
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index 382e78fb7f..19ebaf13b3 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -65,6 +65,7 @@
#define PARALLEL_KEY_QUERY_TEXT UINT64CONST(0xE000000000000008)
#define PARALLEL_KEY_JIT_INSTRUMENTATION UINT64CONST(0xE000000000000009)
#define PARALLEL_KEY_WAL_USAGE UINT64CONST(0xE00000000000000A)
+#define PARALLEL_KEY_INDIVIDUAL_QUERY_TEXT UINT64CONST(0xE00000000000000B)
#define PARALLEL_TUPLE_QUEUE_SIZE 65536
@@ -600,7 +601,9 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate,
int instrument_offset = 0;
Size dsa_minsize = dsa_minimum_size();
char *query_string;
+ char *individual_query_string;
int query_len;
+ int individual_query_len;
/*
* Force any initplan outputs that we're going to pass to workers to be
@@ -638,6 +641,15 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate,
sizeof(FixedParallelExecutorState));
shm_toc_estimate_keys(&pcxt->estimator, 1);
+ /* Estimate space for individual query text. */
+ if (estate->es_plannedstmt->stmt_len == 0)
+ individual_query_len = strlen(estate->es_sourceText) - estate->es_plannedstmt->stmt_location;
+ else
+ individual_query_len = estate->es_plannedstmt->stmt_len;
+
+ shm_toc_estimate_chunk(&pcxt->estimator, individual_query_len + 1);
+ shm_toc_estimate_keys(&pcxt->estimator, 1);
+
/* Estimate space for query text. */
query_len = strlen(estate->es_sourceText);
shm_toc_estimate_chunk(&pcxt->estimator, query_len + 1);
@@ -732,6 +744,11 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate,
fpes->jit_flags = estate->es_jit_flags;
shm_toc_insert(pcxt->toc, PARALLEL_KEY_EXECUTOR_FIXED, fpes);
+ /* Store individual query string */
+ individual_query_string = shm_toc_allocate(pcxt->toc, individual_query_len + 1);
+ memcpy(individual_query_string, estate->es_sourceText + estate->es_plannedstmt->stmt_location, individual_query_len + 1);
+ shm_toc_insert(pcxt->toc, PARALLEL_KEY_INDIVIDUAL_QUERY_TEXT, individual_query_string);
+
/* Store query string */
query_string = shm_toc_allocate(pcxt->toc, query_len + 1);
memcpy(query_string, estate->es_sourceText, query_len + 1);
@@ -1388,6 +1405,7 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc)
void *area_space;
dsa_area *area;
ParallelWorkerContext pwcxt;
+ char *individual_query;
/* Get fixed-size state. */
fpes = shm_toc_lookup(toc, PARALLEL_KEY_EXECUTOR_FIXED, false);
@@ -1403,9 +1421,13 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc)
/* Setting debug_query_string for individual workers */
debug_query_string = queryDesc->sourceText;
+ individual_query = shm_toc_lookup(toc, PARALLEL_KEY_INDIVIDUAL_QUERY_TEXT, false);
/* Report workers' query for monitoring purposes */
- pgstat_report_activity(STATE_RUNNING, debug_query_string);
+ if (strlen(debug_query_string) != strlen(individual_query))
+ pgstat_report_activity(STATE_RUNNING, debug_query_string, individual_query);
+ else
+ pgstat_report_activity(STATE_RUNNING, debug_query_string, NULL);
/* Attach to the dynamic shared memory area. */
area_space = shm_toc_lookup(toc, PARALLEL_KEY_DSA, false);
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 9c7d4b0c60..340ab8a76e 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -3176,7 +3176,7 @@ autovac_report_activity(autovac_table *tab)
/* Set statement_timestamp() to current time for pg_stat_activity */
SetCurrentStatementStartTimestamp();
- pgstat_report_activity(STATE_RUNNING, activity);
+ pgstat_report_activity(STATE_RUNNING, activity, NULL);
}
/*
@@ -3215,7 +3215,7 @@ autovac_report_workitem(AutoVacuumWorkItem *workitem,
/* Set statement_timestamp() to current time for pg_stat_activity */
SetCurrentStatementStartTimestamp();
- pgstat_report_activity(STATE_RUNNING, activity);
+ pgstat_report_activity(STATE_RUNNING, activity, NULL);
}
/*
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 15f92b66c6..44fb7e77eb 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2702,7 +2702,9 @@ static PgBackendStatus *MyBEEntry = NULL;
static char *BackendAppnameBuffer = NULL;
static char *BackendClientHostnameBuffer = NULL;
static char *BackendActivityBuffer = NULL;
+static char *BackendIndividualActivityBuffer = NULL;
static Size BackendActivityBufferSize = 0;
+static Size BackendIndividualActivityBufferSize = 0;
#ifdef USE_SSL
static PgBackendSSLStatus *BackendSslStatusBuffer = NULL;
#endif
@@ -2730,6 +2732,9 @@ BackendStatusShmemSize(void)
/* BackendActivityBuffer: */
size = add_size(size,
mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
+ /* BackendIndividualActivityBuffer: */
+ size = add_size(size,
+ mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
#ifdef USE_SSL
/* BackendSslStatusBuffer: */
size = add_size(size,
@@ -2820,6 +2825,27 @@ CreateSharedBackendStatus(void)
}
}
+ /* Create or attach to the indiviudal shared activity buffer */
+ BackendIndividualActivityBufferSize = mul_size(pgstat_track_activity_query_size,
+ NumBackendStatSlots);
+ BackendIndividualActivityBuffer = (char *)
+ ShmemInitStruct("Backend Individual Activity Buffer",
+ BackendIndividualActivityBufferSize,
+ &found);
+
+ if (!found)
+ {
+ MemSet(BackendIndividualActivityBuffer, 0, BackendIndividualActivityBufferSize);
+
+ /* Initialize st_individual_activity pointers. */
+ buffer = BackendIndividualActivityBuffer;
+ for (i = 0; i < NumBackendStatSlots; i++)
+ {
+ BackendStatusArray[i].st_individual_activity_raw = buffer;
+ buffer += pgstat_track_activity_query_size;
+ }
+ }
+
#ifdef USE_SSL
/* Create or attach to the shared SSL status buffer */
size = mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots);
@@ -3062,10 +3088,12 @@ pgstat_bestart(void)
else
lbeentry.st_clienthostname[0] = '\0';
lbeentry.st_activity_raw[0] = '\0';
+ lbeentry.st_individual_activity_raw[0] = '\0';
/* Also make sure the last byte in each string area is always 0 */
lbeentry.st_appname[NAMEDATALEN - 1] = '\0';
lbeentry.st_clienthostname[NAMEDATALEN - 1] = '\0';
lbeentry.st_activity_raw[pgstat_track_activity_query_size - 1] = '\0';
+ lbeentry.st_individual_activity_raw[pgstat_track_activity_query_size - 1] = '\0';
#ifdef USE_SSL
memcpy(lbeentry.st_sslstatus, &lsslstatus, sizeof(PgBackendSSLStatus));
@@ -3129,12 +3157,13 @@ pgstat_beshutdown_hook(int code, Datum arg)
* ----------
*/
void
-pgstat_report_activity(BackendState state, const char *cmd_str)
+pgstat_report_activity(BackendState state, const char *cmd_str, const char *individual_cmd_str)
{
volatile PgBackendStatus *beentry = MyBEEntry;
TimestampTz start_timestamp;
TimestampTz current_timestamp;
int len = 0;
+ int individual_len = 0;
TRACE_POSTGRESQL_STATEMENT_STATUS(cmd_str);
@@ -3156,6 +3185,7 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
beentry->st_state = STATE_DISABLED;
beentry->st_state_start_timestamp = 0;
beentry->st_activity_raw[0] = '\0';
+ beentry->st_individual_activity_raw[0] = '\0';
beentry->st_activity_start_timestamp = 0;
/* st_xact_start_timestamp and wait_event_info are also disabled */
beentry->st_xact_start_timestamp = 0;
@@ -3179,6 +3209,16 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
*/
len = Min(strlen(cmd_str), pgstat_track_activity_query_size - 1);
}
+
+ if (individual_cmd_str != NULL)
+ {
+ /*
+ * Compute length of to-be-stored string unaware of multi-byte
+ * characters. For speed reasons that'll get corrected on read, rather
+ * than computed every write.
+ */
+ individual_len = Min(strlen(individual_cmd_str), pgstat_track_activity_query_size - 1);
+ }
current_timestamp = GetCurrentTimestamp();
/*
@@ -3196,6 +3236,12 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
beentry->st_activity_start_timestamp = start_timestamp;
}
+ if (individual_cmd_str != NULL)
+ {
+ memcpy((char *) beentry->st_individual_activity_raw, individual_cmd_str, individual_len);
+ beentry->st_individual_activity_raw[len] = '\0';
+ }
+
PGSTAT_END_WRITE_ACTIVITY(beentry);
}
@@ -3365,7 +3411,8 @@ pgstat_read_current_status(void)
LocalPgBackendStatus *localentry;
char *localappname,
*localclienthostname,
- *localactivity;
+ *localactivity,
+ *local_individual_activity;
#ifdef USE_SSL
PgBackendSSLStatus *localsslstatus;
#endif
@@ -3400,6 +3447,9 @@ pgstat_read_current_status(void)
localactivity = (char *)
MemoryContextAllocHuge(pgStatLocalContext,
pgstat_track_activity_query_size * NumBackendStatSlots);
+ local_individual_activity = (char *)
+ MemoryContextAllocHuge(pgStatLocalContext,
+ pgstat_track_activity_query_size * NumBackendStatSlots);
#ifdef USE_SSL
localsslstatus = (PgBackendSSLStatus *)
MemoryContextAlloc(pgStatLocalContext,
@@ -3451,6 +3501,8 @@ pgstat_read_current_status(void)
localentry->backendStatus.st_clienthostname = localclienthostname;
strcpy(localactivity, (char *) beentry->st_activity_raw);
localentry->backendStatus.st_activity_raw = localactivity;
+ strcpy(local_individual_activity, (char *) beentry->st_individual_activity_raw);
+ localentry->backendStatus.st_individual_activity_raw = local_individual_activity;
#ifdef USE_SSL
if (beentry->st_ssl)
{
@@ -3489,6 +3541,7 @@ pgstat_read_current_status(void)
localappname += NAMEDATALEN;
localclienthostname += NAMEDATALEN;
localactivity += pgstat_track_activity_query_size;
+ local_individual_activity += pgstat_track_activity_query_size;
#ifdef USE_SSL
localsslstatus++;
#endif
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 2fcf2e61bc..de7f0ce0af 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -556,7 +556,7 @@ apply_handle_begin(StringInfo s)
in_remote_transaction = true;
- pgstat_report_activity(STATE_RUNNING, NULL);
+ pgstat_report_activity(STATE_RUNNING, NULL, NULL);
}
/*
@@ -600,7 +600,7 @@ apply_handle_commit(StringInfo s)
/* Process any tables that are being synchronized in parallel. */
process_syncing_tables(commit_data.end_lsn);
- pgstat_report_activity(STATE_IDLE, NULL);
+ pgstat_report_activity(STATE_IDLE, NULL, NULL);
}
/*
@@ -1571,7 +1571,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
ALLOCSET_DEFAULT_SIZES);
/* mark as idle, before starting to loop */
- pgstat_report_activity(STATE_IDLE, NULL);
+ pgstat_report_activity(STATE_IDLE, NULL, NULL);
for (;;)
{
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 5e2210dd7b..fd9225a987 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1601,7 +1601,7 @@ exec_replication_command(const char *cmd_string)
initStringInfo(&tmpbuf);
/* Report to pgstat that this process is running */
- pgstat_report_activity(STATE_RUNNING, NULL);
+ pgstat_report_activity(STATE_RUNNING, NULL, NULL);
switch (cmd_node->type)
{
@@ -1660,7 +1660,7 @@ exec_replication_command(const char *cmd_string)
(errmsg("cannot execute SQL commands in WAL sender for physical replication")));
/* Report to pgstat that this process is now idle */
- pgstat_report_activity(STATE_IDLE, NULL);
+ pgstat_report_activity(STATE_IDLE, NULL, NULL);
/* Tell the caller that this wasn't a WalSender command. */
return false;
@@ -1679,7 +1679,7 @@ exec_replication_command(const char *cmd_string)
EndCommand(&qc, DestRemote, true);
/* Report to pgstat that this process is now idle */
- pgstat_report_activity(STATE_IDLE, NULL);
+ pgstat_report_activity(STATE_IDLE, NULL, NULL);
return true;
}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index c9424f167c..98544439b0 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -167,6 +167,9 @@ static ProcSignalReason RecoveryConflictReason;
static MemoryContext row_description_context = NULL;
static StringInfoData row_description_buf;
+/* reused buffer to pass the individual queries */
+static StringInfoData individual_query_buf;
+
/* ----------------------------------------------------------------
* decls for routines only used in this file
* ----------------------------------------------------------------
@@ -991,14 +994,6 @@ exec_simple_query(const char *query_string)
bool use_implicit_block;
char msec_str[32];
- /*
- * Report query to various monitoring facilities.
- */
- debug_query_string = query_string;
-
- pgstat_report_activity(STATE_RUNNING, query_string);
-
- TRACE_POSTGRESQL_QUERY_START(query_string);
/*
* We use save_log_statement_stats so ShowUsage doesn't report incorrect
@@ -1075,7 +1070,38 @@ exec_simple_query(const char *query_string)
Portal portal;
DestReceiver *receiver;
int16 format;
+ char *individual_query;
+ int individual_query_length;
+
+ /* if statement does not end with ;
+ * then parsetree->stmt_len == 0
+ */
+ if (parsetree->stmt_len == 0)
+ individual_query_length = strlen(query_string) - parsetree->stmt_location;
+ else
+ individual_query_length = parsetree->stmt_len + 1;
+ /* extract the query text */
+ individual_query = palloc(individual_query_length + 1);
+ strncpy(individual_query, query_string + parsetree->stmt_location, individual_query_length);
+ individual_query[individual_query_length] = '\0';
+ /*
+ * Report query to various monitoring facilities.
+ */
+
+ resetStringInfo(&individual_query_buf);
+ appendStringInfoString(&individual_query_buf, individual_query);
+
+ debug_query_string = query_string;
+
+ if (strlen(debug_query_string) != individual_query_buf.len)
+ pgstat_report_activity(STATE_RUNNING, query_string, individual_query_buf.data);
+ else
+ pgstat_report_activity(STATE_RUNNING, query_string, NULL);
+
+ TRACE_POSTGRESQL_QUERY_START(query_string);
+
+ pfree(individual_query);
/*
* Get the command name for use in status display (it also becomes the
* default completion tag, down inside PortalRun). Set ps_status and
@@ -1366,7 +1392,7 @@ exec_parse_message(const char *query_string, /* string to execute */
*/
debug_query_string = query_string;
- pgstat_report_activity(STATE_RUNNING, query_string);
+ pgstat_report_activity(STATE_RUNNING, query_string, NULL);
set_ps_display("PARSE");
@@ -1657,7 +1683,7 @@ exec_bind_message(StringInfo input_message)
*/
debug_query_string = psrc->query_string;
- pgstat_report_activity(STATE_RUNNING, psrc->query_string);
+ pgstat_report_activity(STATE_RUNNING, psrc->query_string, NULL);
set_ps_display("BIND");
@@ -2115,7 +2141,7 @@ exec_execute_message(const char *portal_name, long max_rows)
*/
debug_query_string = sourceText;
- pgstat_report_activity(STATE_RUNNING, sourceText);
+ pgstat_report_activity(STATE_RUNNING, sourceText, NULL);
set_ps_display(GetCommandTagName(portal->commandTag));
@@ -4011,6 +4037,8 @@ PostgresMain(int argc, char *argv[],
initStringInfo(&row_description_buf);
MemoryContextSwitchTo(TopMemoryContext);
+ initStringInfo(&individual_query_buf);
+
/*
* Remember stand-alone backend startup time
*/
@@ -4196,7 +4224,7 @@ PostgresMain(int argc, char *argv[],
if (IsAbortedTransactionBlockState())
{
set_ps_display("idle in transaction (aborted)");
- pgstat_report_activity(STATE_IDLEINTRANSACTION_ABORTED, NULL);
+ pgstat_report_activity(STATE_IDLEINTRANSACTION_ABORTED, NULL, NULL);
/* Start the idle-in-transaction timer */
if (IdleInTransactionSessionTimeout > 0)
@@ -4209,7 +4237,7 @@ PostgresMain(int argc, char *argv[],
else if (IsTransactionOrTransactionBlock())
{
set_ps_display("idle in transaction");
- pgstat_report_activity(STATE_IDLEINTRANSACTION, NULL);
+ pgstat_report_activity(STATE_IDLEINTRANSACTION, NULL, NULL);
/* Start the idle-in-transaction timer */
if (IdleInTransactionSessionTimeout > 0)
@@ -4236,7 +4264,7 @@ PostgresMain(int argc, char *argv[],
pgstat_report_stat(false);
set_ps_display("idle");
- pgstat_report_activity(STATE_IDLE, NULL);
+ pgstat_report_activity(STATE_IDLE, NULL, NULL);
}
ReadyForQuery(whereToSendOutput);
@@ -4384,7 +4412,7 @@ PostgresMain(int argc, char *argv[],
SetCurrentStatementStartTimestamp();
/* Report query to various monitoring facilities. */
- pgstat_report_activity(STATE_FASTPATH, NULL);
+ pgstat_report_activity(STATE_FASTPATH, NULL, NULL);
set_ps_display("");
/* start an xact for this function invocation */
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 95738a4e34..976dfc7583 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -567,7 +567,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
Datum
pg_stat_get_activity(PG_FUNCTION_ARGS)
{
-#define PG_STAT_GET_ACTIVITY_COLS 30
+#define PG_STAT_GET_ACTIVITY_COLS 31
int num_backends = pgstat_fetch_stat_numbackends();
int curr_backend;
int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
@@ -631,6 +631,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
nulls[5] = false;
values[5] = CStringGetTextDatum("");
+ nulls[6] = false;
+ values[6] = CStringGetTextDatum("");
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
continue;
@@ -661,20 +663,21 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
nulls[3] = true;
if (TransactionIdIsValid(local_beentry->backend_xid))
- values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
+ values[16] = TransactionIdGetDatum(local_beentry->backend_xid);
else
- nulls[15] = true;
+ nulls[16] = true;
if (TransactionIdIsValid(local_beentry->backend_xmin))
- values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
+ values[17] = TransactionIdGetDatum(local_beentry->backend_xmin);
else
- nulls[16] = true;
+ nulls[17] = true;
/* Values only available to role member or pg_read_all_stats */
if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
{
SockAddr zero_clientaddr;
char *clipped_activity;
+ char *clipped_individual_activity;
switch (beentry->st_state)
{
@@ -705,8 +708,12 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
values[5] = CStringGetTextDatum(clipped_activity);
pfree(clipped_activity);
+ clipped_individual_activity = pgstat_clip_activity(beentry->st_individual_activity_raw);
+ values[6] = CStringGetTextDatum(clipped_individual_activity);
+ pfree(clipped_individual_activity);
+
/* leader_pid */
- nulls[29] = true;
+ nulls[30] = true;
proc = BackendPidGetProc(beentry->st_procpid);
@@ -743,20 +750,20 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
*/
if (leader && leader->pid != beentry->st_procpid)
{
- values[29] = Int32GetDatum(leader->pid);
- nulls[29] = false;
+ values[30] = Int32GetDatum(leader->pid);
+ nulls[30] = false;
}
}
if (wait_event_type)
- values[6] = CStringGetTextDatum(wait_event_type);
+ values[7] = CStringGetTextDatum(wait_event_type);
else
- nulls[6] = true;
+ nulls[7] = true;
if (wait_event)
- values[7] = CStringGetTextDatum(wait_event);
+ values[8] = CStringGetTextDatum(wait_event);
else
- nulls[7] = true;
+ nulls[8] = true;
/*
* Don't expose transaction time for walsenders; it confuses
@@ -765,33 +772,33 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
*/
if (beentry->st_xact_start_timestamp != 0 &&
beentry->st_backendType != B_WAL_SENDER)
- values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
+ values[9] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
else
- nulls[8] = true;
+ nulls[9] = true;
if (beentry->st_activity_start_timestamp != 0)
- values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
+ values[10] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
else
- nulls[9] = true;
+ nulls[10] = true;
if (beentry->st_proc_start_timestamp != 0)
- values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
+ values[11] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
else
- nulls[10] = true;
+ nulls[11] = true;
if (beentry->st_state_start_timestamp != 0)
- values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
+ values[12] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
else
- nulls[11] = true;
+ nulls[12] = true;
/* A zeroed client addr means we don't know */
memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
sizeof(zero_clientaddr)) == 0)
{
- nulls[12] = true;
nulls[13] = true;
nulls[14] = true;
+ nulls[15] = true;
}
else
{
@@ -815,20 +822,20 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
if (ret == 0)
{
clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
- values[12] = DirectFunctionCall1(inet_in,
+ values[13] = DirectFunctionCall1(inet_in,
CStringGetDatum(remote_host));
if (beentry->st_clienthostname &&
beentry->st_clienthostname[0])
- values[13] = CStringGetTextDatum(beentry->st_clienthostname);
+ values[14] = CStringGetTextDatum(beentry->st_clienthostname);
else
- nulls[13] = true;
- values[14] = Int32GetDatum(atoi(remote_port));
+ nulls[14] = true;
+ values[15] = Int32GetDatum(atoi(remote_port));
}
else
{
- nulls[12] = true;
nulls[13] = true;
nulls[14] = true;
+ nulls[15] = true;
}
}
else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
@@ -839,16 +846,16 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
* connections we have no permissions to view, or with
* errors.
*/
- nulls[12] = true;
nulls[13] = true;
- values[14] = Int32GetDatum(-1);
+ nulls[14] = true;
+ values[15] = Int32GetDatum(-1);
}
else
{
/* Unknown address type, should never happen */
- nulls[12] = true;
nulls[13] = true;
nulls[14] = true;
+ nulls[15] = true;
}
}
/* Add backend type */
@@ -858,59 +865,59 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
bgw_type = GetBackgroundWorkerTypeByPid(beentry->st_procpid);
if (bgw_type)
- values[17] = CStringGetTextDatum(bgw_type);
+ values[18] = CStringGetTextDatum(bgw_type);
else
- nulls[17] = true;
+ nulls[18] = true;
}
else
- values[17] =
+ values[18] =
CStringGetTextDatum(GetBackendTypeDesc(beentry->st_backendType));
/* SSL information */
if (beentry->st_ssl)
{
- values[18] = BoolGetDatum(true); /* ssl */
- values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
- values[20] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
- values[21] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
- values[22] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
+ values[19] = BoolGetDatum(true); /* ssl */
+ values[20] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
+ values[21] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
+ values[22] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
+ values[23] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
if (beentry->st_sslstatus->ssl_client_dn[0])
- values[23] = CStringGetTextDatum(beentry->st_sslstatus->ssl_client_dn);
+ values[24] = CStringGetTextDatum(beentry->st_sslstatus->ssl_client_dn);
else
- nulls[23] = true;
+ nulls[24] = true;
if (beentry->st_sslstatus->ssl_client_serial[0])
- values[24] = DirectFunctionCall3(numeric_in,
+ values[25] = DirectFunctionCall3(numeric_in,
CStringGetDatum(beentry->st_sslstatus->ssl_client_serial),
ObjectIdGetDatum(InvalidOid),
Int32GetDatum(-1));
else
- nulls[24] = true;
+ nulls[25] = true;
if (beentry->st_sslstatus->ssl_issuer_dn[0])
- values[25] = CStringGetTextDatum(beentry->st_sslstatus->ssl_issuer_dn);
+ values[26] = CStringGetTextDatum(beentry->st_sslstatus->ssl_issuer_dn);
else
- nulls[25] = true;
+ nulls[26] = true;
}
else
{
- values[18] = BoolGetDatum(false); /* ssl */
- nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = nulls[25] = true;
+ values[19] = BoolGetDatum(false); /* ssl */
+ nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = nulls[25] = nulls[26] = true;
}
/* GSSAPI information */
if (beentry->st_gss)
{
- values[26] = BoolGetDatum(beentry->st_gssstatus->gss_auth); /* gss_auth */
- values[27] = CStringGetTextDatum(beentry->st_gssstatus->gss_princ);
- values[28] = BoolGetDatum(beentry->st_gssstatus->gss_enc); /* GSS Encryption in use */
+ values[27] = BoolGetDatum(beentry->st_gssstatus->gss_auth); /* gss_auth */
+ values[28] = CStringGetTextDatum(beentry->st_gssstatus->gss_princ);
+ values[29] = BoolGetDatum(beentry->st_gssstatus->gss_enc); /* GSS Encryption in use */
}
else
{
- values[26] = BoolGetDatum(false); /* gss_auth */
- nulls[27] = true; /* No GSS principal */
- values[28] = BoolGetDatum(false); /* GSS Encryption not in
+ values[27] = BoolGetDatum(false); /* gss_auth */
+ nulls[28] = true; /* No GSS principal */
+ values[29] = BoolGetDatum(false); /* GSS Encryption not in
* use */
}
}
@@ -918,8 +925,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
{
/* No permissions to view data about this session */
values[5] = CStringGetTextDatum("");
+ values[6] = CStringGetTextDatum("");
nulls[4] = true;
- nulls[6] = true;
nulls[7] = true;
nulls[8] = true;
nulls[9] = true;
@@ -928,7 +935,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
nulls[12] = true;
nulls[13] = true;
nulls[14] = true;
- nulls[17] = true;
+ nulls[15] = true;
nulls[18] = true;
nulls[19] = true;
nulls[20] = true;
@@ -941,6 +948,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
nulls[27] = true;
nulls[28] = true;
nulls[29] = true;
+ nulls[30] = true;
}
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 082a11f270..a4451c1ef6 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5222,9 +5222,9 @@
proname => 'pg_stat_get_activity', prorows => '100', proisstrict => 'f',
proretset => 't', provolatile => 's', proparallel => 'r',
prorettype => 'record', proargtypes => 'int4',
- proallargtypes => '{int4,oid,int4,oid,text,text,text,text,text,timestamptz,timestamptz,timestamptz,timestamptz,inet,text,int4,xid,xid,text,bool,text,text,int4,bool,text,numeric,text,bool,text,bool,int4}',
- proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
- proargnames => '{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,sslcompression,ssl_client_dn,ssl_client_serial,ssl_issuer_dn,gss_auth,gss_princ,gss_enc,leader_pid}',
+ proallargtypes => '{int4,oid,int4,oid,text,text,text,text,text,text,timestamptz,timestamptz,timestamptz,timestamptz,inet,text,int4,xid,xid,text,bool,text,text,int4,bool,text,numeric,text,bool,text,bool,int4}',
+ proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
+ proargnames => '{pid,datid,pid,usesysid,application_name,state,query,individual_query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,sslcompression,ssl_client_dn,ssl_client_serial,ssl_issuer_dn,gss_auth,gss_princ,gss_enc,leader_pid}',
prosrc => 'pg_stat_get_activity' },
{ oid => '3318',
descr => 'statistics: information about progress of backends running maintenance command',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 1387201382..f29dfcbf13 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -1123,6 +1123,15 @@ typedef struct PgBackendStatus
*/
char *st_activity_raw;
+ /*
+ * Current individual command string; MUST be null-terminated. Note that this string
+ * possibly is truncated in the middle of a multi-byte character. As
+ * activity strings are stored more frequently than read, that allows to
+ * move the cost of correct truncation to the display side. Use
+ * pgstat_clip_activity() to truncate correctly.
+ */
+ char *st_individual_activity_raw;
+
/*
* Command progress reporting. Any command which wishes can advertise
* that it is running by setting st_progress_command,
@@ -1314,7 +1323,7 @@ extern void pgstat_report_checksum_failure(void);
extern void pgstat_initialize(void);
extern void pgstat_bestart(void);
-extern void pgstat_report_activity(BackendState state, const char *cmd_str);
+extern void pgstat_report_activity(BackendState state, const char *cmd_str, const char *individual_cmd_str);
extern void pgstat_report_tempfile(size_t filesize);
extern void pgstat_report_appname(const char *appname);
extern void pgstat_report_xact_timestamp(TimestampTz tstamp);
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 1c7b17c56f..bc7b4a4a54 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -112,7 +112,7 @@ initialize_worker_spi(worktable *table)
StartTransactionCommand();
SPI_connect();
PushActiveSnapshot(GetTransactionSnapshot());
- pgstat_report_activity(STATE_RUNNING, "initializing worker_spi schema");
+ pgstat_report_activity(STATE_RUNNING, "initializing worker_spi schema", NULL);
/* XXX could we use CREATE SCHEMA IF NOT EXISTS? */
initStringInfo(&buf);
@@ -156,7 +156,7 @@ initialize_worker_spi(worktable *table)
SPI_finish();
PopActiveSnapshot();
CommitTransactionCommand();
- pgstat_report_activity(STATE_IDLE, NULL);
+ pgstat_report_activity(STATE_IDLE, NULL, NULL);
}
void
@@ -262,7 +262,7 @@ worker_spi_main(Datum main_arg)
StartTransactionCommand();
SPI_connect();
PushActiveSnapshot(GetTransactionSnapshot());
- pgstat_report_activity(STATE_RUNNING, buf.data);
+ pgstat_report_activity(STATE_RUNNING, buf.data, NULL);
/* We can now execute queries via SPI */
ret = SPI_execute(buf.data, false, 0);
@@ -292,7 +292,7 @@ worker_spi_main(Datum main_arg)
PopActiveSnapshot();
CommitTransactionCommand();
pgstat_report_stat(false);
- pgstat_report_activity(STATE_IDLE, NULL);
+ pgstat_report_activity(STATE_IDLE, NULL, NULL);
}
proc_exit(1);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 601734a6f1..5635e80811 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1751,8 +1751,9 @@ pg_stat_activity| SELECT s.datid,
s.backend_xid,
s.backend_xmin,
s.query,
+ s.individual_query,
s.backend_type
- FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid)
+ FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, individual_query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid)
LEFT JOIN pg_database d ON ((s.datid = d.oid)))
LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
pg_stat_all_indexes| SELECT c.oid AS relid,
@@ -1857,7 +1858,7 @@ pg_stat_gssapi| SELECT s.pid,
s.gss_auth AS gss_authenticated,
s.gss_princ AS principal,
s.gss_enc AS encrypted
- FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid)
+ FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, individual_query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid)
WHERE (s.client_port IS NOT NULL);
pg_stat_progress_analyze| SELECT s.pid,
s.datid,
@@ -2005,7 +2006,7 @@ pg_stat_replication| SELECT s.pid,
w.sync_priority,
w.sync_state,
w.reply_time
- FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid)
+ FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, individual_query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid)
JOIN pg_stat_get_wal_senders() w(pid, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, write_lag, flush_lag, replay_lag, sync_priority, sync_state, reply_time) ON ((s.pid = w.pid)))
LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
pg_stat_slru| SELECT s.name,
@@ -2027,7 +2028,7 @@ pg_stat_ssl| SELECT s.pid,
s.ssl_client_dn AS client_dn,
s.ssl_client_serial AS client_serial,
s.ssl_issuer_dn AS issuer_dn
- FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid)
+ FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, individual_query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid)
WHERE (s.client_port IS NOT NULL);
pg_stat_subscription| SELECT su.oid AS subid,
su.subname,