Add notBefore and notAfter to SSL cert info display
[pgsql.git] / src / backend / utils / adt / pgstatfuncs.c
blob61522642cba63960ec3f786a891f4c9796cba58c
1 /*-------------------------------------------------------------------------
3 * pgstatfuncs.c
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
10 * IDENTIFICATION
11 * src/backend/utils/adt/pgstatfuncs.c
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
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"
24 #include "funcapi.h"
25 #include "miscadmin.h"
26 #include "pgstat.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) \
40 Datum \
41 CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS) \
42 { \
43 Oid relid = PG_GETARG_OID(0); \
44 int64 result; \
45 PgStat_StatTabEntry *tabentry; \
47 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
48 result = 0; \
49 else \
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) \
110 Datum \
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) \
118 result = 0; \
119 else \
120 result = tabentry->stat; \
122 if (result == 0) \
123 PG_RETURN_NULL(); \
124 else \
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)
143 Datum
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)
150 PG_RETURN_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) \
156 Datum \
157 CppConcat(pg_stat_get_function_,stat)(PG_FUNCTION_ARGS) \
159 Oid funcid = PG_GETARG_OID(0); \
160 double result; \
161 PgStat_StatFuncEntry *funcentry; \
163 if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL) \
164 PG_RETURN_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)
175 Datum
176 pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
178 FuncCallContext *funcctx;
179 int *fctx;
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,
188 sizeof(int));
189 funcctx->user_fctx = fctx;
191 fctx[0] = 0;
194 /* stuff done on every call of the function */
195 funcctx = SRF_PERCALL_SETUP();
196 fctx = funcctx->user_fctx;
198 fctx[0] += 1;
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));
216 else
218 /* do when there is no more left */
219 SRF_RETURN_DONE(funcctx);
224 * Returns command progress information for the named command.
226 Datum
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();
231 int curr_backend;
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;
249 else
250 ereport(ERROR,
251 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
252 errmsg("invalid command name: \"%s\"", cmd)));
254 InitMaterializedSRF(fcinfo, 0);
256 /* 1-based index */
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};
263 int i;
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
270 * command.
272 if (beentry->st_progress_command != cmdtype)
273 continue;
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]);
286 else
288 nulls[2] = true;
289 for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
290 nulls[i + 3] = true;
293 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
296 return (Datum) 0;
300 * Returns activity of PG backends.
302 Datum
303 pg_stat_get_activity(PG_FUNCTION_ARGS)
305 #define PG_STAT_GET_ACTIVITY_COLS 33
306 int num_backends = pgstat_fetch_stat_numbackends();
307 int curr_backend;
308 int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
309 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
311 InitMaterializedSRF(fcinfo, 0);
313 /* 1-based index */
314 for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
316 /* for each row */
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;
321 PGPROC *proc;
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)
331 continue;
333 /* Values available to all callers */
334 if (beentry->st_databaseid != InvalidOid)
335 values[0] = ObjectIdGetDatum(beentry->st_databaseid);
336 else
337 nulls[0] = true;
339 values[1] = Int32GetDatum(beentry->st_procpid);
341 if (beentry->st_userid != InvalidOid)
342 values[2] = ObjectIdGetDatum(beentry->st_userid);
343 else
344 nulls[2] = true;
346 if (beentry->st_appname)
347 values[3] = CStringGetTextDatum(beentry->st_appname);
348 else
349 nulls[3] = true;
351 if (TransactionIdIsValid(local_beentry->backend_xid))
352 values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
353 else
354 nulls[15] = true;
356 if (TransactionIdIsValid(local_beentry->backend_xmin))
357 values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
358 else
359 nulls[16] = true;
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)
369 case STATE_IDLE:
370 values[4] = CStringGetTextDatum("idle");
371 break;
372 case STATE_RUNNING:
373 values[4] = CStringGetTextDatum("active");
374 break;
375 case STATE_IDLEINTRANSACTION:
376 values[4] = CStringGetTextDatum("idle in transaction");
377 break;
378 case STATE_FASTPATH:
379 values[4] = CStringGetTextDatum("fastpath function call");
380 break;
381 case STATE_IDLEINTRANSACTION_ABORTED:
382 values[4] = CStringGetTextDatum("idle in transaction (aborted)");
383 break;
384 case STATE_DISABLED:
385 values[4] = CStringGetTextDatum("disabled");
386 break;
387 case STATE_UNDEFINED:
388 nulls[4] = true;
389 break;
392 clipped_activity = pgstat_clip_activity(beentry->st_activity_raw);
393 values[5] = CStringGetTextDatum(clipped_activity);
394 pfree(clipped_activity);
396 /* leader_pid */
397 nulls[31] = true;
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.
416 if (proc != NULL)
418 uint32 raw_wait_event;
419 PGPROC *leader;
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[31] = Int32GetDatum(leader->pid);
435 nulls[31] = false;
437 else if (beentry->st_backendType == B_BG_WORKER)
439 int leader_pid = GetLeaderApplyWorkerPid(beentry->st_procpid);
441 if (leader_pid != InvalidPid)
443 values[31] = Int32GetDatum(leader_pid);
444 nulls[31] = false;
449 if (wait_event_type)
450 values[6] = CStringGetTextDatum(wait_event_type);
451 else
452 nulls[6] = true;
454 if (wait_event)
455 values[7] = CStringGetTextDatum(wait_event);
456 else
457 nulls[7] = true;
460 * Don't expose transaction time for walsenders; it confuses
461 * monitoring, particularly because we don't keep the time up-to-
462 * date.
464 if (beentry->st_xact_start_timestamp != 0 &&
465 beentry->st_backendType != B_WAL_SENDER)
466 values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
467 else
468 nulls[8] = true;
470 if (beentry->st_activity_start_timestamp != 0)
471 values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
472 else
473 nulls[9] = true;
475 if (beentry->st_proc_start_timestamp != 0)
476 values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
477 else
478 nulls[10] = true;
480 if (beentry->st_state_start_timestamp != 0)
481 values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
482 else
483 nulls[11] = true;
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)
490 nulls[12] = true;
491 nulls[13] = true;
492 nulls[14] = true;
494 else
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];
501 int ret;
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);
510 if (ret == 0)
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);
518 else
519 nulls[13] = true;
520 values[14] = Int32GetDatum(atoi(remote_port));
522 else
524 nulls[12] = true;
525 nulls[13] = true;
526 nulls[14] = true;
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
535 * errors.
537 nulls[12] = true;
538 nulls[13] = true;
539 values[14] = Int32GetDatum(-1);
541 else
543 /* Unknown address type, should never happen */
544 nulls[12] = true;
545 nulls[13] = true;
546 nulls[14] = true;
549 /* Add backend type */
550 if (beentry->st_backendType == B_BG_WORKER)
552 const char *bgw_type;
554 bgw_type = GetBackgroundWorkerTypeByPid(beentry->st_procpid);
555 if (bgw_type)
556 values[17] = CStringGetTextDatum(bgw_type);
557 else
558 nulls[17] = true;
560 else
561 values[17] =
562 CStringGetTextDatum(GetBackendTypeDesc(beentry->st_backendType));
564 /* SSL information */
565 if (beentry->st_ssl)
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);
574 else
575 nulls[22] = true;
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),
581 Int32GetDatum(-1));
582 else
583 nulls[23] = true;
585 if (beentry->st_sslstatus->ssl_issuer_dn[0])
586 values[24] = CStringGetTextDatum(beentry->st_sslstatus->ssl_issuer_dn);
587 else
588 nulls[24] = true;
590 if (beentry->st_sslstatus->ssl_not_before != 0)
591 values[25] = TimestampTzGetDatum(beentry->st_sslstatus->ssl_not_before);
592 else
593 nulls[25] = true;
595 if (beentry->st_sslstatus->ssl_not_after != 0)
596 values[26] = TimestampTzGetDatum(beentry->st_sslstatus->ssl_not_after);
597 else
598 nulls[26] = true;
600 else
602 values[18] = BoolGetDatum(false); /* ssl */
603 nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = nulls[25] = nulls[26] = true;
606 /* GSSAPI information */
607 if (beentry->st_gss)
609 values[27] = BoolGetDatum(beentry->st_gssstatus->gss_auth); /* gss_auth */
610 values[28] = CStringGetTextDatum(beentry->st_gssstatus->gss_princ);
611 values[29] = BoolGetDatum(beentry->st_gssstatus->gss_enc); /* GSS Encryption in use */
612 values[30] = BoolGetDatum(beentry->st_gssstatus->gss_delegation); /* GSS credentials
613 * delegated */
615 else
617 values[27] = BoolGetDatum(false); /* gss_auth */
618 nulls[28] = true; /* No GSS principal */
619 values[29] = BoolGetDatum(false); /* GSS Encryption not in
620 * use */
621 values[30] = BoolGetDatum(false); /* GSS credentials not
622 * delegated */
624 if (beentry->st_query_id == 0)
625 nulls[32] = true;
626 else
627 values[32] = UInt64GetDatum(beentry->st_query_id);
629 else
631 /* No permissions to view data about this session */
632 values[5] = CStringGetTextDatum("<insufficient privilege>");
633 nulls[4] = true;
634 nulls[6] = true;
635 nulls[7] = true;
636 nulls[8] = true;
637 nulls[9] = true;
638 nulls[10] = true;
639 nulls[11] = true;
640 nulls[12] = true;
641 nulls[13] = true;
642 nulls[14] = true;
643 nulls[17] = true;
644 nulls[18] = true;
645 nulls[19] = true;
646 nulls[20] = true;
647 nulls[21] = true;
648 nulls[22] = true;
649 nulls[23] = true;
650 nulls[24] = true;
651 nulls[25] = true;
652 nulls[26] = true;
653 nulls[27] = true;
654 nulls[28] = true;
655 nulls[29] = true;
656 nulls[30] = true;
657 nulls[31] = true;
658 nulls[32] = true;
661 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
663 /* If only a single backend was requested, and we found it, break. */
664 if (pid != -1)
665 break;
668 return (Datum) 0;
672 Datum
673 pg_backend_pid(PG_FUNCTION_ARGS)
675 PG_RETURN_INT32(MyProcPid);
679 Datum
680 pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
682 int32 procNumber = PG_GETARG_INT32(0);
683 PgBackendStatus *beentry;
685 if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
686 PG_RETURN_NULL();
688 PG_RETURN_INT32(beentry->st_procpid);
692 Datum
693 pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
695 int32 procNumber = PG_GETARG_INT32(0);
696 PgBackendStatus *beentry;
698 if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
699 PG_RETURN_NULL();
701 PG_RETURN_OID(beentry->st_databaseid);
705 Datum
706 pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
708 int32 procNumber = PG_GETARG_INT32(0);
709 PgBackendStatus *beentry;
711 if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
712 PG_RETURN_NULL();
714 PG_RETURN_OID(beentry->st_userid);
717 Datum
718 pg_stat_get_backend_subxact(PG_FUNCTION_ARGS)
720 #define PG_STAT_GET_SUBXACT_COLS 2
721 TupleDesc tupdesc;
722 Datum values[PG_STAT_GET_SUBXACT_COLS] = {0};
723 bool nulls[PG_STAT_GET_SUBXACT_COLS] = {0};
724 int32 procNumber = PG_GETARG_INT32(0);
725 LocalPgBackendStatus *local_beentry;
727 /* Initialise attributes information in the tuple descriptor */
728 tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_SUBXACT_COLS);
729 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "subxact_count",
730 INT4OID, -1, 0);
731 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "subxact_overflow",
732 BOOLOID, -1, 0);
734 BlessTupleDesc(tupdesc);
736 if ((local_beentry = pgstat_get_local_beentry_by_proc_number(procNumber)) != NULL)
738 /* Fill values and NULLs */
739 values[0] = Int32GetDatum(local_beentry->backend_subxact_count);
740 values[1] = BoolGetDatum(local_beentry->backend_subxact_overflowed);
742 else
744 nulls[0] = true;
745 nulls[1] = true;
748 /* Returns the record as Datum */
749 PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
752 Datum
753 pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
755 int32 procNumber = PG_GETARG_INT32(0);
756 PgBackendStatus *beentry;
757 const char *activity;
758 char *clipped_activity;
759 text *ret;
761 if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
762 activity = "<backend information not available>";
763 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
764 activity = "<insufficient privilege>";
765 else if (*(beentry->st_activity_raw) == '\0')
766 activity = "<command string not enabled>";
767 else
768 activity = beentry->st_activity_raw;
770 clipped_activity = pgstat_clip_activity(activity);
771 ret = cstring_to_text(activity);
772 pfree(clipped_activity);
774 PG_RETURN_TEXT_P(ret);
777 Datum
778 pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS)
780 int32 procNumber = PG_GETARG_INT32(0);
781 PgBackendStatus *beentry;
782 PGPROC *proc;
783 const char *wait_event_type = NULL;
785 if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
786 wait_event_type = "<backend information not available>";
787 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
788 wait_event_type = "<insufficient privilege>";
789 else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
790 wait_event_type = pgstat_get_wait_event_type(proc->wait_event_info);
792 if (!wait_event_type)
793 PG_RETURN_NULL();
795 PG_RETURN_TEXT_P(cstring_to_text(wait_event_type));
798 Datum
799 pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS)
801 int32 procNumber = PG_GETARG_INT32(0);
802 PgBackendStatus *beentry;
803 PGPROC *proc;
804 const char *wait_event = NULL;
806 if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
807 wait_event = "<backend information not available>";
808 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
809 wait_event = "<insufficient privilege>";
810 else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
811 wait_event = pgstat_get_wait_event(proc->wait_event_info);
813 if (!wait_event)
814 PG_RETURN_NULL();
816 PG_RETURN_TEXT_P(cstring_to_text(wait_event));
820 Datum
821 pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
823 int32 procNumber = PG_GETARG_INT32(0);
824 TimestampTz result;
825 PgBackendStatus *beentry;
827 if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
828 PG_RETURN_NULL();
830 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
831 PG_RETURN_NULL();
833 result = beentry->st_activity_start_timestamp;
836 * No time recorded for start of current query -- this is the case if the
837 * user hasn't enabled query-level stats collection.
839 if (result == 0)
840 PG_RETURN_NULL();
842 PG_RETURN_TIMESTAMPTZ(result);
846 Datum
847 pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)
849 int32 procNumber = PG_GETARG_INT32(0);
850 TimestampTz result;
851 PgBackendStatus *beentry;
853 if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
854 PG_RETURN_NULL();
856 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
857 PG_RETURN_NULL();
859 result = beentry->st_xact_start_timestamp;
861 if (result == 0) /* not in a transaction */
862 PG_RETURN_NULL();
864 PG_RETURN_TIMESTAMPTZ(result);
868 Datum
869 pg_stat_get_backend_start(PG_FUNCTION_ARGS)
871 int32 procNumber = PG_GETARG_INT32(0);
872 TimestampTz result;
873 PgBackendStatus *beentry;
875 if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
876 PG_RETURN_NULL();
878 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
879 PG_RETURN_NULL();
881 result = beentry->st_proc_start_timestamp;
883 if (result == 0) /* probably can't happen? */
884 PG_RETURN_NULL();
886 PG_RETURN_TIMESTAMPTZ(result);
890 Datum
891 pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
893 int32 procNumber = PG_GETARG_INT32(0);
894 PgBackendStatus *beentry;
895 SockAddr zero_clientaddr;
896 char remote_host[NI_MAXHOST];
897 int ret;
899 if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
900 PG_RETURN_NULL();
902 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
903 PG_RETURN_NULL();
905 /* A zeroed client addr means we don't know */
906 memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
907 if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
908 sizeof(zero_clientaddr)) == 0)
909 PG_RETURN_NULL();
911 switch (beentry->st_clientaddr.addr.ss_family)
913 case AF_INET:
914 case AF_INET6:
915 break;
916 default:
917 PG_RETURN_NULL();
920 remote_host[0] = '\0';
921 ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
922 beentry->st_clientaddr.salen,
923 remote_host, sizeof(remote_host),
924 NULL, 0,
925 NI_NUMERICHOST | NI_NUMERICSERV);
926 if (ret != 0)
927 PG_RETURN_NULL();
929 clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
931 PG_RETURN_DATUM(DirectFunctionCall1(inet_in,
932 CStringGetDatum(remote_host)));
935 Datum
936 pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
938 int32 procNumber = PG_GETARG_INT32(0);
939 PgBackendStatus *beentry;
940 SockAddr zero_clientaddr;
941 char remote_port[NI_MAXSERV];
942 int ret;
944 if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
945 PG_RETURN_NULL();
947 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
948 PG_RETURN_NULL();
950 /* A zeroed client addr means we don't know */
951 memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
952 if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
953 sizeof(zero_clientaddr)) == 0)
954 PG_RETURN_NULL();
956 switch (beentry->st_clientaddr.addr.ss_family)
958 case AF_INET:
959 case AF_INET6:
960 break;
961 case AF_UNIX:
962 PG_RETURN_INT32(-1);
963 default:
964 PG_RETURN_NULL();
967 remote_port[0] = '\0';
968 ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
969 beentry->st_clientaddr.salen,
970 NULL, 0,
971 remote_port, sizeof(remote_port),
972 NI_NUMERICHOST | NI_NUMERICSERV);
973 if (ret != 0)
974 PG_RETURN_NULL();
976 PG_RETURN_DATUM(DirectFunctionCall1(int4in,
977 CStringGetDatum(remote_port)));
981 Datum
982 pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
984 Oid dbid = PG_GETARG_OID(0);
985 int32 result;
986 int tot_backends = pgstat_fetch_stat_numbackends();
987 int idx;
989 result = 0;
990 for (idx = 1; idx <= tot_backends; idx++)
992 LocalPgBackendStatus *local_beentry = pgstat_get_local_beentry_by_index(idx);
994 if (local_beentry->backendStatus.st_databaseid == dbid)
995 result++;
998 PG_RETURN_INT32(result);
1002 #define PG_STAT_GET_DBENTRY_INT64(stat) \
1003 Datum \
1004 CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS) \
1006 Oid dbid = PG_GETARG_OID(0); \
1007 int64 result; \
1008 PgStat_StatDBEntry *dbentry; \
1010 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) \
1011 result = 0; \
1012 else \
1013 result = (int64) (dbentry->stat); \
1015 PG_RETURN_INT64(result); \
1018 /* pg_stat_get_db_blocks_fetched */
1019 PG_STAT_GET_DBENTRY_INT64(blocks_fetched)
1021 /* pg_stat_get_db_blocks_hit */
1022 PG_STAT_GET_DBENTRY_INT64(blocks_hit)
1024 /* pg_stat_get_db_conflict_bufferpin */
1025 PG_STAT_GET_DBENTRY_INT64(conflict_bufferpin)
1027 /* pg_stat_get_db_conflict_lock */
1028 PG_STAT_GET_DBENTRY_INT64(conflict_lock)
1030 /* pg_stat_get_db_conflict_snapshot */
1031 PG_STAT_GET_DBENTRY_INT64(conflict_snapshot)
1033 /* pg_stat_get_db_conflict_startup_deadlock */
1034 PG_STAT_GET_DBENTRY_INT64(conflict_startup_deadlock)
1036 /* pg_stat_get_db_conflict_tablespace */
1037 PG_STAT_GET_DBENTRY_INT64(conflict_tablespace)
1039 /* pg_stat_get_db_deadlocks */
1040 PG_STAT_GET_DBENTRY_INT64(deadlocks)
1042 /* pg_stat_get_db_sessions */
1043 PG_STAT_GET_DBENTRY_INT64(sessions)
1045 /* pg_stat_get_db_sessions_abandoned */
1046 PG_STAT_GET_DBENTRY_INT64(sessions_abandoned)
1048 /* pg_stat_get_db_sessions_fatal */
1049 PG_STAT_GET_DBENTRY_INT64(sessions_fatal)
1051 /* pg_stat_get_db_sessions_killed */
1052 PG_STAT_GET_DBENTRY_INT64(sessions_killed)
1054 /* pg_stat_get_db_temp_bytes */
1055 PG_STAT_GET_DBENTRY_INT64(temp_bytes)
1057 /* pg_stat_get_db_temp_files */
1058 PG_STAT_GET_DBENTRY_INT64(temp_files)
1060 /* pg_stat_get_db_tuples_deleted */
1061 PG_STAT_GET_DBENTRY_INT64(tuples_deleted)
1063 /* pg_stat_get_db_tuples_fetched */
1064 PG_STAT_GET_DBENTRY_INT64(tuples_fetched)
1066 /* pg_stat_get_db_tuples_inserted */
1067 PG_STAT_GET_DBENTRY_INT64(tuples_inserted)
1069 /* pg_stat_get_db_tuples_returned */
1070 PG_STAT_GET_DBENTRY_INT64(tuples_returned)
1072 /* pg_stat_get_db_tuples_updated */
1073 PG_STAT_GET_DBENTRY_INT64(tuples_updated)
1075 /* pg_stat_get_db_xact_commit */
1076 PG_STAT_GET_DBENTRY_INT64(xact_commit)
1078 /* pg_stat_get_db_xact_rollback */
1079 PG_STAT_GET_DBENTRY_INT64(xact_rollback)
1081 /* pg_stat_get_db_conflict_logicalslot */
1082 PG_STAT_GET_DBENTRY_INT64(conflict_logicalslot)
1084 Datum
1085 pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)
1087 Oid dbid = PG_GETARG_OID(0);
1088 TimestampTz result;
1089 PgStat_StatDBEntry *dbentry;
1091 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1092 result = 0;
1093 else
1094 result = dbentry->stat_reset_timestamp;
1096 if (result == 0)
1097 PG_RETURN_NULL();
1098 else
1099 PG_RETURN_TIMESTAMPTZ(result);
1103 Datum
1104 pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS)
1106 Oid dbid = PG_GETARG_OID(0);
1107 int64 result;
1108 PgStat_StatDBEntry *dbentry;
1110 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1111 result = 0;
1112 else
1113 result = (int64) (dbentry->conflict_tablespace +
1114 dbentry->conflict_lock +
1115 dbentry->conflict_snapshot +
1116 dbentry->conflict_logicalslot +
1117 dbentry->conflict_bufferpin +
1118 dbentry->conflict_startup_deadlock);
1120 PG_RETURN_INT64(result);
1123 Datum
1124 pg_stat_get_db_checksum_failures(PG_FUNCTION_ARGS)
1126 Oid dbid = PG_GETARG_OID(0);
1127 int64 result;
1128 PgStat_StatDBEntry *dbentry;
1130 if (!DataChecksumsEnabled())
1131 PG_RETURN_NULL();
1133 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1134 result = 0;
1135 else
1136 result = (int64) (dbentry->checksum_failures);
1138 PG_RETURN_INT64(result);
1141 Datum
1142 pg_stat_get_db_checksum_last_failure(PG_FUNCTION_ARGS)
1144 Oid dbid = PG_GETARG_OID(0);
1145 TimestampTz result;
1146 PgStat_StatDBEntry *dbentry;
1148 if (!DataChecksumsEnabled())
1149 PG_RETURN_NULL();
1151 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1152 result = 0;
1153 else
1154 result = dbentry->last_checksum_failure;
1156 if (result == 0)
1157 PG_RETURN_NULL();
1158 else
1159 PG_RETURN_TIMESTAMPTZ(result);
1162 /* convert counter from microsec to millisec for display */
1163 #define PG_STAT_GET_DBENTRY_FLOAT8_MS(stat) \
1164 Datum \
1165 CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS) \
1167 Oid dbid = PG_GETARG_OID(0); \
1168 double result; \
1169 PgStat_StatDBEntry *dbentry; \
1171 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) \
1172 result = 0; \
1173 else \
1174 result = ((double) dbentry->stat) / 1000.0; \
1176 PG_RETURN_FLOAT8(result); \
1179 /* pg_stat_get_db_active_time */
1180 PG_STAT_GET_DBENTRY_FLOAT8_MS(active_time)
1182 /* pg_stat_get_db_blk_read_time */
1183 PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_read_time)
1185 /* pg_stat_get_db_blk_write_time */
1186 PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_write_time)
1188 /* pg_stat_get_db_idle_in_transaction_time */
1189 PG_STAT_GET_DBENTRY_FLOAT8_MS(idle_in_transaction_time)
1191 /* pg_stat_get_db_session_time */
1192 PG_STAT_GET_DBENTRY_FLOAT8_MS(session_time)
1194 Datum
1195 pg_stat_get_checkpointer_num_timed(PG_FUNCTION_ARGS)
1197 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_timed);
1200 Datum
1201 pg_stat_get_checkpointer_num_requested(PG_FUNCTION_ARGS)
1203 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_requested);
1206 Datum
1207 pg_stat_get_checkpointer_restartpoints_timed(PG_FUNCTION_ARGS)
1209 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_timed);
1212 Datum
1213 pg_stat_get_checkpointer_restartpoints_requested(PG_FUNCTION_ARGS)
1215 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_requested);
1218 Datum
1219 pg_stat_get_checkpointer_restartpoints_performed(PG_FUNCTION_ARGS)
1221 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_performed);
1224 Datum
1225 pg_stat_get_checkpointer_buffers_written(PG_FUNCTION_ARGS)
1227 PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buffers_written);
1230 Datum
1231 pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)
1233 PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->buf_written_clean);
1236 Datum
1237 pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
1239 PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->maxwritten_clean);
1242 Datum
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);
1250 Datum
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);
1258 Datum
1259 pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
1261 PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
1264 Datum
1265 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
1267 PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_bgwriter()->stat_reset_timestamp);
1270 Datum
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,
1284 IO_COL_OBJECT,
1285 IO_COL_CONTEXT,
1286 IO_COL_READS,
1287 IO_COL_READ_TIME,
1288 IO_COL_WRITES,
1289 IO_COL_WRITE_TIME,
1290 IO_COL_WRITEBACKS,
1291 IO_COL_WRITEBACK_TIME,
1292 IO_COL_EXTENDS,
1293 IO_COL_EXTEND_TIME,
1294 IO_COL_CONVERSION,
1295 IO_COL_HITS,
1296 IO_COL_EVICTIONS,
1297 IO_COL_REUSES,
1298 IO_COL_FSYNCS,
1299 IO_COL_FSYNC_TIME,
1300 IO_COL_RESET_TIME,
1301 IO_NUM_COLUMNS,
1302 } io_stat_col;
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.
1308 static io_stat_col
1309 pgstat_get_io_op_index(IOOp io_op)
1311 switch (io_op)
1313 case IOOP_EVICT:
1314 return IO_COL_EVICTIONS;
1315 case IOOP_EXTEND:
1316 return IO_COL_EXTENDS;
1317 case IOOP_FSYNC:
1318 return IO_COL_FSYNCS;
1319 case IOOP_HIT:
1320 return IO_COL_HITS;
1321 case IOOP_READ:
1322 return IO_COL_READS;
1323 case IOOP_REUSE:
1324 return IO_COL_REUSES;
1325 case IOOP_WRITE:
1326 return IO_COL_WRITES;
1327 case IOOP_WRITEBACK:
1328 return IO_COL_WRITEBACKS;
1331 elog(ERROR, "unrecognized IOOp value: %d", io_op);
1332 pg_unreachable();
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.
1341 static io_stat_col
1342 pgstat_get_io_time_index(IOOp io_op)
1344 switch (io_op)
1346 case IOOP_READ:
1347 case IOOP_WRITE:
1348 case IOOP_WRITEBACK:
1349 case IOOP_EXTEND:
1350 case IOOP_FSYNC:
1351 return pgstat_get_io_op_index(io_op) + 1;
1352 case IOOP_EVICT:
1353 case IOOP_HIT:
1354 case IOOP_REUSE:
1355 return IO_COL_INVALID;
1358 elog(ERROR, "unrecognized IOOp value: %d", io_op);
1359 pg_unreachable();
1362 static inline double
1363 pg_stat_us_to_ms(PgStat_Counter val_ms)
1365 return val_ms * (double) 0.001;
1368 Datum
1369 pg_stat_get_io(PG_FUNCTION_ARGS)
1371 ReturnSetInfo *rsinfo;
1372 PgStat_IO *backends_io_stats;
1373 Datum reset_time;
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))
1399 continue;
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))
1418 continue;
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] = TimestampTzGetDatum(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);
1450 else
1451 nulls[op_idx] = true;
1453 /* not every operation is timed */
1454 if (time_idx == IO_COL_INVALID)
1455 continue;
1457 if (!nulls[op_idx])
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));
1464 else
1465 nulls[time_idx] = true;
1468 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1469 values, nulls);
1474 return (Datum) 0;
1478 * Returns statistics of WAL activity
1480 Datum
1481 pg_stat_get_wal(PG_FUNCTION_ARGS)
1483 #define PG_STAT_GET_WAL_COLS 9
1484 TupleDesc tupdesc;
1485 Datum values[PG_STAT_GET_WAL_COLS] = {0};
1486 bool nulls[PG_STAT_GET_WAL_COLS] = {0};
1487 char buf[256];
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",
1493 INT8OID, -1, 0);
1494 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "wal_fpi",
1495 INT8OID, -1, 0);
1496 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "wal_bytes",
1497 NUMERICOID, -1, 0);
1498 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_buffers_full",
1499 INT8OID, -1, 0);
1500 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "wal_write",
1501 INT8OID, -1, 0);
1502 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "wal_sync",
1503 INT8OID, -1, 0);
1504 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "wal_write_time",
1505 FLOAT8OID, -1, 0);
1506 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "wal_sync_time",
1507 FLOAT8OID, -1, 0);
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),
1525 Int32GetDatum(-1));
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.
1544 Datum
1545 pg_stat_get_slru(PG_FUNCTION_ARGS)
1547 #define PG_STAT_GET_SLRU_COLS 9
1548 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1549 int i;
1550 PgStat_SLRUStats *stats;
1552 InitMaterializedSRF(fcinfo, 0);
1554 /* request SLRU stats from the cumulative stats system */
1555 stats = pgstat_fetch_slru();
1557 for (i = 0;; i++)
1559 /* for each row */
1560 Datum values[PG_STAT_GET_SLRU_COLS] = {0};
1561 bool nulls[PG_STAT_GET_SLRU_COLS] = {0};
1562 PgStat_SLRUStats stat;
1563 const char *name;
1565 name = pgstat_get_slru_name(i);
1567 if (!name)
1568 break;
1570 stat = stats[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);
1585 return (Datum) 0;
1588 #define PG_STAT_GET_XACT_RELENTRY_INT64(stat) \
1589 Datum \
1590 CppConcat(pg_stat_get_xact_,stat)(PG_FUNCTION_ARGS) \
1592 Oid relid = PG_GETARG_OID(0); \
1593 int64 result; \
1594 PgStat_TableStatus *tabentry; \
1596 if ((tabentry = find_tabstat_entry(relid)) == NULL) \
1597 result = 0; \
1598 else \
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)
1634 Datum
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)
1641 PG_RETURN_NULL();
1642 PG_RETURN_INT64(funcentry->numcalls);
1645 #define PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(stat) \
1646 Datum \
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) \
1653 PG_RETURN_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 */
1664 Datum
1665 pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS)
1667 bool have_snapshot;
1668 TimestampTz ts;
1670 ts = pgstat_get_stat_snapshot_timestamp(&have_snapshot);
1672 if (!have_snapshot)
1673 PG_RETURN_NULL();
1675 PG_RETURN_TIMESTAMPTZ(ts);
1678 /* Discard the active statistics snapshot */
1679 Datum
1680 pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
1682 pgstat_clear_snapshot();
1684 PG_RETURN_VOID();
1688 /* Force statistics to be reported at the next occasion */
1689 Datum
1690 pg_stat_force_next_flush(PG_FUNCTION_ARGS)
1692 pgstat_force_next_flush();
1694 PG_RETURN_VOID();
1698 /* Reset all counters for the current database */
1699 Datum
1700 pg_stat_reset(PG_FUNCTION_ARGS)
1702 pgstat_reset_counters();
1704 PG_RETURN_VOID();
1708 * Reset some shared cluster-wide counters
1710 * When adding a new reset target, ideally the name should match that in
1711 * pgstat_kind_infos, if relevant.
1713 Datum
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);
1729 PG_RETURN_VOID();
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);
1748 else
1749 ereport(ERROR,
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\".")));
1754 PG_RETURN_VOID();
1758 * Reset a statistics for a single object, which may be of current
1759 * database or shared across all databases in the cluster.
1761 Datum
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);
1769 PG_RETURN_VOID();
1772 Datum
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);
1779 PG_RETURN_VOID();
1782 /* Reset SLRU counters (a specific one or all of them). */
1783 Datum
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);
1790 else
1792 target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1793 pgstat_reset_slru(target);
1796 PG_RETURN_VOID();
1799 /* Reset replication slots stats (a specific one or all of them). */
1800 Datum
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);
1807 else
1809 target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1810 pgstat_reset_replslot(target);
1813 PG_RETURN_VOID();
1816 /* Reset subscription stats (a specific one or all of them) */
1817 Datum
1818 pg_stat_reset_subscription_stats(PG_FUNCTION_ARGS)
1820 Oid subid;
1822 if (PG_ARGISNULL(0))
1824 /* Clear all subscription stats */
1825 pgstat_reset_of_kind(PGSTAT_KIND_SUBSCRIPTION);
1827 else
1829 subid = PG_GETARG_OID(0);
1831 if (!OidIsValid(subid))
1832 ereport(ERROR,
1833 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1834 errmsg("invalid subscription OID %u", subid)));
1835 pgstat_reset(PGSTAT_KIND_SUBSCRIPTION, InvalidOid, subid);
1838 PG_RETURN_VOID();
1841 Datum
1842 pg_stat_get_archiver(PG_FUNCTION_ARGS)
1844 TupleDesc tupdesc;
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",
1852 INT8OID, -1, 0);
1853 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
1854 TEXTOID, -1, 0);
1855 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time",
1856 TIMESTAMPTZOID, -1, 0);
1857 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count",
1858 INT8OID, -1, 0);
1859 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
1860 TEXTOID, -1, 0);
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')
1874 nulls[1] = true;
1875 else
1876 values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
1878 if (archiver_stats->last_archived_timestamp == 0)
1879 nulls[2] = true;
1880 else
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')
1885 nulls[4] = true;
1886 else
1887 values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
1889 if (archiver_stats->last_failed_timestamp == 0)
1890 nulls[5] = true;
1891 else
1892 values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp);
1894 if (archiver_stats->stat_reset_timestamp == 0)
1895 nulls[6] = true;
1896 else
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.
1907 Datum
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);
1912 NameData slotname;
1913 TupleDesc tupdesc;
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",
1922 TEXTOID, -1, 0);
1923 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "spill_txns",
1924 INT8OID, -1, 0);
1925 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "spill_count",
1926 INT8OID, -1, 0);
1927 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "spill_bytes",
1928 INT8OID, -1, 0);
1929 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "stream_txns",
1930 INT8OID, -1, 0);
1931 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "stream_count",
1932 INT8OID, -1, 0);
1933 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stream_bytes",
1934 INT8OID, -1, 0);
1935 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "total_txns",
1936 INT8OID, -1, 0);
1937 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "total_bytes",
1938 INT8OID, -1, 0);
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);
1945 if (!slotent)
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));
1952 slotent = &allzero;
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)
1966 nulls[9] = true;
1967 else
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.
1978 Datum
1979 pg_stat_get_subscription_stats(PG_FUNCTION_ARGS)
1981 #define PG_STAT_GET_SUBSCRIPTION_STATS_COLS 4
1982 Oid subid = PG_GETARG_OID(0);
1983 TupleDesc tupdesc;
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;
1989 /* Get subscription stats */
1990 subentry = pgstat_fetch_stat_subscription(subid);
1992 /* Initialise attributes information in the tuple descriptor */
1993 tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_SUBSCRIPTION_STATS_COLS);
1994 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "subid",
1995 OIDOID, -1, 0);
1996 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "apply_error_count",
1997 INT8OID, -1, 0);
1998 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "sync_error_count",
1999 INT8OID, -1, 0);
2000 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "stats_reset",
2001 TIMESTAMPTZOID, -1, 0);
2002 BlessTupleDesc(tupdesc);
2004 if (!subentry)
2006 /* If the subscription is not found, initialise its stats */
2007 memset(&allzero, 0, sizeof(PgStat_StatSubEntry));
2008 subentry = &allzero;
2011 /* subid */
2012 values[0] = ObjectIdGetDatum(subid);
2014 /* apply_error_count */
2015 values[1] = Int64GetDatum(subentry->apply_error_count);
2017 /* sync_error_count */
2018 values[2] = Int64GetDatum(subentry->sync_error_count);
2020 /* stats_reset */
2021 if (subentry->stat_reset_timestamp == 0)
2022 nulls[3] = true;
2023 else
2024 values[3] = TimestampTzGetDatum(subentry->stat_reset_timestamp);
2026 /* Returns the record as Datum */
2027 PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
2031 * Checks for presence of stats for object with provided kind, database oid,
2032 * object oid.
2034 * This is useful for tests, but not really anything else. Therefore not
2035 * documented.
2037 Datum
2038 pg_stat_have_stats(PG_FUNCTION_ARGS)
2040 char *stats_type = text_to_cstring(PG_GETARG_TEXT_P(0));
2041 Oid dboid = PG_GETARG_OID(1);
2042 Oid objoid = PG_GETARG_OID(2);
2043 PgStat_Kind kind = pgstat_get_kind_from_str(stats_type);
2045 PG_RETURN_BOOL(pgstat_have_entry(kind, dboid, objoid));