1 /*-------------------------------------------------------------------------
4 * Functions for accessing various forms of statistics data
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/adt/pgstatfuncs.c
13 *-------------------------------------------------------------------------
17 #include "access/htup_details.h"
18 #include "access/xlog.h"
19 #include "access/xlogprefetcher.h"
20 #include "catalog/catalog.h"
21 #include "catalog/pg_authid.h"
22 #include "catalog/pg_type.h"
23 #include "common/ip.h"
25 #include "miscadmin.h"
27 #include "postmaster/bgworker.h"
28 #include "replication/logicallauncher.h"
29 #include "storage/proc.h"
30 #include "storage/procarray.h"
31 #include "utils/acl.h"
32 #include "utils/builtins.h"
33 #include "utils/timestamp.h"
35 #define UINT32_ACCESS_ONCE(var) ((uint32)(*((volatile uint32 *)&(var))))
37 #define HAS_PGSTAT_PERMISSIONS(role) (has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role))
39 #define PG_STAT_GET_RELENTRY_INT64(stat) \
41 CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS) \
43 Oid relid = PG_GETARG_OID(0); \
45 PgStat_StatTabEntry *tabentry; \
47 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
50 result = (int64) (tabentry->stat); \
52 PG_RETURN_INT64(result); \
55 /* pg_stat_get_analyze_count */
56 PG_STAT_GET_RELENTRY_INT64(analyze_count
)
58 /* pg_stat_get_autoanalyze_count */
59 PG_STAT_GET_RELENTRY_INT64(autoanalyze_count
)
61 /* pg_stat_get_autovacuum_count */
62 PG_STAT_GET_RELENTRY_INT64(autovacuum_count
)
64 /* pg_stat_get_blocks_fetched */
65 PG_STAT_GET_RELENTRY_INT64(blocks_fetched
)
67 /* pg_stat_get_blocks_hit */
68 PG_STAT_GET_RELENTRY_INT64(blocks_hit
)
70 /* pg_stat_get_dead_tuples */
71 PG_STAT_GET_RELENTRY_INT64(dead_tuples
)
73 /* pg_stat_get_ins_since_vacuum */
74 PG_STAT_GET_RELENTRY_INT64(ins_since_vacuum
)
76 /* pg_stat_get_live_tuples */
77 PG_STAT_GET_RELENTRY_INT64(live_tuples
)
79 /* pg_stat_get_mod_since_analyze */
80 PG_STAT_GET_RELENTRY_INT64(mod_since_analyze
)
82 /* pg_stat_get_numscans */
83 PG_STAT_GET_RELENTRY_INT64(numscans
)
85 /* pg_stat_get_tuples_deleted */
86 PG_STAT_GET_RELENTRY_INT64(tuples_deleted
)
88 /* pg_stat_get_tuples_fetched */
89 PG_STAT_GET_RELENTRY_INT64(tuples_fetched
)
91 /* pg_stat_get_tuples_hot_updated */
92 PG_STAT_GET_RELENTRY_INT64(tuples_hot_updated
)
94 /* pg_stat_get_tuples_newpage_updated */
95 PG_STAT_GET_RELENTRY_INT64(tuples_newpage_updated
)
97 /* pg_stat_get_tuples_inserted */
98 PG_STAT_GET_RELENTRY_INT64(tuples_inserted
)
100 /* pg_stat_get_tuples_returned */
101 PG_STAT_GET_RELENTRY_INT64(tuples_returned
)
103 /* pg_stat_get_tuples_updated */
104 PG_STAT_GET_RELENTRY_INT64(tuples_updated
)
106 /* pg_stat_get_vacuum_count */
107 PG_STAT_GET_RELENTRY_INT64(vacuum_count
)
109 #define PG_STAT_GET_RELENTRY_TIMESTAMPTZ(stat) \
111 CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS) \
113 Oid relid = PG_GETARG_OID(0); \
114 TimestampTz result; \
115 PgStat_StatTabEntry *tabentry; \
117 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
120 result = tabentry->stat; \
125 PG_RETURN_TIMESTAMPTZ(result); \
128 /* pg_stat_get_last_analyze_time */
129 PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_analyze_time
)
131 /* pg_stat_get_last_autoanalyze_time */
132 PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_autoanalyze_time
)
134 /* pg_stat_get_last_autovacuum_time */
135 PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_autovacuum_time
)
137 /* pg_stat_get_last_vacuum_time */
138 PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_vacuum_time
)
140 /* pg_stat_get_lastscan */
141 PG_STAT_GET_RELENTRY_TIMESTAMPTZ(lastscan
)
144 pg_stat_get_function_calls(PG_FUNCTION_ARGS
)
146 Oid funcid
= PG_GETARG_OID(0);
147 PgStat_StatFuncEntry
*funcentry
;
149 if ((funcentry
= pgstat_fetch_stat_funcentry(funcid
)) == NULL
)
151 PG_RETURN_INT64(funcentry
->numcalls
);
154 /* convert counter from microsec to millisec for display */
155 #define PG_STAT_GET_FUNCENTRY_FLOAT8_MS(stat) \
157 CppConcat(pg_stat_get_function_,stat)(PG_FUNCTION_ARGS) \
159 Oid funcid = PG_GETARG_OID(0); \
161 PgStat_StatFuncEntry *funcentry; \
163 if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL) \
165 result = ((double) funcentry->stat) / 1000.0; \
166 PG_RETURN_FLOAT8(result); \
169 /* pg_stat_get_function_total_time */
170 PG_STAT_GET_FUNCENTRY_FLOAT8_MS(total_time
)
172 /* pg_stat_get_function_self_time */
173 PG_STAT_GET_FUNCENTRY_FLOAT8_MS(self_time
)
176 pg_stat_get_backend_idset(PG_FUNCTION_ARGS
)
178 FuncCallContext
*funcctx
;
181 /* stuff done only on the first call of the function */
182 if (SRF_IS_FIRSTCALL())
184 /* create a function context for cross-call persistence */
185 funcctx
= SRF_FIRSTCALL_INIT();
187 fctx
= MemoryContextAlloc(funcctx
->multi_call_memory_ctx
,
189 funcctx
->user_fctx
= fctx
;
194 /* stuff done on every call of the function */
195 funcctx
= SRF_PERCALL_SETUP();
196 fctx
= funcctx
->user_fctx
;
201 * We recheck pgstat_fetch_stat_numbackends() each time through, just in
202 * case the local status data has been refreshed since we started. It's
203 * plenty cheap enough if not. If a refresh does happen, we'll likely
204 * miss or duplicate some backend IDs, but we're content not to crash.
205 * (Refreshing midway through such a query would be problematic usage
206 * anyway, since the backend IDs we've already returned might no longer
207 * refer to extant sessions.)
209 if (fctx
[0] <= pgstat_fetch_stat_numbackends())
211 /* do when there is more left to send */
212 LocalPgBackendStatus
*local_beentry
= pgstat_get_local_beentry_by_index(fctx
[0]);
214 SRF_RETURN_NEXT(funcctx
, Int32GetDatum(local_beentry
->proc_number
));
218 /* do when there is no more left */
219 SRF_RETURN_DONE(funcctx
);
224 * Returns command progress information for the named command.
227 pg_stat_get_progress_info(PG_FUNCTION_ARGS
)
229 #define PG_STAT_GET_PROGRESS_COLS PGSTAT_NUM_PROGRESS_PARAM + 3
230 int num_backends
= pgstat_fetch_stat_numbackends();
232 char *cmd
= text_to_cstring(PG_GETARG_TEXT_PP(0));
233 ProgressCommandType cmdtype
;
234 ReturnSetInfo
*rsinfo
= (ReturnSetInfo
*) fcinfo
->resultinfo
;
236 /* Translate command name into command type code. */
237 if (pg_strcasecmp(cmd
, "VACUUM") == 0)
238 cmdtype
= PROGRESS_COMMAND_VACUUM
;
239 else if (pg_strcasecmp(cmd
, "ANALYZE") == 0)
240 cmdtype
= PROGRESS_COMMAND_ANALYZE
;
241 else if (pg_strcasecmp(cmd
, "CLUSTER") == 0)
242 cmdtype
= PROGRESS_COMMAND_CLUSTER
;
243 else if (pg_strcasecmp(cmd
, "CREATE INDEX") == 0)
244 cmdtype
= PROGRESS_COMMAND_CREATE_INDEX
;
245 else if (pg_strcasecmp(cmd
, "BASEBACKUP") == 0)
246 cmdtype
= PROGRESS_COMMAND_BASEBACKUP
;
247 else if (pg_strcasecmp(cmd
, "COPY") == 0)
248 cmdtype
= PROGRESS_COMMAND_COPY
;
251 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
252 errmsg("invalid command name: \"%s\"", cmd
)));
254 InitMaterializedSRF(fcinfo
, 0);
257 for (curr_backend
= 1; curr_backend
<= num_backends
; curr_backend
++)
259 LocalPgBackendStatus
*local_beentry
;
260 PgBackendStatus
*beentry
;
261 Datum values
[PG_STAT_GET_PROGRESS_COLS
] = {0};
262 bool nulls
[PG_STAT_GET_PROGRESS_COLS
] = {0};
265 local_beentry
= pgstat_get_local_beentry_by_index(curr_backend
);
266 beentry
= &local_beentry
->backendStatus
;
269 * Report values for only those backends which are running the given
272 if (beentry
->st_progress_command
!= cmdtype
)
275 /* Value available to all callers */
276 values
[0] = Int32GetDatum(beentry
->st_procpid
);
277 values
[1] = ObjectIdGetDatum(beentry
->st_databaseid
);
279 /* show rest of the values including relid only to role members */
280 if (HAS_PGSTAT_PERMISSIONS(beentry
->st_userid
))
282 values
[2] = ObjectIdGetDatum(beentry
->st_progress_command_target
);
283 for (i
= 0; i
< PGSTAT_NUM_PROGRESS_PARAM
; i
++)
284 values
[i
+ 3] = Int64GetDatum(beentry
->st_progress_param
[i
]);
289 for (i
= 0; i
< PGSTAT_NUM_PROGRESS_PARAM
; i
++)
293 tuplestore_putvalues(rsinfo
->setResult
, rsinfo
->setDesc
, values
, nulls
);
300 * Returns activity of PG backends.
303 pg_stat_get_activity(PG_FUNCTION_ARGS
)
305 #define PG_STAT_GET_ACTIVITY_COLS 31
306 int num_backends
= pgstat_fetch_stat_numbackends();
308 int pid
= PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
309 ReturnSetInfo
*rsinfo
= (ReturnSetInfo
*) fcinfo
->resultinfo
;
311 InitMaterializedSRF(fcinfo
, 0);
314 for (curr_backend
= 1; curr_backend
<= num_backends
; curr_backend
++)
317 Datum values
[PG_STAT_GET_ACTIVITY_COLS
] = {0};
318 bool nulls
[PG_STAT_GET_ACTIVITY_COLS
] = {0};
319 LocalPgBackendStatus
*local_beentry
;
320 PgBackendStatus
*beentry
;
322 const char *wait_event_type
= NULL
;
323 const char *wait_event
= NULL
;
325 /* Get the next one in the list */
326 local_beentry
= pgstat_get_local_beentry_by_index(curr_backend
);
327 beentry
= &local_beentry
->backendStatus
;
329 /* If looking for specific PID, ignore all the others */
330 if (pid
!= -1 && beentry
->st_procpid
!= pid
)
333 /* Values available to all callers */
334 if (beentry
->st_databaseid
!= InvalidOid
)
335 values
[0] = ObjectIdGetDatum(beentry
->st_databaseid
);
339 values
[1] = Int32GetDatum(beentry
->st_procpid
);
341 if (beentry
->st_userid
!= InvalidOid
)
342 values
[2] = ObjectIdGetDatum(beentry
->st_userid
);
346 if (beentry
->st_appname
)
347 values
[3] = CStringGetTextDatum(beentry
->st_appname
);
351 if (TransactionIdIsValid(local_beentry
->backend_xid
))
352 values
[15] = TransactionIdGetDatum(local_beentry
->backend_xid
);
356 if (TransactionIdIsValid(local_beentry
->backend_xmin
))
357 values
[16] = TransactionIdGetDatum(local_beentry
->backend_xmin
);
361 /* Values only available to role member or pg_read_all_stats */
362 if (HAS_PGSTAT_PERMISSIONS(beentry
->st_userid
))
364 SockAddr zero_clientaddr
;
365 char *clipped_activity
;
367 switch (beentry
->st_state
)
370 values
[4] = CStringGetTextDatum("idle");
373 values
[4] = CStringGetTextDatum("active");
375 case STATE_IDLEINTRANSACTION
:
376 values
[4] = CStringGetTextDatum("idle in transaction");
379 values
[4] = CStringGetTextDatum("fastpath function call");
381 case STATE_IDLEINTRANSACTION_ABORTED
:
382 values
[4] = CStringGetTextDatum("idle in transaction (aborted)");
385 values
[4] = CStringGetTextDatum("disabled");
387 case STATE_UNDEFINED
:
392 clipped_activity
= pgstat_clip_activity(beentry
->st_activity_raw
);
393 values
[5] = CStringGetTextDatum(clipped_activity
);
394 pfree(clipped_activity
);
399 proc
= BackendPidGetProc(beentry
->st_procpid
);
401 if (proc
== NULL
&& (beentry
->st_backendType
!= B_BACKEND
))
404 * For an auxiliary process, retrieve process info from
405 * AuxiliaryProcs stored in shared-memory.
407 proc
= AuxiliaryPidGetProc(beentry
->st_procpid
);
411 * If a PGPROC entry was retrieved, display wait events and lock
412 * group leader or apply leader information if any. To avoid
413 * extra overhead, no extra lock is being held, so there is no
414 * guarantee of consistency across multiple rows.
418 uint32 raw_wait_event
;
421 raw_wait_event
= UINT32_ACCESS_ONCE(proc
->wait_event_info
);
422 wait_event_type
= pgstat_get_wait_event_type(raw_wait_event
);
423 wait_event
= pgstat_get_wait_event(raw_wait_event
);
425 leader
= proc
->lockGroupLeader
;
428 * Show the leader only for active parallel workers. This
429 * leaves the field as NULL for the leader of a parallel group
430 * or the leader of parallel apply workers.
432 if (leader
&& leader
->pid
!= beentry
->st_procpid
)
434 values
[29] = Int32GetDatum(leader
->pid
);
437 else if (beentry
->st_backendType
== B_BG_WORKER
)
439 int leader_pid
= GetLeaderApplyWorkerPid(beentry
->st_procpid
);
441 if (leader_pid
!= InvalidPid
)
443 values
[29] = Int32GetDatum(leader_pid
);
450 values
[6] = CStringGetTextDatum(wait_event_type
);
455 values
[7] = CStringGetTextDatum(wait_event
);
460 * Don't expose transaction time for walsenders; it confuses
461 * monitoring, particularly because we don't keep the time up-to-
464 if (beentry
->st_xact_start_timestamp
!= 0 &&
465 beentry
->st_backendType
!= B_WAL_SENDER
)
466 values
[8] = TimestampTzGetDatum(beentry
->st_xact_start_timestamp
);
470 if (beentry
->st_activity_start_timestamp
!= 0)
471 values
[9] = TimestampTzGetDatum(beentry
->st_activity_start_timestamp
);
475 if (beentry
->st_proc_start_timestamp
!= 0)
476 values
[10] = TimestampTzGetDatum(beentry
->st_proc_start_timestamp
);
480 if (beentry
->st_state_start_timestamp
!= 0)
481 values
[11] = TimestampTzGetDatum(beentry
->st_state_start_timestamp
);
485 /* A zeroed client addr means we don't know */
486 memset(&zero_clientaddr
, 0, sizeof(zero_clientaddr
));
487 if (memcmp(&(beentry
->st_clientaddr
), &zero_clientaddr
,
488 sizeof(zero_clientaddr
)) == 0)
496 if (beentry
->st_clientaddr
.addr
.ss_family
== AF_INET
||
497 beentry
->st_clientaddr
.addr
.ss_family
== AF_INET6
)
499 char remote_host
[NI_MAXHOST
];
500 char remote_port
[NI_MAXSERV
];
503 remote_host
[0] = '\0';
504 remote_port
[0] = '\0';
505 ret
= pg_getnameinfo_all(&beentry
->st_clientaddr
.addr
,
506 beentry
->st_clientaddr
.salen
,
507 remote_host
, sizeof(remote_host
),
508 remote_port
, sizeof(remote_port
),
509 NI_NUMERICHOST
| NI_NUMERICSERV
);
512 clean_ipv6_addr(beentry
->st_clientaddr
.addr
.ss_family
, remote_host
);
513 values
[12] = DirectFunctionCall1(inet_in
,
514 CStringGetDatum(remote_host
));
515 if (beentry
->st_clienthostname
&&
516 beentry
->st_clienthostname
[0])
517 values
[13] = CStringGetTextDatum(beentry
->st_clienthostname
);
520 values
[14] = Int32GetDatum(atoi(remote_port
));
529 else if (beentry
->st_clientaddr
.addr
.ss_family
== AF_UNIX
)
532 * Unix sockets always reports NULL for host and -1 for
533 * port, so it's possible to tell the difference to
534 * connections we have no permissions to view, or with
539 values
[14] = Int32GetDatum(-1);
543 /* Unknown address type, should never happen */
549 /* Add backend type */
550 if (beentry
->st_backendType
== B_BG_WORKER
)
552 const char *bgw_type
;
554 bgw_type
= GetBackgroundWorkerTypeByPid(beentry
->st_procpid
);
556 values
[17] = CStringGetTextDatum(bgw_type
);
562 CStringGetTextDatum(GetBackendTypeDesc(beentry
->st_backendType
));
564 /* SSL information */
567 values
[18] = BoolGetDatum(true); /* ssl */
568 values
[19] = CStringGetTextDatum(beentry
->st_sslstatus
->ssl_version
);
569 values
[20] = CStringGetTextDatum(beentry
->st_sslstatus
->ssl_cipher
);
570 values
[21] = Int32GetDatum(beentry
->st_sslstatus
->ssl_bits
);
572 if (beentry
->st_sslstatus
->ssl_client_dn
[0])
573 values
[22] = CStringGetTextDatum(beentry
->st_sslstatus
->ssl_client_dn
);
577 if (beentry
->st_sslstatus
->ssl_client_serial
[0])
578 values
[23] = DirectFunctionCall3(numeric_in
,
579 CStringGetDatum(beentry
->st_sslstatus
->ssl_client_serial
),
580 ObjectIdGetDatum(InvalidOid
),
585 if (beentry
->st_sslstatus
->ssl_issuer_dn
[0])
586 values
[24] = CStringGetTextDatum(beentry
->st_sslstatus
->ssl_issuer_dn
);
592 values
[18] = BoolGetDatum(false); /* ssl */
593 nulls
[19] = nulls
[20] = nulls
[21] = nulls
[22] = nulls
[23] = nulls
[24] = true;
596 /* GSSAPI information */
599 values
[25] = BoolGetDatum(beentry
->st_gssstatus
->gss_auth
); /* gss_auth */
600 values
[26] = CStringGetTextDatum(beentry
->st_gssstatus
->gss_princ
);
601 values
[27] = BoolGetDatum(beentry
->st_gssstatus
->gss_enc
); /* GSS Encryption in use */
602 values
[28] = BoolGetDatum(beentry
->st_gssstatus
->gss_delegation
); /* GSS credentials
607 values
[25] = BoolGetDatum(false); /* gss_auth */
608 nulls
[26] = true; /* No GSS principal */
609 values
[27] = BoolGetDatum(false); /* GSS Encryption not in
611 values
[28] = BoolGetDatum(false); /* GSS credentials not
614 if (beentry
->st_query_id
== 0)
617 values
[30] = UInt64GetDatum(beentry
->st_query_id
);
621 /* No permissions to view data about this session */
622 values
[5] = CStringGetTextDatum("<insufficient privilege>");
649 tuplestore_putvalues(rsinfo
->setResult
, rsinfo
->setDesc
, values
, nulls
);
651 /* If only a single backend was requested, and we found it, break. */
661 pg_backend_pid(PG_FUNCTION_ARGS
)
663 PG_RETURN_INT32(MyProcPid
);
668 pg_stat_get_backend_pid(PG_FUNCTION_ARGS
)
670 int32 procNumber
= PG_GETARG_INT32(0);
671 PgBackendStatus
*beentry
;
673 if ((beentry
= pgstat_get_beentry_by_proc_number(procNumber
)) == NULL
)
676 PG_RETURN_INT32(beentry
->st_procpid
);
681 pg_stat_get_backend_dbid(PG_FUNCTION_ARGS
)
683 int32 procNumber
= PG_GETARG_INT32(0);
684 PgBackendStatus
*beentry
;
686 if ((beentry
= pgstat_get_beentry_by_proc_number(procNumber
)) == NULL
)
689 PG_RETURN_OID(beentry
->st_databaseid
);
694 pg_stat_get_backend_userid(PG_FUNCTION_ARGS
)
696 int32 procNumber
= PG_GETARG_INT32(0);
697 PgBackendStatus
*beentry
;
699 if ((beentry
= pgstat_get_beentry_by_proc_number(procNumber
)) == NULL
)
702 PG_RETURN_OID(beentry
->st_userid
);
706 pg_stat_get_backend_subxact(PG_FUNCTION_ARGS
)
708 #define PG_STAT_GET_SUBXACT_COLS 2
710 Datum values
[PG_STAT_GET_SUBXACT_COLS
] = {0};
711 bool nulls
[PG_STAT_GET_SUBXACT_COLS
] = {0};
712 int32 procNumber
= PG_GETARG_INT32(0);
713 LocalPgBackendStatus
*local_beentry
;
715 /* Initialise attributes information in the tuple descriptor */
716 tupdesc
= CreateTemplateTupleDesc(PG_STAT_GET_SUBXACT_COLS
);
717 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, "subxact_count",
719 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "subxact_overflow",
722 BlessTupleDesc(tupdesc
);
724 if ((local_beentry
= pgstat_get_local_beentry_by_proc_number(procNumber
)) != NULL
)
726 /* Fill values and NULLs */
727 values
[0] = Int32GetDatum(local_beentry
->backend_subxact_count
);
728 values
[1] = BoolGetDatum(local_beentry
->backend_subxact_overflowed
);
736 /* Returns the record as Datum */
737 PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc
, values
, nulls
)));
741 pg_stat_get_backend_activity(PG_FUNCTION_ARGS
)
743 int32 procNumber
= PG_GETARG_INT32(0);
744 PgBackendStatus
*beentry
;
745 const char *activity
;
746 char *clipped_activity
;
749 if ((beentry
= pgstat_get_beentry_by_proc_number(procNumber
)) == NULL
)
750 activity
= "<backend information not available>";
751 else if (!HAS_PGSTAT_PERMISSIONS(beentry
->st_userid
))
752 activity
= "<insufficient privilege>";
753 else if (*(beentry
->st_activity_raw
) == '\0')
754 activity
= "<command string not enabled>";
756 activity
= beentry
->st_activity_raw
;
758 clipped_activity
= pgstat_clip_activity(activity
);
759 ret
= cstring_to_text(activity
);
760 pfree(clipped_activity
);
762 PG_RETURN_TEXT_P(ret
);
766 pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS
)
768 int32 procNumber
= PG_GETARG_INT32(0);
769 PgBackendStatus
*beentry
;
771 const char *wait_event_type
= NULL
;
773 if ((beentry
= pgstat_get_beentry_by_proc_number(procNumber
)) == NULL
)
774 wait_event_type
= "<backend information not available>";
775 else if (!HAS_PGSTAT_PERMISSIONS(beentry
->st_userid
))
776 wait_event_type
= "<insufficient privilege>";
777 else if ((proc
= BackendPidGetProc(beentry
->st_procpid
)) != NULL
)
778 wait_event_type
= pgstat_get_wait_event_type(proc
->wait_event_info
);
780 if (!wait_event_type
)
783 PG_RETURN_TEXT_P(cstring_to_text(wait_event_type
));
787 pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS
)
789 int32 procNumber
= PG_GETARG_INT32(0);
790 PgBackendStatus
*beentry
;
792 const char *wait_event
= NULL
;
794 if ((beentry
= pgstat_get_beentry_by_proc_number(procNumber
)) == NULL
)
795 wait_event
= "<backend information not available>";
796 else if (!HAS_PGSTAT_PERMISSIONS(beentry
->st_userid
))
797 wait_event
= "<insufficient privilege>";
798 else if ((proc
= BackendPidGetProc(beentry
->st_procpid
)) != NULL
)
799 wait_event
= pgstat_get_wait_event(proc
->wait_event_info
);
804 PG_RETURN_TEXT_P(cstring_to_text(wait_event
));
809 pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS
)
811 int32 procNumber
= PG_GETARG_INT32(0);
813 PgBackendStatus
*beentry
;
815 if ((beentry
= pgstat_get_beentry_by_proc_number(procNumber
)) == NULL
)
818 else if (!HAS_PGSTAT_PERMISSIONS(beentry
->st_userid
))
821 result
= beentry
->st_activity_start_timestamp
;
824 * No time recorded for start of current query -- this is the case if the
825 * user hasn't enabled query-level stats collection.
830 PG_RETURN_TIMESTAMPTZ(result
);
835 pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS
)
837 int32 procNumber
= PG_GETARG_INT32(0);
839 PgBackendStatus
*beentry
;
841 if ((beentry
= pgstat_get_beentry_by_proc_number(procNumber
)) == NULL
)
844 else if (!HAS_PGSTAT_PERMISSIONS(beentry
->st_userid
))
847 result
= beentry
->st_xact_start_timestamp
;
849 if (result
== 0) /* not in a transaction */
852 PG_RETURN_TIMESTAMPTZ(result
);
857 pg_stat_get_backend_start(PG_FUNCTION_ARGS
)
859 int32 procNumber
= PG_GETARG_INT32(0);
861 PgBackendStatus
*beentry
;
863 if ((beentry
= pgstat_get_beentry_by_proc_number(procNumber
)) == NULL
)
866 else if (!HAS_PGSTAT_PERMISSIONS(beentry
->st_userid
))
869 result
= beentry
->st_proc_start_timestamp
;
871 if (result
== 0) /* probably can't happen? */
874 PG_RETURN_TIMESTAMPTZ(result
);
879 pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS
)
881 int32 procNumber
= PG_GETARG_INT32(0);
882 PgBackendStatus
*beentry
;
883 SockAddr zero_clientaddr
;
884 char remote_host
[NI_MAXHOST
];
887 if ((beentry
= pgstat_get_beentry_by_proc_number(procNumber
)) == NULL
)
890 else if (!HAS_PGSTAT_PERMISSIONS(beentry
->st_userid
))
893 /* A zeroed client addr means we don't know */
894 memset(&zero_clientaddr
, 0, sizeof(zero_clientaddr
));
895 if (memcmp(&(beentry
->st_clientaddr
), &zero_clientaddr
,
896 sizeof(zero_clientaddr
)) == 0)
899 switch (beentry
->st_clientaddr
.addr
.ss_family
)
908 remote_host
[0] = '\0';
909 ret
= pg_getnameinfo_all(&beentry
->st_clientaddr
.addr
,
910 beentry
->st_clientaddr
.salen
,
911 remote_host
, sizeof(remote_host
),
913 NI_NUMERICHOST
| NI_NUMERICSERV
);
917 clean_ipv6_addr(beentry
->st_clientaddr
.addr
.ss_family
, remote_host
);
919 PG_RETURN_DATUM(DirectFunctionCall1(inet_in
,
920 CStringGetDatum(remote_host
)));
924 pg_stat_get_backend_client_port(PG_FUNCTION_ARGS
)
926 int32 procNumber
= PG_GETARG_INT32(0);
927 PgBackendStatus
*beentry
;
928 SockAddr zero_clientaddr
;
929 char remote_port
[NI_MAXSERV
];
932 if ((beentry
= pgstat_get_beentry_by_proc_number(procNumber
)) == NULL
)
935 else if (!HAS_PGSTAT_PERMISSIONS(beentry
->st_userid
))
938 /* A zeroed client addr means we don't know */
939 memset(&zero_clientaddr
, 0, sizeof(zero_clientaddr
));
940 if (memcmp(&(beentry
->st_clientaddr
), &zero_clientaddr
,
941 sizeof(zero_clientaddr
)) == 0)
944 switch (beentry
->st_clientaddr
.addr
.ss_family
)
955 remote_port
[0] = '\0';
956 ret
= pg_getnameinfo_all(&beentry
->st_clientaddr
.addr
,
957 beentry
->st_clientaddr
.salen
,
959 remote_port
, sizeof(remote_port
),
960 NI_NUMERICHOST
| NI_NUMERICSERV
);
964 PG_RETURN_DATUM(DirectFunctionCall1(int4in
,
965 CStringGetDatum(remote_port
)));
970 pg_stat_get_db_numbackends(PG_FUNCTION_ARGS
)
972 Oid dbid
= PG_GETARG_OID(0);
974 int tot_backends
= pgstat_fetch_stat_numbackends();
978 for (idx
= 1; idx
<= tot_backends
; idx
++)
980 LocalPgBackendStatus
*local_beentry
= pgstat_get_local_beentry_by_index(idx
);
982 if (local_beentry
->backendStatus
.st_databaseid
== dbid
)
986 PG_RETURN_INT32(result
);
990 #define PG_STAT_GET_DBENTRY_INT64(stat) \
992 CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS) \
994 Oid dbid = PG_GETARG_OID(0); \
996 PgStat_StatDBEntry *dbentry; \
998 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) \
1001 result = (int64) (dbentry->stat); \
1003 PG_RETURN_INT64(result); \
1006 /* pg_stat_get_db_blocks_fetched */
1007 PG_STAT_GET_DBENTRY_INT64(blocks_fetched
)
1009 /* pg_stat_get_db_blocks_hit */
1010 PG_STAT_GET_DBENTRY_INT64(blocks_hit
)
1012 /* pg_stat_get_db_conflict_bufferpin */
1013 PG_STAT_GET_DBENTRY_INT64(conflict_bufferpin
)
1015 /* pg_stat_get_db_conflict_lock */
1016 PG_STAT_GET_DBENTRY_INT64(conflict_lock
)
1018 /* pg_stat_get_db_conflict_snapshot */
1019 PG_STAT_GET_DBENTRY_INT64(conflict_snapshot
)
1021 /* pg_stat_get_db_conflict_startup_deadlock */
1022 PG_STAT_GET_DBENTRY_INT64(conflict_startup_deadlock
)
1024 /* pg_stat_get_db_conflict_tablespace */
1025 PG_STAT_GET_DBENTRY_INT64(conflict_tablespace
)
1027 /* pg_stat_get_db_deadlocks */
1028 PG_STAT_GET_DBENTRY_INT64(deadlocks
)
1030 /* pg_stat_get_db_sessions */
1031 PG_STAT_GET_DBENTRY_INT64(sessions
)
1033 /* pg_stat_get_db_sessions_abandoned */
1034 PG_STAT_GET_DBENTRY_INT64(sessions_abandoned
)
1036 /* pg_stat_get_db_sessions_fatal */
1037 PG_STAT_GET_DBENTRY_INT64(sessions_fatal
)
1039 /* pg_stat_get_db_sessions_killed */
1040 PG_STAT_GET_DBENTRY_INT64(sessions_killed
)
1042 /* pg_stat_get_db_temp_bytes */
1043 PG_STAT_GET_DBENTRY_INT64(temp_bytes
)
1045 /* pg_stat_get_db_temp_files */
1046 PG_STAT_GET_DBENTRY_INT64(temp_files
)
1048 /* pg_stat_get_db_tuples_deleted */
1049 PG_STAT_GET_DBENTRY_INT64(tuples_deleted
)
1051 /* pg_stat_get_db_tuples_fetched */
1052 PG_STAT_GET_DBENTRY_INT64(tuples_fetched
)
1054 /* pg_stat_get_db_tuples_inserted */
1055 PG_STAT_GET_DBENTRY_INT64(tuples_inserted
)
1057 /* pg_stat_get_db_tuples_returned */
1058 PG_STAT_GET_DBENTRY_INT64(tuples_returned
)
1060 /* pg_stat_get_db_tuples_updated */
1061 PG_STAT_GET_DBENTRY_INT64(tuples_updated
)
1063 /* pg_stat_get_db_xact_commit */
1064 PG_STAT_GET_DBENTRY_INT64(xact_commit
)
1066 /* pg_stat_get_db_xact_rollback */
1067 PG_STAT_GET_DBENTRY_INT64(xact_rollback
)
1069 /* pg_stat_get_db_conflict_logicalslot */
1070 PG_STAT_GET_DBENTRY_INT64(conflict_logicalslot
)
1073 pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS
)
1075 Oid dbid
= PG_GETARG_OID(0);
1077 PgStat_StatDBEntry
*dbentry
;
1079 if ((dbentry
= pgstat_fetch_stat_dbentry(dbid
)) == NULL
)
1082 result
= dbentry
->stat_reset_timestamp
;
1087 PG_RETURN_TIMESTAMPTZ(result
);
1092 pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS
)
1094 Oid dbid
= PG_GETARG_OID(0);
1096 PgStat_StatDBEntry
*dbentry
;
1098 if ((dbentry
= pgstat_fetch_stat_dbentry(dbid
)) == NULL
)
1101 result
= (int64
) (dbentry
->conflict_tablespace
+
1102 dbentry
->conflict_lock
+
1103 dbentry
->conflict_snapshot
+
1104 dbentry
->conflict_logicalslot
+
1105 dbentry
->conflict_bufferpin
+
1106 dbentry
->conflict_startup_deadlock
);
1108 PG_RETURN_INT64(result
);
1112 pg_stat_get_db_checksum_failures(PG_FUNCTION_ARGS
)
1114 Oid dbid
= PG_GETARG_OID(0);
1116 PgStat_StatDBEntry
*dbentry
;
1118 if (!DataChecksumsEnabled())
1121 if ((dbentry
= pgstat_fetch_stat_dbentry(dbid
)) == NULL
)
1124 result
= (int64
) (dbentry
->checksum_failures
);
1126 PG_RETURN_INT64(result
);
1130 pg_stat_get_db_checksum_last_failure(PG_FUNCTION_ARGS
)
1132 Oid dbid
= PG_GETARG_OID(0);
1134 PgStat_StatDBEntry
*dbentry
;
1136 if (!DataChecksumsEnabled())
1139 if ((dbentry
= pgstat_fetch_stat_dbentry(dbid
)) == NULL
)
1142 result
= dbentry
->last_checksum_failure
;
1147 PG_RETURN_TIMESTAMPTZ(result
);
1150 /* convert counter from microsec to millisec for display */
1151 #define PG_STAT_GET_DBENTRY_FLOAT8_MS(stat) \
1153 CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS) \
1155 Oid dbid = PG_GETARG_OID(0); \
1157 PgStat_StatDBEntry *dbentry; \
1159 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) \
1162 result = ((double) dbentry->stat) / 1000.0; \
1164 PG_RETURN_FLOAT8(result); \
1167 /* pg_stat_get_db_active_time */
1168 PG_STAT_GET_DBENTRY_FLOAT8_MS(active_time
)
1170 /* pg_stat_get_db_blk_read_time */
1171 PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_read_time
)
1173 /* pg_stat_get_db_blk_write_time */
1174 PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_write_time
)
1176 /* pg_stat_get_db_idle_in_transaction_time */
1177 PG_STAT_GET_DBENTRY_FLOAT8_MS(idle_in_transaction_time
)
1179 /* pg_stat_get_db_session_time */
1180 PG_STAT_GET_DBENTRY_FLOAT8_MS(session_time
)
1183 pg_stat_get_checkpointer_num_timed(PG_FUNCTION_ARGS
)
1185 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_timed
);
1189 pg_stat_get_checkpointer_num_requested(PG_FUNCTION_ARGS
)
1191 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_requested
);
1195 pg_stat_get_checkpointer_num_performed(PG_FUNCTION_ARGS
)
1197 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_performed
);
1201 pg_stat_get_checkpointer_restartpoints_timed(PG_FUNCTION_ARGS
)
1203 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_timed
);
1207 pg_stat_get_checkpointer_restartpoints_requested(PG_FUNCTION_ARGS
)
1209 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_requested
);
1213 pg_stat_get_checkpointer_restartpoints_performed(PG_FUNCTION_ARGS
)
1215 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_performed
);
1219 pg_stat_get_checkpointer_buffers_written(PG_FUNCTION_ARGS
)
1221 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buffers_written
);
1225 pg_stat_get_checkpointer_slru_written(PG_FUNCTION_ARGS
)
1227 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->slru_written
);
1231 pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS
)
1233 PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->buf_written_clean
);
1237 pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS
)
1239 PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->maxwritten_clean
);
1243 pg_stat_get_checkpointer_write_time(PG_FUNCTION_ARGS
)
1245 /* time is already in msec, just convert to double for presentation */
1246 PG_RETURN_FLOAT8((double)
1247 pgstat_fetch_stat_checkpointer()->write_time
);
1251 pg_stat_get_checkpointer_sync_time(PG_FUNCTION_ARGS
)
1253 /* time is already in msec, just convert to double for presentation */
1254 PG_RETURN_FLOAT8((double)
1255 pgstat_fetch_stat_checkpointer()->sync_time
);
1259 pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS
)
1261 PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp
);
1265 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS
)
1267 PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_bgwriter()->stat_reset_timestamp
);
1271 pg_stat_get_buf_alloc(PG_FUNCTION_ARGS
)
1273 PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->buf_alloc
);
1277 * When adding a new column to the pg_stat_io view, add a new enum value
1278 * here above IO_NUM_COLUMNS.
1280 typedef enum io_stat_col
1282 IO_COL_INVALID
= -1,
1283 IO_COL_BACKEND_TYPE
,
1291 IO_COL_WRITEBACK_TIME
,
1305 * When adding a new IOOp, add a new io_stat_col and add a case to this
1306 * function returning the corresponding io_stat_col.
1309 pgstat_get_io_op_index(IOOp io_op
)
1314 return IO_COL_EVICTIONS
;
1316 return IO_COL_EXTENDS
;
1318 return IO_COL_FSYNCS
;
1322 return IO_COL_READS
;
1324 return IO_COL_REUSES
;
1326 return IO_COL_WRITES
;
1327 case IOOP_WRITEBACK
:
1328 return IO_COL_WRITEBACKS
;
1331 elog(ERROR
, "unrecognized IOOp value: %d", io_op
);
1336 * Get the number of the column containing IO times for the specified IOOp.
1337 * This function encodes our assumption that IO time for an IOOp is displayed
1338 * in the view in the column directly after the IOOp counts. If an op has no
1339 * associated time, IO_COL_INVALID is returned.
1342 pgstat_get_io_time_index(IOOp io_op
)
1348 case IOOP_WRITEBACK
:
1351 return pgstat_get_io_op_index(io_op
) + 1;
1355 return IO_COL_INVALID
;
1358 elog(ERROR
, "unrecognized IOOp value: %d", io_op
);
1362 static inline double
1363 pg_stat_us_to_ms(PgStat_Counter val_ms
)
1365 return val_ms
* (double) 0.001;
1369 pg_stat_get_io(PG_FUNCTION_ARGS
)
1371 ReturnSetInfo
*rsinfo
;
1372 PgStat_IO
*backends_io_stats
;
1375 InitMaterializedSRF(fcinfo
, 0);
1376 rsinfo
= (ReturnSetInfo
*) fcinfo
->resultinfo
;
1378 backends_io_stats
= pgstat_fetch_stat_io();
1380 reset_time
= TimestampTzGetDatum(backends_io_stats
->stat_reset_timestamp
);
1382 for (int bktype
= 0; bktype
< BACKEND_NUM_TYPES
; bktype
++)
1384 Datum bktype_desc
= CStringGetTextDatum(GetBackendTypeDesc(bktype
));
1385 PgStat_BktypeIO
*bktype_stats
= &backends_io_stats
->stats
[bktype
];
1388 * In Assert builds, we can afford an extra loop through all of the
1389 * counters checking that only expected stats are non-zero, since it
1390 * keeps the non-Assert code cleaner.
1392 Assert(pgstat_bktype_io_stats_valid(bktype_stats
, bktype
));
1395 * For those BackendTypes without IO Operation stats, skip
1396 * representing them in the view altogether.
1398 if (!pgstat_tracks_io_bktype(bktype
))
1401 for (int io_obj
= 0; io_obj
< IOOBJECT_NUM_TYPES
; io_obj
++)
1403 const char *obj_name
= pgstat_get_io_object_name(io_obj
);
1405 for (int io_context
= 0; io_context
< IOCONTEXT_NUM_TYPES
; io_context
++)
1407 const char *context_name
= pgstat_get_io_context_name(io_context
);
1409 Datum values
[IO_NUM_COLUMNS
] = {0};
1410 bool nulls
[IO_NUM_COLUMNS
] = {0};
1413 * Some combinations of BackendType, IOObject, and IOContext
1414 * are not valid for any type of IOOp. In such cases, omit the
1415 * entire row from the view.
1417 if (!pgstat_tracks_io_object(bktype
, io_obj
, io_context
))
1420 values
[IO_COL_BACKEND_TYPE
] = bktype_desc
;
1421 values
[IO_COL_CONTEXT
] = CStringGetTextDatum(context_name
);
1422 values
[IO_COL_OBJECT
] = CStringGetTextDatum(obj_name
);
1423 values
[IO_COL_RESET_TIME
] = reset_time
;
1426 * Hard-code this to the value of BLCKSZ for now. Future
1427 * values could include XLOG_BLCKSZ, once WAL IO is tracked,
1428 * and constant multipliers, once non-block-oriented IO (e.g.
1429 * temporary file IO) is tracked.
1431 values
[IO_COL_CONVERSION
] = Int64GetDatum(BLCKSZ
);
1433 for (int io_op
= 0; io_op
< IOOP_NUM_TYPES
; io_op
++)
1435 int op_idx
= pgstat_get_io_op_index(io_op
);
1436 int time_idx
= pgstat_get_io_time_index(io_op
);
1439 * Some combinations of BackendType and IOOp, of IOContext
1440 * and IOOp, and of IOObject and IOOp are not tracked. Set
1441 * these cells in the view NULL.
1443 if (pgstat_tracks_io_op(bktype
, io_obj
, io_context
, io_op
))
1445 PgStat_Counter count
=
1446 bktype_stats
->counts
[io_obj
][io_context
][io_op
];
1448 values
[op_idx
] = Int64GetDatum(count
);
1451 nulls
[op_idx
] = true;
1453 /* not every operation is timed */
1454 if (time_idx
== IO_COL_INVALID
)
1459 PgStat_Counter time
=
1460 bktype_stats
->times
[io_obj
][io_context
][io_op
];
1462 values
[time_idx
] = Float8GetDatum(pg_stat_us_to_ms(time
));
1465 nulls
[time_idx
] = true;
1468 tuplestore_putvalues(rsinfo
->setResult
, rsinfo
->setDesc
,
1478 * Returns statistics of WAL activity
1481 pg_stat_get_wal(PG_FUNCTION_ARGS
)
1483 #define PG_STAT_GET_WAL_COLS 9
1485 Datum values
[PG_STAT_GET_WAL_COLS
] = {0};
1486 bool nulls
[PG_STAT_GET_WAL_COLS
] = {0};
1488 PgStat_WalStats
*wal_stats
;
1490 /* Initialise attributes information in the tuple descriptor */
1491 tupdesc
= CreateTemplateTupleDesc(PG_STAT_GET_WAL_COLS
);
1492 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, "wal_records",
1494 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "wal_fpi",
1496 TupleDescInitEntry(tupdesc
, (AttrNumber
) 3, "wal_bytes",
1498 TupleDescInitEntry(tupdesc
, (AttrNumber
) 4, "wal_buffers_full",
1500 TupleDescInitEntry(tupdesc
, (AttrNumber
) 5, "wal_write",
1502 TupleDescInitEntry(tupdesc
, (AttrNumber
) 6, "wal_sync",
1504 TupleDescInitEntry(tupdesc
, (AttrNumber
) 7, "wal_write_time",
1506 TupleDescInitEntry(tupdesc
, (AttrNumber
) 8, "wal_sync_time",
1508 TupleDescInitEntry(tupdesc
, (AttrNumber
) 9, "stats_reset",
1509 TIMESTAMPTZOID
, -1, 0);
1511 BlessTupleDesc(tupdesc
);
1513 /* Get statistics about WAL activity */
1514 wal_stats
= pgstat_fetch_stat_wal();
1516 /* Fill values and NULLs */
1517 values
[0] = Int64GetDatum(wal_stats
->wal_records
);
1518 values
[1] = Int64GetDatum(wal_stats
->wal_fpi
);
1520 /* Convert to numeric. */
1521 snprintf(buf
, sizeof buf
, UINT64_FORMAT
, wal_stats
->wal_bytes
);
1522 values
[2] = DirectFunctionCall3(numeric_in
,
1523 CStringGetDatum(buf
),
1524 ObjectIdGetDatum(0),
1527 values
[3] = Int64GetDatum(wal_stats
->wal_buffers_full
);
1528 values
[4] = Int64GetDatum(wal_stats
->wal_write
);
1529 values
[5] = Int64GetDatum(wal_stats
->wal_sync
);
1531 /* Convert counters from microsec to millisec for display */
1532 values
[6] = Float8GetDatum(((double) wal_stats
->wal_write_time
) / 1000.0);
1533 values
[7] = Float8GetDatum(((double) wal_stats
->wal_sync_time
) / 1000.0);
1535 values
[8] = TimestampTzGetDatum(wal_stats
->stat_reset_timestamp
);
1537 /* Returns the record as Datum */
1538 PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc
, values
, nulls
)));
1542 * Returns statistics of SLRU caches.
1545 pg_stat_get_slru(PG_FUNCTION_ARGS
)
1547 #define PG_STAT_GET_SLRU_COLS 9
1548 ReturnSetInfo
*rsinfo
= (ReturnSetInfo
*) fcinfo
->resultinfo
;
1550 PgStat_SLRUStats
*stats
;
1552 InitMaterializedSRF(fcinfo
, 0);
1554 /* request SLRU stats from the cumulative stats system */
1555 stats
= pgstat_fetch_slru();
1560 Datum values
[PG_STAT_GET_SLRU_COLS
] = {0};
1561 bool nulls
[PG_STAT_GET_SLRU_COLS
] = {0};
1562 PgStat_SLRUStats stat
;
1565 name
= pgstat_get_slru_name(i
);
1572 values
[0] = PointerGetDatum(cstring_to_text(name
));
1573 values
[1] = Int64GetDatum(stat
.blocks_zeroed
);
1574 values
[2] = Int64GetDatum(stat
.blocks_hit
);
1575 values
[3] = Int64GetDatum(stat
.blocks_read
);
1576 values
[4] = Int64GetDatum(stat
.blocks_written
);
1577 values
[5] = Int64GetDatum(stat
.blocks_exists
);
1578 values
[6] = Int64GetDatum(stat
.flush
);
1579 values
[7] = Int64GetDatum(stat
.truncate
);
1580 values
[8] = TimestampTzGetDatum(stat
.stat_reset_timestamp
);
1582 tuplestore_putvalues(rsinfo
->setResult
, rsinfo
->setDesc
, values
, nulls
);
1588 #define PG_STAT_GET_XACT_RELENTRY_INT64(stat) \
1590 CppConcat(pg_stat_get_xact_,stat)(PG_FUNCTION_ARGS) \
1592 Oid relid = PG_GETARG_OID(0); \
1594 PgStat_TableStatus *tabentry; \
1596 if ((tabentry = find_tabstat_entry(relid)) == NULL) \
1599 result = (int64) (tabentry->counts.stat); \
1601 PG_RETURN_INT64(result); \
1604 /* pg_stat_get_xact_numscans */
1605 PG_STAT_GET_XACT_RELENTRY_INT64(numscans
)
1607 /* pg_stat_get_xact_tuples_returned */
1608 PG_STAT_GET_XACT_RELENTRY_INT64(tuples_returned
)
1610 /* pg_stat_get_xact_tuples_fetched */
1611 PG_STAT_GET_XACT_RELENTRY_INT64(tuples_fetched
)
1613 /* pg_stat_get_xact_tuples_hot_updated */
1614 PG_STAT_GET_XACT_RELENTRY_INT64(tuples_hot_updated
)
1616 /* pg_stat_get_xact_tuples_newpage_updated */
1617 PG_STAT_GET_XACT_RELENTRY_INT64(tuples_newpage_updated
)
1619 /* pg_stat_get_xact_blocks_fetched */
1620 PG_STAT_GET_XACT_RELENTRY_INT64(blocks_fetched
)
1622 /* pg_stat_get_xact_blocks_hit */
1623 PG_STAT_GET_XACT_RELENTRY_INT64(blocks_hit
)
1625 /* pg_stat_get_xact_tuples_inserted */
1626 PG_STAT_GET_XACT_RELENTRY_INT64(tuples_inserted
)
1628 /* pg_stat_get_xact_tuples_updated */
1629 PG_STAT_GET_XACT_RELENTRY_INT64(tuples_updated
)
1631 /* pg_stat_get_xact_tuples_deleted */
1632 PG_STAT_GET_XACT_RELENTRY_INT64(tuples_deleted
)
1635 pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS
)
1637 Oid funcid
= PG_GETARG_OID(0);
1638 PgStat_FunctionCounts
*funcentry
;
1640 if ((funcentry
= find_funcstat_entry(funcid
)) == NULL
)
1642 PG_RETURN_INT64(funcentry
->numcalls
);
1645 #define PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(stat) \
1647 CppConcat(pg_stat_get_xact_function_,stat)(PG_FUNCTION_ARGS) \
1649 Oid funcid = PG_GETARG_OID(0); \
1650 PgStat_FunctionCounts *funcentry; \
1652 if ((funcentry = find_funcstat_entry(funcid)) == NULL) \
1654 PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->stat)); \
1657 /* pg_stat_get_xact_function_total_time */
1658 PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(total_time
)
1660 /* pg_stat_get_xact_function_self_time */
1661 PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(self_time
)
1663 /* Get the timestamp of the current statistics snapshot */
1665 pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS
)
1670 ts
= pgstat_get_stat_snapshot_timestamp(&have_snapshot
);
1675 PG_RETURN_TIMESTAMPTZ(ts
);
1678 /* Discard the active statistics snapshot */
1680 pg_stat_clear_snapshot(PG_FUNCTION_ARGS
)
1682 pgstat_clear_snapshot();
1688 /* Force statistics to be reported at the next occasion */
1690 pg_stat_force_next_flush(PG_FUNCTION_ARGS
)
1692 pgstat_force_next_flush();
1698 /* Reset all counters for the current database */
1700 pg_stat_reset(PG_FUNCTION_ARGS
)
1702 pgstat_reset_counters();
1708 * Reset some shared cluster-wide counters
1710 * When adding a new reset target, ideally the name should match that in
1711 * pgstat_kind_builtin_infos, if relevant.
1714 pg_stat_reset_shared(PG_FUNCTION_ARGS
)
1716 char *target
= NULL
;
1718 if (PG_ARGISNULL(0))
1720 /* Reset all the statistics when nothing is specified */
1721 pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER
);
1722 pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER
);
1723 pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER
);
1724 pgstat_reset_of_kind(PGSTAT_KIND_IO
);
1725 XLogPrefetchResetStats();
1726 pgstat_reset_of_kind(PGSTAT_KIND_SLRU
);
1727 pgstat_reset_of_kind(PGSTAT_KIND_WAL
);
1732 target
= text_to_cstring(PG_GETARG_TEXT_PP(0));
1734 if (strcmp(target
, "archiver") == 0)
1735 pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER
);
1736 else if (strcmp(target
, "bgwriter") == 0)
1737 pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER
);
1738 else if (strcmp(target
, "checkpointer") == 0)
1739 pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER
);
1740 else if (strcmp(target
, "io") == 0)
1741 pgstat_reset_of_kind(PGSTAT_KIND_IO
);
1742 else if (strcmp(target
, "recovery_prefetch") == 0)
1743 XLogPrefetchResetStats();
1744 else if (strcmp(target
, "slru") == 0)
1745 pgstat_reset_of_kind(PGSTAT_KIND_SLRU
);
1746 else if (strcmp(target
, "wal") == 0)
1747 pgstat_reset_of_kind(PGSTAT_KIND_WAL
);
1750 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1751 errmsg("unrecognized reset target: \"%s\"", target
),
1752 errhint("Target must be \"archiver\", \"bgwriter\", \"checkpointer\", \"io\", \"recovery_prefetch\", \"slru\", or \"wal\".")));
1758 * Reset a statistics for a single object, which may be of current
1759 * database or shared across all databases in the cluster.
1762 pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS
)
1764 Oid taboid
= PG_GETARG_OID(0);
1765 Oid dboid
= (IsSharedRelation(taboid
) ? InvalidOid
: MyDatabaseId
);
1767 pgstat_reset(PGSTAT_KIND_RELATION
, dboid
, taboid
);
1773 pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS
)
1775 Oid funcoid
= PG_GETARG_OID(0);
1777 pgstat_reset(PGSTAT_KIND_FUNCTION
, MyDatabaseId
, funcoid
);
1782 /* Reset SLRU counters (a specific one or all of them). */
1784 pg_stat_reset_slru(PG_FUNCTION_ARGS
)
1786 char *target
= NULL
;
1788 if (PG_ARGISNULL(0))
1789 pgstat_reset_of_kind(PGSTAT_KIND_SLRU
);
1792 target
= text_to_cstring(PG_GETARG_TEXT_PP(0));
1793 pgstat_reset_slru(target
);
1799 /* Reset replication slots stats (a specific one or all of them). */
1801 pg_stat_reset_replication_slot(PG_FUNCTION_ARGS
)
1803 char *target
= NULL
;
1805 if (PG_ARGISNULL(0))
1806 pgstat_reset_of_kind(PGSTAT_KIND_REPLSLOT
);
1809 target
= text_to_cstring(PG_GETARG_TEXT_PP(0));
1810 pgstat_reset_replslot(target
);
1816 /* Reset subscription stats (a specific one or all of them) */
1818 pg_stat_reset_subscription_stats(PG_FUNCTION_ARGS
)
1822 if (PG_ARGISNULL(0))
1824 /* Clear all subscription stats */
1825 pgstat_reset_of_kind(PGSTAT_KIND_SUBSCRIPTION
);
1829 subid
= PG_GETARG_OID(0);
1831 if (!OidIsValid(subid
))
1833 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1834 errmsg("invalid subscription OID %u", subid
)));
1835 pgstat_reset(PGSTAT_KIND_SUBSCRIPTION
, InvalidOid
, subid
);
1842 pg_stat_get_archiver(PG_FUNCTION_ARGS
)
1845 Datum values
[7] = {0};
1846 bool nulls
[7] = {0};
1847 PgStat_ArchiverStats
*archiver_stats
;
1849 /* Initialise attributes information in the tuple descriptor */
1850 tupdesc
= CreateTemplateTupleDesc(7);
1851 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, "archived_count",
1853 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "last_archived_wal",
1855 TupleDescInitEntry(tupdesc
, (AttrNumber
) 3, "last_archived_time",
1856 TIMESTAMPTZOID
, -1, 0);
1857 TupleDescInitEntry(tupdesc
, (AttrNumber
) 4, "failed_count",
1859 TupleDescInitEntry(tupdesc
, (AttrNumber
) 5, "last_failed_wal",
1861 TupleDescInitEntry(tupdesc
, (AttrNumber
) 6, "last_failed_time",
1862 TIMESTAMPTZOID
, -1, 0);
1863 TupleDescInitEntry(tupdesc
, (AttrNumber
) 7, "stats_reset",
1864 TIMESTAMPTZOID
, -1, 0);
1866 BlessTupleDesc(tupdesc
);
1868 /* Get statistics about the archiver process */
1869 archiver_stats
= pgstat_fetch_stat_archiver();
1871 /* Fill values and NULLs */
1872 values
[0] = Int64GetDatum(archiver_stats
->archived_count
);
1873 if (*(archiver_stats
->last_archived_wal
) == '\0')
1876 values
[1] = CStringGetTextDatum(archiver_stats
->last_archived_wal
);
1878 if (archiver_stats
->last_archived_timestamp
== 0)
1881 values
[2] = TimestampTzGetDatum(archiver_stats
->last_archived_timestamp
);
1883 values
[3] = Int64GetDatum(archiver_stats
->failed_count
);
1884 if (*(archiver_stats
->last_failed_wal
) == '\0')
1887 values
[4] = CStringGetTextDatum(archiver_stats
->last_failed_wal
);
1889 if (archiver_stats
->last_failed_timestamp
== 0)
1892 values
[5] = TimestampTzGetDatum(archiver_stats
->last_failed_timestamp
);
1894 if (archiver_stats
->stat_reset_timestamp
== 0)
1897 values
[6] = TimestampTzGetDatum(archiver_stats
->stat_reset_timestamp
);
1899 /* Returns the record as Datum */
1900 PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc
, values
, nulls
)));
1904 * Get the statistics for the replication slot. If the slot statistics is not
1905 * available, return all-zeroes stats.
1908 pg_stat_get_replication_slot(PG_FUNCTION_ARGS
)
1910 #define PG_STAT_GET_REPLICATION_SLOT_COLS 10
1911 text
*slotname_text
= PG_GETARG_TEXT_P(0);
1914 Datum values
[PG_STAT_GET_REPLICATION_SLOT_COLS
] = {0};
1915 bool nulls
[PG_STAT_GET_REPLICATION_SLOT_COLS
] = {0};
1916 PgStat_StatReplSlotEntry
*slotent
;
1917 PgStat_StatReplSlotEntry allzero
;
1919 /* Initialise attributes information in the tuple descriptor */
1920 tupdesc
= CreateTemplateTupleDesc(PG_STAT_GET_REPLICATION_SLOT_COLS
);
1921 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, "slot_name",
1923 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "spill_txns",
1925 TupleDescInitEntry(tupdesc
, (AttrNumber
) 3, "spill_count",
1927 TupleDescInitEntry(tupdesc
, (AttrNumber
) 4, "spill_bytes",
1929 TupleDescInitEntry(tupdesc
, (AttrNumber
) 5, "stream_txns",
1931 TupleDescInitEntry(tupdesc
, (AttrNumber
) 6, "stream_count",
1933 TupleDescInitEntry(tupdesc
, (AttrNumber
) 7, "stream_bytes",
1935 TupleDescInitEntry(tupdesc
, (AttrNumber
) 8, "total_txns",
1937 TupleDescInitEntry(tupdesc
, (AttrNumber
) 9, "total_bytes",
1939 TupleDescInitEntry(tupdesc
, (AttrNumber
) 10, "stats_reset",
1940 TIMESTAMPTZOID
, -1, 0);
1941 BlessTupleDesc(tupdesc
);
1943 namestrcpy(&slotname
, text_to_cstring(slotname_text
));
1944 slotent
= pgstat_fetch_replslot(slotname
);
1948 * If the slot is not found, initialise its stats. This is possible if
1949 * the create slot message is lost.
1951 memset(&allzero
, 0, sizeof(PgStat_StatReplSlotEntry
));
1955 values
[0] = CStringGetTextDatum(NameStr(slotname
));
1956 values
[1] = Int64GetDatum(slotent
->spill_txns
);
1957 values
[2] = Int64GetDatum(slotent
->spill_count
);
1958 values
[3] = Int64GetDatum(slotent
->spill_bytes
);
1959 values
[4] = Int64GetDatum(slotent
->stream_txns
);
1960 values
[5] = Int64GetDatum(slotent
->stream_count
);
1961 values
[6] = Int64GetDatum(slotent
->stream_bytes
);
1962 values
[7] = Int64GetDatum(slotent
->total_txns
);
1963 values
[8] = Int64GetDatum(slotent
->total_bytes
);
1965 if (slotent
->stat_reset_timestamp
== 0)
1968 values
[9] = TimestampTzGetDatum(slotent
->stat_reset_timestamp
);
1970 /* Returns the record as Datum */
1971 PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc
, values
, nulls
)));
1975 * Get the subscription statistics for the given subscription. If the
1976 * subscription statistics is not available, return all-zeros stats.
1979 pg_stat_get_subscription_stats(PG_FUNCTION_ARGS
)
1981 #define PG_STAT_GET_SUBSCRIPTION_STATS_COLS 10
1982 Oid subid
= PG_GETARG_OID(0);
1984 Datum values
[PG_STAT_GET_SUBSCRIPTION_STATS_COLS
] = {0};
1985 bool nulls
[PG_STAT_GET_SUBSCRIPTION_STATS_COLS
] = {0};
1986 PgStat_StatSubEntry
*subentry
;
1987 PgStat_StatSubEntry allzero
;
1990 /* Get subscription stats */
1991 subentry
= pgstat_fetch_stat_subscription(subid
);
1993 /* Initialise attributes information in the tuple descriptor */
1994 tupdesc
= CreateTemplateTupleDesc(PG_STAT_GET_SUBSCRIPTION_STATS_COLS
);
1995 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, "subid",
1997 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "apply_error_count",
1999 TupleDescInitEntry(tupdesc
, (AttrNumber
) 3, "sync_error_count",
2001 TupleDescInitEntry(tupdesc
, (AttrNumber
) 4, "confl_insert_exists",
2003 TupleDescInitEntry(tupdesc
, (AttrNumber
) 5, "confl_update_origin_differs",
2005 TupleDescInitEntry(tupdesc
, (AttrNumber
) 6, "confl_update_exists",
2007 TupleDescInitEntry(tupdesc
, (AttrNumber
) 7, "confl_update_missing",
2009 TupleDescInitEntry(tupdesc
, (AttrNumber
) 8, "confl_delete_origin_differs",
2011 TupleDescInitEntry(tupdesc
, (AttrNumber
) 9, "confl_delete_missing",
2013 TupleDescInitEntry(tupdesc
, (AttrNumber
) 10, "stats_reset",
2014 TIMESTAMPTZOID
, -1, 0);
2015 BlessTupleDesc(tupdesc
);
2019 /* If the subscription is not found, initialise its stats */
2020 memset(&allzero
, 0, sizeof(PgStat_StatSubEntry
));
2021 subentry
= &allzero
;
2025 values
[i
++] = ObjectIdGetDatum(subid
);
2027 /* apply_error_count */
2028 values
[i
++] = Int64GetDatum(subentry
->apply_error_count
);
2030 /* sync_error_count */
2031 values
[i
++] = Int64GetDatum(subentry
->sync_error_count
);
2033 /* conflict count */
2034 for (int nconflict
= 0; nconflict
< CONFLICT_NUM_TYPES
; nconflict
++)
2035 values
[i
++] = Int64GetDatum(subentry
->conflict_count
[nconflict
]);
2038 if (subentry
->stat_reset_timestamp
== 0)
2041 values
[i
] = TimestampTzGetDatum(subentry
->stat_reset_timestamp
);
2043 Assert(i
+ 1 == PG_STAT_GET_SUBSCRIPTION_STATS_COLS
);
2045 /* Returns the record as Datum */
2046 PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc
, values
, nulls
)));
2050 * Checks for presence of stats for object with provided kind, database oid,
2053 * This is useful for tests, but not really anything else. Therefore not
2057 pg_stat_have_stats(PG_FUNCTION_ARGS
)
2059 char *stats_type
= text_to_cstring(PG_GETARG_TEXT_P(0));
2060 Oid dboid
= PG_GETARG_OID(1);
2061 uint64 objid
= PG_GETARG_INT64(2);
2062 PgStat_Kind kind
= pgstat_get_kind_from_str(stats_type
);
2064 PG_RETURN_BOOL(pgstat_have_entry(kind
, dboid
, objid
));