Hi, On Sat, Aug 3, 2019 at 1:21 AM Andres Freund <and...@anarazel.de> wrote: > > On 2019-08-02 10:54:35 +0200, Julien Rouhaud wrote: > > However having the nested queryid in > > pg_stat_activity would be convenient to track what is a long stored > > functions currently doing. Maybe we could expose something like > > top_level_queryid and current_queryid instead? > > Given that the query string is the toplevel one, I think that'd just be > confusing. And given the fact that it adds *substantial* additional > complexity, I'd just rip the subcommand bits out.
Ok, so here's a version that only exposes the top-level queryid only. There can still be discrepancies with the query field, if a multi-command string is provided. The queryid will be updated each time a new top level statement is executed. As the queryid cannot be immediately known, and may never exist at all if a query fails to parse, here are the heuristic I used to update the stored queryid: - it's reset to 0 each time pgstat_report_activity(STATE_RUNNING) is called. This way, we're sure that we don't display last query's queryid in the logs if the next query fails to parse - it's also reset to 0 at the beginning of exec_simple_query() loop on the parsetree_list (for multi-command string case) - pg_analyze_and_rewrite() and pg_analyze_and_rewrite_params() will report the new queryid after parse analysis. - a non-zero queryid will only be updated if the stored one is zero This should also work as intended for background worker using SPI, provided that they correctly call pgstat_report_activity. I also modified ExecInitParallelPlan() to publish the queryId in the serialized plannedStmt, so ParallelQueryMain() can report it to make the queryid available in the parallel workers too. Note that this patch makes it clear that a zero queryid means no queryid computed (and NULL will be displayed in such case in pg_stat_activity). pg_stat_statements already makes sure that it cannot compute a zero queryid. It also assume that any extension computing a queryid will do that in the post_parse_analysis hook, which seems like a sane requirement. We may want to have a dedicated hook for that instead, if more people get interested in having the queryid only, possibly different implementations, if it becomes available outside pgss.
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index c91e3e1550..c7ca1bf9a8 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -6353,6 +6353,11 @@ local0.* /var/log/postgresql session processes</entry> <entry>no</entry> </row> + <row> + <entry><literal>%Q</literal></entry> + <entry>queryid: identifier of session's current query, if any</entry> + <entry>yes</entry> + </row> <row> <entry><literal>%%</literal></entry> <entry>Literal <literal>%</literal></entry> @@ -6736,8 +6741,8 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; <listitem> <para> Enables the collection of information on the currently - executing command of each session, along with the time when - that command began execution. This parameter is on by + executing command of each session, along with its identifier and the + time when that command began execution. This parameter is on by default. Note that even when enabled, this information is not visible to all users, only to superusers and the user owning the session being reported on, so it should not represent a diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index bf72d0c303..7f287c7a7e 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -824,6 +824,18 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser <entry><type>xid</type></entry> <entry>The current backend's <literal>xmin</literal> horizon.</entry> </row> + <row> + <entry><structfield>queryid</structfield></entry> + <entry><type>bigint</type></entry> + <entry>Identifier of this backend's most recent query. If + <structfield>state</structfield> is <literal>active</literal> this field + shows the identifier of the currently executing query. In all other + states, it shows the identifier of last query that was executed. By + default, query identifiers are not computed, so this field will always + be null, unless an additional module that compute query identifiers, such + as <xref linkend="pgstatstatements"/>, is configured. + </entry> + </row> <row> <entry><structfield>query</structfield></entry> <entry><type>text</type></entry> diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index ea4c85e395..f30098c2cd 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -749,6 +749,7 @@ CREATE VIEW pg_stat_activity AS S.state, S.backend_xid, s.backend_xmin, + S.queryid, S.query, S.backend_type FROM pg_stat_get_activity(NULL) AS S diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index 53cd2fc666..9ba6d3f2e6 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -121,7 +121,7 @@ typedef struct ExecParallelInitializeDSMContext } ExecParallelInitializeDSMContext; /* Helper functions that run in the parallel leader. */ -static char *ExecSerializePlan(Plan *plan, EState *estate); +static char *ExecSerializePlan(Plan *plan, EState *estate, uint64 queryId); static bool ExecParallelEstimate(PlanState *node, ExecParallelEstimateContext *e); static bool ExecParallelInitializeDSM(PlanState *node, @@ -140,7 +140,7 @@ static DestReceiver *ExecParallelGetReceiver(dsm_segment *seg, shm_toc *toc); * Create a serialized representation of the plan to be sent to each worker. */ static char * -ExecSerializePlan(Plan *plan, EState *estate) +ExecSerializePlan(Plan *plan, EState *estate, uint64 queryId) { PlannedStmt *pstmt; ListCell *lc; @@ -171,7 +171,7 @@ ExecSerializePlan(Plan *plan, EState *estate) */ pstmt = makeNode(PlannedStmt); pstmt->commandType = CMD_SELECT; - pstmt->queryId = UINT64CONST(0); + pstmt->queryId = queryId; pstmt->hasReturning = false; pstmt->hasModifyingCTE = false; pstmt->canSetTag = true; @@ -560,7 +560,8 @@ ExecParallelSetupTupleQueues(ParallelContext *pcxt, bool reinitialize) ParallelExecutorInfo * ExecInitParallelPlan(PlanState *planstate, EState *estate, Bitmapset *sendParams, int nworkers, - int64 tuples_needed) + int64 tuples_needed, + uint64 queryId) { ParallelExecutorInfo *pei; ParallelContext *pcxt; @@ -601,7 +602,7 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate, pei->planstate = planstate; /* Fix up and serialize plan to be sent to workers. */ - pstmt_data = ExecSerializePlan(planstate->plan, estate); + pstmt_data = ExecSerializePlan(planstate->plan, estate, queryId); /* Create a parallel context. */ pcxt = CreateParallelContext("postgres", "ParallelQueryMain", nworkers); @@ -1355,8 +1356,9 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc) /* Setting debug_query_string for individual workers */ debug_query_string = queryDesc->sourceText; - /* Report workers' query for monitoring purposes */ + /* Report workers' query and queryId for monitoring purposes */ pgstat_report_activity(STATE_RUNNING, debug_query_string); + pgstat_report_queryid(queryDesc->plannedstmt->queryId); /* Attach to the dynamic shared memory area. */ area_space = shm_toc_lookup(toc, PARALLEL_KEY_DSA, false); diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index 69d5a1f239..b57b502022 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -172,7 +172,8 @@ ExecGather(PlanState *pstate) estate, gather->initParam, gather->num_workers, - node->tuples_needed); + node->tuples_needed, + pgstat_get_my_queryid()); else ExecParallelReinitialize(node->ps.lefttree, node->pei, diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c index 6ef128e2ab..25b2494ab7 100644 --- a/src/backend/executor/nodeGatherMerge.c +++ b/src/backend/executor/nodeGatherMerge.c @@ -24,6 +24,7 @@ #include "lib/binaryheap.h" #include "miscadmin.h" #include "optimizer/optimizer.h" +#include "pgstat.h" #include "utils/memutils.h" #include "utils/rel.h" @@ -216,7 +217,8 @@ ExecGatherMerge(PlanState *pstate) estate, gm->initParam, gm->num_workers, - node->tuples_needed); + node->tuples_needed, + pgstat_get_my_queryid()); else ExecParallelReinitialize(node->ps.lefttree, node->pei, diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index b4f2b28b51..f6b0089730 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -3148,6 +3148,7 @@ pgstat_report_activity(BackendState state, const char *cmd_str) beentry->st_activity_start_timestamp = 0; /* st_xact_start_timestamp and wait_event_info are also disabled */ beentry->st_xact_start_timestamp = 0; + beentry->st_queryid = 0; proc->wait_event_info = 0; PGSTAT_END_WRITE_ACTIVITY(beentry); } @@ -3178,6 +3179,14 @@ pgstat_report_activity(BackendState state, const char *cmd_str) beentry->st_state = state; beentry->st_state_start_timestamp = current_timestamp; + /* + * If a new query is started, we reset the query identifier as it'll only + * be known after parse analysis, to avoid reporting last query's + * identifier. + */ + if (state == STATE_RUNNING) + beentry->st_queryid = 0; + if (cmd_str != NULL) { memcpy((char *) beentry->st_activity_raw, cmd_str, len); @@ -3188,6 +3197,47 @@ pgstat_report_activity(BackendState state, const char *cmd_str) PGSTAT_END_WRITE_ACTIVITY(beentry); } +/* -------- + * pgstat_report_queryid() - + * + * Called to update top-level query identifier. + * -------- + */ +void +pgstat_report_queryid(uint64 queryId) +{ + volatile PgBackendStatus *beentry = MyBEEntry; + + if (!beentry) + return; + + /* + * if track_activities is disabled, st_queryid should already have been + * reset + */ + if (!pgstat_track_activities) + return; + + /* + * We only report the top-level query identifiers. The stored queryid is + * reset when a backend call pgstat_report_activity(STATE_RUNNING), or with + * an explicit call to this function. If the saved query identifier is not + * zero it means that it's not a top-level command, so ignore the one + * provided unless it's an explicit call to reset the identifier. + */ + if (queryId != 0 && beentry->st_queryid != 0) + return; + + /* + * Update my status entry, following the protocol of bumping + * st_changecount before and after. We use a volatile pointer here to + * ensure the compiler doesn't try to get cute. + */ + PGSTAT_BEGIN_WRITE_ACTIVITY(beentry); + beentry->st_queryid = queryId; + PGSTAT_END_WRITE_ACTIVITY(beentry); +} + /*----------- * pgstat_progress_start_command() - * @@ -4787,6 +4837,20 @@ pgstat_get_db_entry(Oid databaseid, bool create) return result; } +/* ---------- + * pgstat_get_my_queryid() - + * + * Return current backend's query identifier. + */ +uint64 +pgstat_get_my_queryid(void) +{ + if (!MyBEEntry) + return 0; + + return MyBEEntry->st_queryid; +} + /* * Lookup the hash table entry for the specified table. If no hash diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index a6505c7335..f88a8e74bd 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -695,6 +695,8 @@ pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string, query = parse_analyze(parsetree, query_string, paramTypes, numParams, queryEnv); + pgstat_report_queryid(query->queryId); + if (log_parser_stats) ShowUsage("PARSE ANALYSIS STATISTICS"); @@ -746,6 +748,8 @@ pg_analyze_and_rewrite_params(RawStmt *parsetree, free_parsestate(pstate); + pgstat_report_queryid(query->queryId); + if (log_parser_stats) ShowUsage("PARSE ANALYSIS STATISTICS"); @@ -1077,6 +1081,8 @@ exec_simple_query(const char *query_string) DestReceiver *receiver; int16 format; + pgstat_report_queryid(0); + /* * Get the command name for use in status display (it also becomes the * default completion tag, down inside PortalRun). Set ps_status and diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 05240bfd14..a4b09ba3f1 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -546,7 +546,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS) Datum pg_stat_get_activity(PG_FUNCTION_ARGS) { -#define PG_STAT_GET_ACTIVITY_COLS 29 +#define PG_STAT_GET_ACTIVITY_COLS 30 int num_backends = pgstat_fetch_stat_numbackends(); int curr_backend; int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0); @@ -875,6 +875,10 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) values[28] = BoolGetDatum(false); /* GSS Encryption not in * use */ } + if (beentry->st_queryid == 0) + nulls[29] = true; + else + values[29] = DatumGetUInt64(beentry->st_queryid); } else { @@ -902,6 +906,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) nulls[26] = true; nulls[27] = true; nulls[28] = true; + nulls[29] = true; } tuplestore_putvalues(tupstore, tupdesc, values, nulls); diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 8b4720ef3a..762f58ae1a 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -69,10 +69,10 @@ #include "libpq/pqformat.h" #include "mb/pg_wchar.h" #include "miscadmin.h" +#include "pgstat.h" #include "postmaster/postmaster.h" #include "postmaster/syslogger.h" #include "storage/ipc.h" -#include "storage/proc.h" #include "tcop/tcopprot.h" #include "utils/guc.h" #include "utils/memutils.h" @@ -2594,6 +2594,14 @@ log_line_prefix(StringInfo buf, ErrorData *edata) else appendStringInfoString(buf, unpack_sql_state(edata->sqlerrcode)); break; + case 'Q': + if (padding != 0) + appendStringInfo(buf, "%*ld", padding, + pgstat_get_my_queryid()); + else + appendStringInfo(buf, "%ld", + pgstat_get_my_queryid()); + break; default: /* format error - ignore it */ break; diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index cfad86c02a..bcb8881e93 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -523,6 +523,7 @@ # %t = timestamp without milliseconds # %m = timestamp with milliseconds # %n = timestamp with milliseconds (as a Unix epoch) + # %Q = query ID (0 if none or not computed) # %i = command tag # %e = SQL state # %c = session ID diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index b88e886f7d..bf6971a5da 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5142,9 +5142,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}', - 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}', - 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}', + 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,int8}', + 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,queryid}', prosrc => 'pg_stat_get_activity' }, { oid => '3318', descr => 'statistics: information about progress of backends running maintenance command', diff --git a/src/include/executor/execParallel.h b/src/include/executor/execParallel.h index 46fcf89992..e619aa467e 100644 --- a/src/include/executor/execParallel.h +++ b/src/include/executor/execParallel.h @@ -38,7 +38,8 @@ typedef struct ParallelExecutorInfo extern ParallelExecutorInfo *ExecInitParallelPlan(PlanState *planstate, EState *estate, Bitmapset *sendParam, int nworkers, - int64 tuples_needed); + int64 tuples_needed, + uint64 queryId); extern void ExecParallelCreateReaders(ParallelExecutorInfo *pei); extern void ExecParallelFinish(ParallelExecutorInfo *pei); extern void ExecParallelCleanup(ParallelExecutorInfo *pei); diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 0a3ad3a188..6dd6e8441d 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -1097,6 +1097,9 @@ typedef struct PgBackendStatus ProgressCommandType st_progress_command; Oid st_progress_command_target; int64 st_progress_param[PGSTAT_NUM_PROGRESS_PARAM]; + + /* query identifier, optionnally computed using post_parse_analyze_hook */ + uint64 st_queryid; } PgBackendStatus; /* @@ -1276,6 +1279,7 @@ 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_queryid(uint64 queryId); extern void pgstat_report_tempfile(size_t filesize); extern void pgstat_report_appname(const char *appname); extern void pgstat_report_xact_timestamp(TimestampTz tstamp); @@ -1285,6 +1289,7 @@ extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser); extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen); extern const char *pgstat_get_backend_desc(BackendType backendType); +extern uint64 pgstat_get_my_queryid(void); extern void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid); diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 210e9cd146..0cbef52045 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1739,9 +1739,10 @@ pg_stat_activity| SELECT s.datid, s.state, s.backend_xid, s.backend_xmin, + s.queryid, s.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) + 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, queryid) 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, @@ -1845,7 +1846,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); + 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, queryid); pg_stat_progress_cluster| SELECT s.pid, s.datid, d.datname, @@ -1952,7 +1953,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) + 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, queryid) 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_ssl| SELECT s.pid, @@ -1964,7 +1965,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); + 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, queryid); pg_stat_subscription| SELECT su.oid AS subid, su.subname, st.pid,