Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pgstatfuncs.c
4 : * Functions for accessing various forms of statistics data
5 : *
6 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/utils/adt/pgstatfuncs.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
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"
34 :
35 : #define UINT32_ACCESS_ONCE(var) ((uint32)(*((volatile uint32 *)&(var))))
36 :
37 : #define HAS_PGSTAT_PERMISSIONS(role) (has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role))
38 :
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; \
46 : \
47 : if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
48 : result = 0; \
49 : else \
50 : result = (int64) (tabentry->stat); \
51 : \
52 : PG_RETURN_INT64(result); \
53 : }
54 :
55 : /* pg_stat_get_analyze_count */
56 0 : PG_STAT_GET_RELENTRY_INT64(analyze_count)
57 :
58 : /* pg_stat_get_autoanalyze_count */
59 0 : PG_STAT_GET_RELENTRY_INT64(autoanalyze_count)
60 :
61 : /* pg_stat_get_autovacuum_count */
62 0 : PG_STAT_GET_RELENTRY_INT64(autovacuum_count)
63 :
64 : /* pg_stat_get_blocks_fetched */
65 48 : PG_STAT_GET_RELENTRY_INT64(blocks_fetched)
66 :
67 : /* pg_stat_get_blocks_hit */
68 96 : PG_STAT_GET_RELENTRY_INT64(blocks_hit)
69 :
70 : /* pg_stat_get_dead_tuples */
71 68 : PG_STAT_GET_RELENTRY_INT64(dead_tuples)
72 :
73 : /* pg_stat_get_ins_since_vacuum */
74 0 : PG_STAT_GET_RELENTRY_INT64(ins_since_vacuum)
75 :
76 : /* pg_stat_get_live_tuples */
77 140 : PG_STAT_GET_RELENTRY_INT64(live_tuples)
78 :
79 : /* pg_stat_get_mod_since_analyze */
80 0 : PG_STAT_GET_RELENTRY_INT64(mod_since_analyze)
81 :
82 : /* pg_stat_get_numscans */
83 168 : PG_STAT_GET_RELENTRY_INT64(numscans)
84 :
85 : /* pg_stat_get_tuples_deleted */
86 68 : PG_STAT_GET_RELENTRY_INT64(tuples_deleted)
87 :
88 : /* pg_stat_get_tuples_fetched */
89 48 : PG_STAT_GET_RELENTRY_INT64(tuples_fetched)
90 :
91 : /* pg_stat_get_tuples_hot_updated */
92 14 : PG_STAT_GET_RELENTRY_INT64(tuples_hot_updated)
93 :
94 : /* pg_stat_get_tuples_newpage_updated */
95 0 : PG_STAT_GET_RELENTRY_INT64(tuples_newpage_updated)
96 :
97 : /* pg_stat_get_tuples_inserted */
98 104 : PG_STAT_GET_RELENTRY_INT64(tuples_inserted)
99 :
100 : /* pg_stat_get_tuples_returned */
101 50 : PG_STAT_GET_RELENTRY_INT64(tuples_returned)
102 :
103 : /* pg_stat_get_tuples_updated */
104 80 : PG_STAT_GET_RELENTRY_INT64(tuples_updated)
105 :
106 : /* pg_stat_get_vacuum_count */
107 7934 : PG_STAT_GET_RELENTRY_INT64(vacuum_count)
108 :
109 : #define PG_STAT_GET_RELENTRY_FLOAT8(stat) \
110 : Datum \
111 : CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS) \
112 : { \
113 : Oid relid = PG_GETARG_OID(0); \
114 : double result; \
115 : PgStat_StatTabEntry *tabentry; \
116 : \
117 : if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
118 : result = 0; \
119 : else \
120 : result = (double) (tabentry->stat); \
121 : \
122 : PG_RETURN_FLOAT8(result); \
123 : }
124 :
125 : /* pg_stat_get_total_vacuum_time */
126 0 : PG_STAT_GET_RELENTRY_FLOAT8(total_vacuum_time)
127 :
128 : /* pg_stat_get_total_autovacuum_time */
129 0 : PG_STAT_GET_RELENTRY_FLOAT8(total_autovacuum_time)
130 :
131 : /* pg_stat_get_total_analyze_time */
132 0 : PG_STAT_GET_RELENTRY_FLOAT8(total_analyze_time)
133 :
134 : /* pg_stat_get_total_autoanalyze_time */
135 0 : PG_STAT_GET_RELENTRY_FLOAT8(total_autoanalyze_time)
136 :
137 : #define PG_STAT_GET_RELENTRY_TIMESTAMPTZ(stat) \
138 : Datum \
139 : CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS) \
140 : { \
141 : Oid relid = PG_GETARG_OID(0); \
142 : TimestampTz result; \
143 : PgStat_StatTabEntry *tabentry; \
144 : \
145 : if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
146 : result = 0; \
147 : else \
148 : result = tabentry->stat; \
149 : \
150 : if (result == 0) \
151 : PG_RETURN_NULL(); \
152 : else \
153 : PG_RETURN_TIMESTAMPTZ(result); \
154 : }
155 :
156 : /* pg_stat_get_last_analyze_time */
157 72 : PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_analyze_time)
158 :
159 : /* pg_stat_get_last_autoanalyze_time */
160 0 : PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_autoanalyze_time)
161 :
162 : /* pg_stat_get_last_autovacuum_time */
163 0 : PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_autovacuum_time)
164 :
165 : /* pg_stat_get_last_vacuum_time */
166 72 : PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_vacuum_time)
167 :
168 : /* pg_stat_get_lastscan */
169 84 : PG_STAT_GET_RELENTRY_TIMESTAMPTZ(lastscan)
170 :
171 : Datum
172 278 : pg_stat_get_function_calls(PG_FUNCTION_ARGS)
173 : {
174 278 : Oid funcid = PG_GETARG_OID(0);
175 : PgStat_StatFuncEntry *funcentry;
176 :
177 278 : if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
178 124 : PG_RETURN_NULL();
179 154 : PG_RETURN_INT64(funcentry->numcalls);
180 : }
181 :
182 : /* convert counter from microsec to millisec for display */
183 : #define PG_STAT_GET_FUNCENTRY_FLOAT8_MS(stat) \
184 : Datum \
185 : CppConcat(pg_stat_get_function_,stat)(PG_FUNCTION_ARGS) \
186 : { \
187 : Oid funcid = PG_GETARG_OID(0); \
188 : double result; \
189 : PgStat_StatFuncEntry *funcentry; \
190 : \
191 : if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL) \
192 : PG_RETURN_NULL(); \
193 : result = ((double) funcentry->stat) / 1000.0; \
194 : PG_RETURN_FLOAT8(result); \
195 : }
196 :
197 : /* pg_stat_get_function_total_time */
198 154 : PG_STAT_GET_FUNCENTRY_FLOAT8_MS(total_time)
199 :
200 : /* pg_stat_get_function_self_time */
201 154 : PG_STAT_GET_FUNCENTRY_FLOAT8_MS(self_time)
202 :
203 : Datum
204 102 : pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
205 : {
206 : FuncCallContext *funcctx;
207 : int *fctx;
208 :
209 : /* stuff done only on the first call of the function */
210 102 : if (SRF_IS_FIRSTCALL())
211 : {
212 : /* create a function context for cross-call persistence */
213 6 : funcctx = SRF_FIRSTCALL_INIT();
214 :
215 6 : fctx = MemoryContextAlloc(funcctx->multi_call_memory_ctx,
216 : sizeof(int));
217 6 : funcctx->user_fctx = fctx;
218 :
219 6 : fctx[0] = 0;
220 : }
221 :
222 : /* stuff done on every call of the function */
223 102 : funcctx = SRF_PERCALL_SETUP();
224 102 : fctx = funcctx->user_fctx;
225 :
226 102 : fctx[0] += 1;
227 :
228 : /*
229 : * We recheck pgstat_fetch_stat_numbackends() each time through, just in
230 : * case the local status data has been refreshed since we started. It's
231 : * plenty cheap enough if not. If a refresh does happen, we'll likely
232 : * miss or duplicate some backend IDs, but we're content not to crash.
233 : * (Refreshing midway through such a query would be problematic usage
234 : * anyway, since the backend IDs we've already returned might no longer
235 : * refer to extant sessions.)
236 : */
237 102 : if (fctx[0] <= pgstat_fetch_stat_numbackends())
238 : {
239 : /* do when there is more left to send */
240 96 : LocalPgBackendStatus *local_beentry = pgstat_get_local_beentry_by_index(fctx[0]);
241 :
242 96 : SRF_RETURN_NEXT(funcctx, Int32GetDatum(local_beentry->proc_number));
243 : }
244 : else
245 : {
246 : /* do when there is no more left */
247 6 : SRF_RETURN_DONE(funcctx);
248 : }
249 : }
250 :
251 : /*
252 : * Returns command progress information for the named command.
253 : */
254 : Datum
255 20 : pg_stat_get_progress_info(PG_FUNCTION_ARGS)
256 : {
257 : #define PG_STAT_GET_PROGRESS_COLS PGSTAT_NUM_PROGRESS_PARAM + 3
258 20 : int num_backends = pgstat_fetch_stat_numbackends();
259 : int curr_backend;
260 20 : char *cmd = text_to_cstring(PG_GETARG_TEXT_PP(0));
261 : ProgressCommandType cmdtype;
262 20 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
263 :
264 : /* Translate command name into command type code. */
265 20 : if (pg_strcasecmp(cmd, "VACUUM") == 0)
266 0 : cmdtype = PROGRESS_COMMAND_VACUUM;
267 20 : else if (pg_strcasecmp(cmd, "ANALYZE") == 0)
268 0 : cmdtype = PROGRESS_COMMAND_ANALYZE;
269 20 : else if (pg_strcasecmp(cmd, "CLUSTER") == 0)
270 0 : cmdtype = PROGRESS_COMMAND_CLUSTER;
271 20 : else if (pg_strcasecmp(cmd, "CREATE INDEX") == 0)
272 0 : cmdtype = PROGRESS_COMMAND_CREATE_INDEX;
273 20 : else if (pg_strcasecmp(cmd, "BASEBACKUP") == 0)
274 2 : cmdtype = PROGRESS_COMMAND_BASEBACKUP;
275 18 : else if (pg_strcasecmp(cmd, "COPY") == 0)
276 18 : cmdtype = PROGRESS_COMMAND_COPY;
277 : else
278 0 : ereport(ERROR,
279 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
280 : errmsg("invalid command name: \"%s\"", cmd)));
281 :
282 20 : InitMaterializedSRF(fcinfo, 0);
283 :
284 : /* 1-based index */
285 248 : for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
286 : {
287 : LocalPgBackendStatus *local_beentry;
288 : PgBackendStatus *beentry;
289 228 : Datum values[PG_STAT_GET_PROGRESS_COLS] = {0};
290 228 : bool nulls[PG_STAT_GET_PROGRESS_COLS] = {0};
291 : int i;
292 :
293 228 : local_beentry = pgstat_get_local_beentry_by_index(curr_backend);
294 228 : beentry = &local_beentry->backendStatus;
295 :
296 : /*
297 : * Report values for only those backends which are running the given
298 : * command.
299 : */
300 228 : if (beentry->st_progress_command != cmdtype)
301 204 : continue;
302 :
303 : /* Value available to all callers */
304 24 : values[0] = Int32GetDatum(beentry->st_procpid);
305 24 : values[1] = ObjectIdGetDatum(beentry->st_databaseid);
306 :
307 : /* show rest of the values including relid only to role members */
308 24 : if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
309 : {
310 24 : values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
311 504 : for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
312 480 : values[i + 3] = Int64GetDatum(beentry->st_progress_param[i]);
313 : }
314 : else
315 : {
316 0 : nulls[2] = true;
317 0 : for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
318 0 : nulls[i + 3] = true;
319 : }
320 :
321 24 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
322 : }
323 :
324 20 : return (Datum) 0;
325 : }
326 :
327 : /*
328 : * Returns activity of PG backends.
329 : */
330 : Datum
331 1516 : pg_stat_get_activity(PG_FUNCTION_ARGS)
332 : {
333 : #define PG_STAT_GET_ACTIVITY_COLS 31
334 1516 : int num_backends = pgstat_fetch_stat_numbackends();
335 : int curr_backend;
336 1516 : int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
337 1516 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
338 :
339 1516 : InitMaterializedSRF(fcinfo, 0);
340 :
341 : /* 1-based index */
342 17068 : for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
343 : {
344 : /* for each row */
345 15554 : Datum values[PG_STAT_GET_ACTIVITY_COLS] = {0};
346 15554 : bool nulls[PG_STAT_GET_ACTIVITY_COLS] = {0};
347 : LocalPgBackendStatus *local_beentry;
348 : PgBackendStatus *beentry;
349 : PGPROC *proc;
350 15554 : const char *wait_event_type = NULL;
351 15554 : const char *wait_event = NULL;
352 :
353 : /* Get the next one in the list */
354 15554 : local_beentry = pgstat_get_local_beentry_by_index(curr_backend);
355 15554 : beentry = &local_beentry->backendStatus;
356 :
357 : /* If looking for specific PID, ignore all the others */
358 15554 : if (pid != -1 && beentry->st_procpid != pid)
359 0 : continue;
360 :
361 : /* Values available to all callers */
362 15554 : if (beentry->st_databaseid != InvalidOid)
363 3020 : values[0] = ObjectIdGetDatum(beentry->st_databaseid);
364 : else
365 12534 : nulls[0] = true;
366 :
367 15554 : values[1] = Int32GetDatum(beentry->st_procpid);
368 :
369 15554 : if (beentry->st_userid != InvalidOid)
370 4992 : values[2] = ObjectIdGetDatum(beentry->st_userid);
371 : else
372 10562 : nulls[2] = true;
373 :
374 15554 : if (beentry->st_appname)
375 15554 : values[3] = CStringGetTextDatum(beentry->st_appname);
376 : else
377 0 : nulls[3] = true;
378 :
379 15554 : if (TransactionIdIsValid(local_beentry->backend_xid))
380 108 : values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
381 : else
382 15446 : nulls[15] = true;
383 :
384 15554 : if (TransactionIdIsValid(local_beentry->backend_xmin))
385 1714 : values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
386 : else
387 13840 : nulls[16] = true;
388 :
389 : /* Values only available to role member or pg_read_all_stats */
390 15554 : if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
391 14784 : {
392 : char *clipped_activity;
393 :
394 14784 : switch (beentry->st_state)
395 : {
396 4 : case STATE_STARTING:
397 4 : values[4] = CStringGetTextDatum("starting");
398 4 : break;
399 202 : case STATE_IDLE:
400 202 : values[4] = CStringGetTextDatum("idle");
401 202 : break;
402 3262 : case STATE_RUNNING:
403 3262 : values[4] = CStringGetTextDatum("active");
404 3262 : break;
405 32 : case STATE_IDLEINTRANSACTION:
406 32 : values[4] = CStringGetTextDatum("idle in transaction");
407 32 : break;
408 0 : case STATE_FASTPATH:
409 0 : values[4] = CStringGetTextDatum("fastpath function call");
410 0 : break;
411 0 : case STATE_IDLEINTRANSACTION_ABORTED:
412 0 : values[4] = CStringGetTextDatum("idle in transaction (aborted)");
413 0 : break;
414 6 : case STATE_DISABLED:
415 6 : values[4] = CStringGetTextDatum("disabled");
416 6 : break;
417 11278 : case STATE_UNDEFINED:
418 11278 : nulls[4] = true;
419 11278 : break;
420 : }
421 :
422 14784 : clipped_activity = pgstat_clip_activity(beentry->st_activity_raw);
423 14784 : values[5] = CStringGetTextDatum(clipped_activity);
424 14784 : pfree(clipped_activity);
425 :
426 : /* leader_pid */
427 14784 : nulls[29] = true;
428 :
429 14784 : proc = BackendPidGetProc(beentry->st_procpid);
430 :
431 14784 : if (proc == NULL && (beentry->st_backendType != B_BACKEND))
432 : {
433 : /*
434 : * For an auxiliary process, retrieve process info from
435 : * AuxiliaryProcs stored in shared-memory.
436 : */
437 8600 : proc = AuxiliaryPidGetProc(beentry->st_procpid);
438 : }
439 :
440 : /*
441 : * If a PGPROC entry was retrieved, display wait events and lock
442 : * group leader or apply leader information if any. To avoid
443 : * extra overhead, no extra lock is being held, so there is no
444 : * guarantee of consistency across multiple rows.
445 : */
446 14784 : if (proc != NULL)
447 : {
448 : uint32 raw_wait_event;
449 : PGPROC *leader;
450 :
451 14784 : raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
452 14784 : wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
453 14784 : wait_event = pgstat_get_wait_event(raw_wait_event);
454 :
455 14784 : leader = proc->lockGroupLeader;
456 :
457 : /*
458 : * Show the leader only for active parallel workers. This
459 : * leaves the field as NULL for the leader of a parallel group
460 : * or the leader of parallel apply workers.
461 : */
462 14784 : if (leader && leader->pid != beentry->st_procpid)
463 : {
464 0 : values[29] = Int32GetDatum(leader->pid);
465 0 : nulls[29] = false;
466 : }
467 14784 : else if (beentry->st_backendType == B_BG_WORKER)
468 : {
469 1496 : int leader_pid = GetLeaderApplyWorkerPid(beentry->st_procpid);
470 :
471 1496 : if (leader_pid != InvalidPid)
472 : {
473 0 : values[29] = Int32GetDatum(leader_pid);
474 0 : nulls[29] = false;
475 : }
476 : }
477 : }
478 :
479 14784 : if (wait_event_type)
480 13134 : values[6] = CStringGetTextDatum(wait_event_type);
481 : else
482 1650 : nulls[6] = true;
483 :
484 14784 : if (wait_event)
485 13134 : values[7] = CStringGetTextDatum(wait_event);
486 : else
487 1650 : nulls[7] = true;
488 :
489 : /*
490 : * Don't expose transaction time for walsenders; it confuses
491 : * monitoring, particularly because we don't keep the time up-to-
492 : * date.
493 : */
494 14784 : if (beentry->st_xact_start_timestamp != 0 &&
495 1746 : beentry->st_backendType != B_WAL_SENDER)
496 1736 : values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
497 : else
498 13048 : nulls[8] = true;
499 :
500 14784 : if (beentry->st_activity_start_timestamp != 0)
501 3414 : values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
502 : else
503 11370 : nulls[9] = true;
504 :
505 14784 : if (beentry->st_proc_start_timestamp != 0)
506 14784 : values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
507 : else
508 0 : nulls[10] = true;
509 :
510 14784 : if (beentry->st_state_start_timestamp != 0)
511 3496 : values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
512 : else
513 11288 : nulls[11] = true;
514 :
515 : /* A zeroed client addr means we don't know */
516 14784 : if (pg_memory_is_all_zeros(&beentry->st_clientaddr,
517 : sizeof(beentry->st_clientaddr)))
518 : {
519 11382 : nulls[12] = true;
520 11382 : nulls[13] = true;
521 11382 : nulls[14] = true;
522 : }
523 : else
524 : {
525 3402 : if (beentry->st_clientaddr.addr.ss_family == AF_INET ||
526 3312 : beentry->st_clientaddr.addr.ss_family == AF_INET6)
527 90 : {
528 : char remote_host[NI_MAXHOST];
529 : char remote_port[NI_MAXSERV];
530 : int ret;
531 :
532 90 : remote_host[0] = '\0';
533 90 : remote_port[0] = '\0';
534 90 : ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
535 90 : beentry->st_clientaddr.salen,
536 : remote_host, sizeof(remote_host),
537 : remote_port, sizeof(remote_port),
538 : NI_NUMERICHOST | NI_NUMERICSERV);
539 90 : if (ret == 0)
540 : {
541 90 : clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
542 90 : values[12] = DirectFunctionCall1(inet_in,
543 : CStringGetDatum(remote_host));
544 90 : if (beentry->st_clienthostname &&
545 90 : beentry->st_clienthostname[0])
546 14 : values[13] = CStringGetTextDatum(beentry->st_clienthostname);
547 : else
548 76 : nulls[13] = true;
549 90 : values[14] = Int32GetDatum(atoi(remote_port));
550 : }
551 : else
552 : {
553 0 : nulls[12] = true;
554 0 : nulls[13] = true;
555 0 : nulls[14] = true;
556 : }
557 : }
558 3312 : else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
559 : {
560 : /*
561 : * Unix sockets always reports NULL for host and -1 for
562 : * port, so it's possible to tell the difference to
563 : * connections we have no permissions to view, or with
564 : * errors.
565 : */
566 3312 : nulls[12] = true;
567 3312 : nulls[13] = true;
568 3312 : values[14] = Int32GetDatum(-1);
569 : }
570 : else
571 : {
572 : /* Unknown address type, should never happen */
573 0 : nulls[12] = true;
574 0 : nulls[13] = true;
575 0 : nulls[14] = true;
576 : }
577 : }
578 : /* Add backend type */
579 14784 : if (beentry->st_backendType == B_BG_WORKER)
580 : {
581 : const char *bgw_type;
582 :
583 1496 : bgw_type = GetBackgroundWorkerTypeByPid(beentry->st_procpid);
584 1496 : if (bgw_type)
585 1496 : values[17] = CStringGetTextDatum(bgw_type);
586 : else
587 0 : nulls[17] = true;
588 : }
589 : else
590 13288 : values[17] =
591 13288 : CStringGetTextDatum(GetBackendTypeDesc(beentry->st_backendType));
592 :
593 : /* SSL information */
594 14784 : if (beentry->st_ssl)
595 : {
596 42 : values[18] = BoolGetDatum(true); /* ssl */
597 42 : values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
598 42 : values[20] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
599 42 : values[21] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
600 :
601 42 : if (beentry->st_sslstatus->ssl_client_dn[0])
602 12 : values[22] = CStringGetTextDatum(beentry->st_sslstatus->ssl_client_dn);
603 : else
604 30 : nulls[22] = true;
605 :
606 42 : if (beentry->st_sslstatus->ssl_client_serial[0])
607 12 : values[23] = DirectFunctionCall3(numeric_in,
608 : CStringGetDatum(beentry->st_sslstatus->ssl_client_serial),
609 : ObjectIdGetDatum(InvalidOid),
610 : Int32GetDatum(-1));
611 : else
612 30 : nulls[23] = true;
613 :
614 42 : if (beentry->st_sslstatus->ssl_issuer_dn[0])
615 12 : values[24] = CStringGetTextDatum(beentry->st_sslstatus->ssl_issuer_dn);
616 : else
617 30 : nulls[24] = true;
618 : }
619 : else
620 : {
621 14742 : values[18] = BoolGetDatum(false); /* ssl */
622 14742 : nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = true;
623 : }
624 :
625 : /* GSSAPI information */
626 14784 : if (beentry->st_gss)
627 : {
628 0 : values[25] = BoolGetDatum(beentry->st_gssstatus->gss_auth); /* gss_auth */
629 0 : values[26] = CStringGetTextDatum(beentry->st_gssstatus->gss_princ);
630 0 : values[27] = BoolGetDatum(beentry->st_gssstatus->gss_enc); /* GSS Encryption in use */
631 0 : values[28] = BoolGetDatum(beentry->st_gssstatus->gss_delegation); /* GSS credentials
632 : * delegated */
633 : }
634 : else
635 : {
636 14784 : values[25] = BoolGetDatum(false); /* gss_auth */
637 14784 : nulls[26] = true; /* No GSS principal */
638 14784 : values[27] = BoolGetDatum(false); /* GSS Encryption not in
639 : * use */
640 14784 : values[28] = BoolGetDatum(false); /* GSS credentials not
641 : * delegated */
642 : }
643 14784 : if (beentry->st_query_id == 0)
644 14698 : nulls[30] = true;
645 : else
646 86 : values[30] = UInt64GetDatum(beentry->st_query_id);
647 : }
648 : else
649 : {
650 : /* No permissions to view data about this session */
651 770 : values[5] = CStringGetTextDatum("<insufficient privilege>");
652 770 : nulls[4] = true;
653 770 : nulls[6] = true;
654 770 : nulls[7] = true;
655 770 : nulls[8] = true;
656 770 : nulls[9] = true;
657 770 : nulls[10] = true;
658 770 : nulls[11] = true;
659 770 : nulls[12] = true;
660 770 : nulls[13] = true;
661 770 : nulls[14] = true;
662 770 : nulls[17] = true;
663 770 : nulls[18] = true;
664 770 : nulls[19] = true;
665 770 : nulls[20] = true;
666 770 : nulls[21] = true;
667 770 : nulls[22] = true;
668 770 : nulls[23] = true;
669 770 : nulls[24] = true;
670 770 : nulls[25] = true;
671 770 : nulls[26] = true;
672 770 : nulls[27] = true;
673 770 : nulls[28] = true;
674 770 : nulls[29] = true;
675 770 : nulls[30] = true;
676 : }
677 :
678 15554 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
679 :
680 : /* If only a single backend was requested, and we found it, break. */
681 15554 : if (pid != -1)
682 2 : break;
683 : }
684 :
685 1516 : return (Datum) 0;
686 : }
687 :
688 :
689 : Datum
690 1642 : pg_backend_pid(PG_FUNCTION_ARGS)
691 : {
692 1642 : PG_RETURN_INT32(MyProcPid);
693 : }
694 :
695 :
696 : Datum
697 96 : pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
698 : {
699 96 : int32 procNumber = PG_GETARG_INT32(0);
700 : PgBackendStatus *beentry;
701 :
702 96 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
703 0 : PG_RETURN_NULL();
704 :
705 96 : PG_RETURN_INT32(beentry->st_procpid);
706 : }
707 :
708 :
709 : Datum
710 0 : pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
711 : {
712 0 : int32 procNumber = PG_GETARG_INT32(0);
713 : PgBackendStatus *beentry;
714 :
715 0 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
716 0 : PG_RETURN_NULL();
717 :
718 0 : PG_RETURN_OID(beentry->st_databaseid);
719 : }
720 :
721 :
722 : Datum
723 0 : pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
724 : {
725 0 : int32 procNumber = PG_GETARG_INT32(0);
726 : PgBackendStatus *beentry;
727 :
728 0 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
729 0 : PG_RETURN_NULL();
730 :
731 0 : PG_RETURN_OID(beentry->st_userid);
732 : }
733 :
734 : Datum
735 0 : pg_stat_get_backend_subxact(PG_FUNCTION_ARGS)
736 : {
737 : #define PG_STAT_GET_SUBXACT_COLS 2
738 : TupleDesc tupdesc;
739 0 : Datum values[PG_STAT_GET_SUBXACT_COLS] = {0};
740 0 : bool nulls[PG_STAT_GET_SUBXACT_COLS] = {0};
741 0 : int32 procNumber = PG_GETARG_INT32(0);
742 : LocalPgBackendStatus *local_beentry;
743 :
744 : /* Initialise attributes information in the tuple descriptor */
745 0 : tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_SUBXACT_COLS);
746 0 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "subxact_count",
747 : INT4OID, -1, 0);
748 0 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "subxact_overflow",
749 : BOOLOID, -1, 0);
750 :
751 0 : BlessTupleDesc(tupdesc);
752 :
753 0 : if ((local_beentry = pgstat_get_local_beentry_by_proc_number(procNumber)) != NULL)
754 : {
755 : /* Fill values and NULLs */
756 0 : values[0] = Int32GetDatum(local_beentry->backend_subxact_count);
757 0 : values[1] = BoolGetDatum(local_beentry->backend_subxact_overflowed);
758 : }
759 : else
760 : {
761 0 : nulls[0] = true;
762 0 : nulls[1] = true;
763 : }
764 :
765 : /* Returns the record as Datum */
766 0 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
767 : }
768 :
769 : Datum
770 0 : pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
771 : {
772 0 : int32 procNumber = PG_GETARG_INT32(0);
773 : PgBackendStatus *beentry;
774 : const char *activity;
775 : char *clipped_activity;
776 : text *ret;
777 :
778 0 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
779 0 : activity = "<backend information not available>";
780 0 : else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
781 0 : activity = "<insufficient privilege>";
782 0 : else if (*(beentry->st_activity_raw) == '\0')
783 0 : activity = "<command string not enabled>";
784 : else
785 0 : activity = beentry->st_activity_raw;
786 :
787 0 : clipped_activity = pgstat_clip_activity(activity);
788 0 : ret = cstring_to_text(activity);
789 0 : pfree(clipped_activity);
790 :
791 0 : PG_RETURN_TEXT_P(ret);
792 : }
793 :
794 : Datum
795 0 : pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS)
796 : {
797 0 : int32 procNumber = PG_GETARG_INT32(0);
798 : PgBackendStatus *beentry;
799 : PGPROC *proc;
800 0 : const char *wait_event_type = NULL;
801 :
802 0 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
803 0 : wait_event_type = "<backend information not available>";
804 0 : else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
805 0 : wait_event_type = "<insufficient privilege>";
806 0 : else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
807 0 : wait_event_type = pgstat_get_wait_event_type(proc->wait_event_info);
808 :
809 0 : if (!wait_event_type)
810 0 : PG_RETURN_NULL();
811 :
812 0 : PG_RETURN_TEXT_P(cstring_to_text(wait_event_type));
813 : }
814 :
815 : Datum
816 0 : pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS)
817 : {
818 0 : int32 procNumber = PG_GETARG_INT32(0);
819 : PgBackendStatus *beentry;
820 : PGPROC *proc;
821 0 : const char *wait_event = NULL;
822 :
823 0 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
824 0 : wait_event = "<backend information not available>";
825 0 : else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
826 0 : wait_event = "<insufficient privilege>";
827 0 : else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
828 0 : wait_event = pgstat_get_wait_event(proc->wait_event_info);
829 :
830 0 : if (!wait_event)
831 0 : PG_RETURN_NULL();
832 :
833 0 : PG_RETURN_TEXT_P(cstring_to_text(wait_event));
834 : }
835 :
836 :
837 : Datum
838 0 : pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
839 : {
840 0 : int32 procNumber = PG_GETARG_INT32(0);
841 : TimestampTz result;
842 : PgBackendStatus *beentry;
843 :
844 0 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
845 0 : PG_RETURN_NULL();
846 :
847 0 : else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
848 0 : PG_RETURN_NULL();
849 :
850 0 : result = beentry->st_activity_start_timestamp;
851 :
852 : /*
853 : * No time recorded for start of current query -- this is the case if the
854 : * user hasn't enabled query-level stats collection.
855 : */
856 0 : if (result == 0)
857 0 : PG_RETURN_NULL();
858 :
859 0 : PG_RETURN_TIMESTAMPTZ(result);
860 : }
861 :
862 :
863 : Datum
864 0 : pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)
865 : {
866 0 : int32 procNumber = PG_GETARG_INT32(0);
867 : TimestampTz result;
868 : PgBackendStatus *beentry;
869 :
870 0 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
871 0 : PG_RETURN_NULL();
872 :
873 0 : else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
874 0 : PG_RETURN_NULL();
875 :
876 0 : result = beentry->st_xact_start_timestamp;
877 :
878 0 : if (result == 0) /* not in a transaction */
879 0 : PG_RETURN_NULL();
880 :
881 0 : PG_RETURN_TIMESTAMPTZ(result);
882 : }
883 :
884 :
885 : Datum
886 0 : pg_stat_get_backend_start(PG_FUNCTION_ARGS)
887 : {
888 0 : int32 procNumber = PG_GETARG_INT32(0);
889 : TimestampTz result;
890 : PgBackendStatus *beentry;
891 :
892 0 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
893 0 : PG_RETURN_NULL();
894 :
895 0 : else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
896 0 : PG_RETURN_NULL();
897 :
898 0 : result = beentry->st_proc_start_timestamp;
899 :
900 0 : if (result == 0) /* probably can't happen? */
901 0 : PG_RETURN_NULL();
902 :
903 0 : PG_RETURN_TIMESTAMPTZ(result);
904 : }
905 :
906 :
907 : Datum
908 0 : pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
909 : {
910 0 : int32 procNumber = PG_GETARG_INT32(0);
911 : PgBackendStatus *beentry;
912 : char remote_host[NI_MAXHOST];
913 : int ret;
914 :
915 0 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
916 0 : PG_RETURN_NULL();
917 :
918 0 : else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
919 0 : PG_RETURN_NULL();
920 :
921 : /* A zeroed client addr means we don't know */
922 0 : if (pg_memory_is_all_zeros(&beentry->st_clientaddr,
923 : sizeof(beentry->st_clientaddr)))
924 0 : PG_RETURN_NULL();
925 :
926 0 : switch (beentry->st_clientaddr.addr.ss_family)
927 : {
928 0 : case AF_INET:
929 : case AF_INET6:
930 0 : break;
931 0 : default:
932 0 : PG_RETURN_NULL();
933 : }
934 :
935 0 : remote_host[0] = '\0';
936 0 : ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
937 0 : beentry->st_clientaddr.salen,
938 : remote_host, sizeof(remote_host),
939 : NULL, 0,
940 : NI_NUMERICHOST | NI_NUMERICSERV);
941 0 : if (ret != 0)
942 0 : PG_RETURN_NULL();
943 :
944 0 : clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
945 :
946 0 : PG_RETURN_DATUM(DirectFunctionCall1(inet_in,
947 : CStringGetDatum(remote_host)));
948 : }
949 :
950 : Datum
951 0 : pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
952 : {
953 0 : int32 procNumber = PG_GETARG_INT32(0);
954 : PgBackendStatus *beentry;
955 : char remote_port[NI_MAXSERV];
956 : int ret;
957 :
958 0 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
959 0 : PG_RETURN_NULL();
960 :
961 0 : else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
962 0 : PG_RETURN_NULL();
963 :
964 : /* A zeroed client addr means we don't know */
965 0 : if (pg_memory_is_all_zeros(&beentry->st_clientaddr,
966 : sizeof(beentry->st_clientaddr)))
967 0 : PG_RETURN_NULL();
968 :
969 0 : switch (beentry->st_clientaddr.addr.ss_family)
970 : {
971 0 : case AF_INET:
972 : case AF_INET6:
973 0 : break;
974 0 : case AF_UNIX:
975 0 : PG_RETURN_INT32(-1);
976 0 : default:
977 0 : PG_RETURN_NULL();
978 : }
979 :
980 0 : remote_port[0] = '\0';
981 0 : ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
982 0 : beentry->st_clientaddr.salen,
983 : NULL, 0,
984 : remote_port, sizeof(remote_port),
985 : NI_NUMERICHOST | NI_NUMERICSERV);
986 0 : if (ret != 0)
987 0 : PG_RETURN_NULL();
988 :
989 0 : PG_RETURN_DATUM(DirectFunctionCall1(int4in,
990 : CStringGetDatum(remote_port)));
991 : }
992 :
993 :
994 : Datum
995 0 : pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
996 : {
997 0 : Oid dbid = PG_GETARG_OID(0);
998 : int32 result;
999 0 : int tot_backends = pgstat_fetch_stat_numbackends();
1000 : int idx;
1001 :
1002 0 : result = 0;
1003 0 : for (idx = 1; idx <= tot_backends; idx++)
1004 : {
1005 0 : LocalPgBackendStatus *local_beentry = pgstat_get_local_beentry_by_index(idx);
1006 :
1007 0 : if (local_beentry->backendStatus.st_databaseid == dbid)
1008 0 : result++;
1009 : }
1010 :
1011 0 : PG_RETURN_INT32(result);
1012 : }
1013 :
1014 :
1015 : #define PG_STAT_GET_DBENTRY_INT64(stat) \
1016 : Datum \
1017 : CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS) \
1018 : { \
1019 : Oid dbid = PG_GETARG_OID(0); \
1020 : int64 result; \
1021 : PgStat_StatDBEntry *dbentry; \
1022 : \
1023 : if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) \
1024 : result = 0; \
1025 : else \
1026 : result = (int64) (dbentry->stat); \
1027 : \
1028 : PG_RETURN_INT64(result); \
1029 : }
1030 :
1031 : /* pg_stat_get_db_blocks_fetched */
1032 0 : PG_STAT_GET_DBENTRY_INT64(blocks_fetched)
1033 :
1034 : /* pg_stat_get_db_blocks_hit */
1035 0 : PG_STAT_GET_DBENTRY_INT64(blocks_hit)
1036 :
1037 : /* pg_stat_get_db_conflict_bufferpin */
1038 2 : PG_STAT_GET_DBENTRY_INT64(conflict_bufferpin)
1039 :
1040 : /* pg_stat_get_db_conflict_lock */
1041 2 : PG_STAT_GET_DBENTRY_INT64(conflict_lock)
1042 :
1043 : /* pg_stat_get_db_conflict_snapshot */
1044 2 : PG_STAT_GET_DBENTRY_INT64(conflict_snapshot)
1045 :
1046 : /* pg_stat_get_db_conflict_startup_deadlock */
1047 2 : PG_STAT_GET_DBENTRY_INT64(conflict_startup_deadlock)
1048 :
1049 : /* pg_stat_get_db_conflict_tablespace */
1050 2 : PG_STAT_GET_DBENTRY_INT64(conflict_tablespace)
1051 :
1052 : /* pg_stat_get_db_deadlocks */
1053 2 : PG_STAT_GET_DBENTRY_INT64(deadlocks)
1054 :
1055 : /* pg_stat_get_db_sessions */
1056 12 : PG_STAT_GET_DBENTRY_INT64(sessions)
1057 :
1058 : /* pg_stat_get_db_sessions_abandoned */
1059 0 : PG_STAT_GET_DBENTRY_INT64(sessions_abandoned)
1060 :
1061 : /* pg_stat_get_db_sessions_fatal */
1062 0 : PG_STAT_GET_DBENTRY_INT64(sessions_fatal)
1063 :
1064 : /* pg_stat_get_db_sessions_killed */
1065 0 : PG_STAT_GET_DBENTRY_INT64(sessions_killed)
1066 :
1067 : /* pg_stat_get_db_parallel_workers_to_launch */
1068 12 : PG_STAT_GET_DBENTRY_INT64(parallel_workers_to_launch)
1069 :
1070 : /* pg_stat_get_db_parallel_workers_launched */
1071 12 : PG_STAT_GET_DBENTRY_INT64(parallel_workers_launched)
1072 :
1073 : /* pg_stat_get_db_temp_bytes */
1074 0 : PG_STAT_GET_DBENTRY_INT64(temp_bytes)
1075 :
1076 : /* pg_stat_get_db_temp_files */
1077 0 : PG_STAT_GET_DBENTRY_INT64(temp_files)
1078 :
1079 : /* pg_stat_get_db_tuples_deleted */
1080 0 : PG_STAT_GET_DBENTRY_INT64(tuples_deleted)
1081 :
1082 : /* pg_stat_get_db_tuples_fetched */
1083 0 : PG_STAT_GET_DBENTRY_INT64(tuples_fetched)
1084 :
1085 : /* pg_stat_get_db_tuples_inserted */
1086 0 : PG_STAT_GET_DBENTRY_INT64(tuples_inserted)
1087 :
1088 : /* pg_stat_get_db_tuples_returned */
1089 0 : PG_STAT_GET_DBENTRY_INT64(tuples_returned)
1090 :
1091 : /* pg_stat_get_db_tuples_updated */
1092 0 : PG_STAT_GET_DBENTRY_INT64(tuples_updated)
1093 :
1094 : /* pg_stat_get_db_xact_commit */
1095 0 : PG_STAT_GET_DBENTRY_INT64(xact_commit)
1096 :
1097 : /* pg_stat_get_db_xact_rollback */
1098 0 : PG_STAT_GET_DBENTRY_INT64(xact_rollback)
1099 :
1100 : /* pg_stat_get_db_conflict_logicalslot */
1101 12 : PG_STAT_GET_DBENTRY_INT64(conflict_logicalslot)
1102 :
1103 : Datum
1104 12 : pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)
1105 : {
1106 12 : Oid dbid = PG_GETARG_OID(0);
1107 : TimestampTz result;
1108 : PgStat_StatDBEntry *dbentry;
1109 :
1110 12 : if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1111 0 : result = 0;
1112 : else
1113 12 : result = dbentry->stat_reset_timestamp;
1114 :
1115 12 : if (result == 0)
1116 0 : PG_RETURN_NULL();
1117 : else
1118 12 : PG_RETURN_TIMESTAMPTZ(result);
1119 : }
1120 :
1121 :
1122 : Datum
1123 2 : pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS)
1124 : {
1125 2 : Oid dbid = PG_GETARG_OID(0);
1126 : int64 result;
1127 : PgStat_StatDBEntry *dbentry;
1128 :
1129 2 : if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1130 0 : result = 0;
1131 : else
1132 2 : result = (int64) (dbentry->conflict_tablespace +
1133 2 : dbentry->conflict_lock +
1134 2 : dbentry->conflict_snapshot +
1135 2 : dbentry->conflict_logicalslot +
1136 2 : dbentry->conflict_bufferpin +
1137 2 : dbentry->conflict_startup_deadlock);
1138 :
1139 2 : PG_RETURN_INT64(result);
1140 : }
1141 :
1142 : Datum
1143 0 : pg_stat_get_db_checksum_failures(PG_FUNCTION_ARGS)
1144 : {
1145 0 : Oid dbid = PG_GETARG_OID(0);
1146 : int64 result;
1147 : PgStat_StatDBEntry *dbentry;
1148 :
1149 0 : if (!DataChecksumsEnabled())
1150 0 : PG_RETURN_NULL();
1151 :
1152 0 : if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1153 0 : result = 0;
1154 : else
1155 0 : result = (int64) (dbentry->checksum_failures);
1156 :
1157 0 : PG_RETURN_INT64(result);
1158 : }
1159 :
1160 : Datum
1161 0 : pg_stat_get_db_checksum_last_failure(PG_FUNCTION_ARGS)
1162 : {
1163 0 : Oid dbid = PG_GETARG_OID(0);
1164 : TimestampTz result;
1165 : PgStat_StatDBEntry *dbentry;
1166 :
1167 0 : if (!DataChecksumsEnabled())
1168 0 : PG_RETURN_NULL();
1169 :
1170 0 : if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1171 0 : result = 0;
1172 : else
1173 0 : result = dbentry->last_checksum_failure;
1174 :
1175 0 : if (result == 0)
1176 0 : PG_RETURN_NULL();
1177 : else
1178 0 : PG_RETURN_TIMESTAMPTZ(result);
1179 : }
1180 :
1181 : /* convert counter from microsec to millisec for display */
1182 : #define PG_STAT_GET_DBENTRY_FLOAT8_MS(stat) \
1183 : Datum \
1184 : CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS) \
1185 : { \
1186 : Oid dbid = PG_GETARG_OID(0); \
1187 : double result; \
1188 : PgStat_StatDBEntry *dbentry; \
1189 : \
1190 : if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) \
1191 : result = 0; \
1192 : else \
1193 : result = ((double) dbentry->stat) / 1000.0; \
1194 : \
1195 : PG_RETURN_FLOAT8(result); \
1196 : }
1197 :
1198 : /* pg_stat_get_db_active_time */
1199 0 : PG_STAT_GET_DBENTRY_FLOAT8_MS(active_time)
1200 :
1201 : /* pg_stat_get_db_blk_read_time */
1202 0 : PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_read_time)
1203 :
1204 : /* pg_stat_get_db_blk_write_time */
1205 0 : PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_write_time)
1206 :
1207 : /* pg_stat_get_db_idle_in_transaction_time */
1208 0 : PG_STAT_GET_DBENTRY_FLOAT8_MS(idle_in_transaction_time)
1209 :
1210 : /* pg_stat_get_db_session_time */
1211 0 : PG_STAT_GET_DBENTRY_FLOAT8_MS(session_time)
1212 :
1213 : Datum
1214 8 : pg_stat_get_checkpointer_num_timed(PG_FUNCTION_ARGS)
1215 : {
1216 8 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_timed);
1217 : }
1218 :
1219 : Datum
1220 20 : pg_stat_get_checkpointer_num_requested(PG_FUNCTION_ARGS)
1221 : {
1222 20 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_requested);
1223 : }
1224 :
1225 : Datum
1226 0 : pg_stat_get_checkpointer_num_performed(PG_FUNCTION_ARGS)
1227 : {
1228 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_performed);
1229 : }
1230 :
1231 : Datum
1232 0 : pg_stat_get_checkpointer_restartpoints_timed(PG_FUNCTION_ARGS)
1233 : {
1234 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_timed);
1235 : }
1236 :
1237 : Datum
1238 0 : pg_stat_get_checkpointer_restartpoints_requested(PG_FUNCTION_ARGS)
1239 : {
1240 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_requested);
1241 : }
1242 :
1243 : Datum
1244 0 : pg_stat_get_checkpointer_restartpoints_performed(PG_FUNCTION_ARGS)
1245 : {
1246 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_performed);
1247 : }
1248 :
1249 : Datum
1250 0 : pg_stat_get_checkpointer_buffers_written(PG_FUNCTION_ARGS)
1251 : {
1252 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buffers_written);
1253 : }
1254 :
1255 : Datum
1256 0 : pg_stat_get_checkpointer_slru_written(PG_FUNCTION_ARGS)
1257 : {
1258 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->slru_written);
1259 : }
1260 :
1261 : Datum
1262 0 : pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)
1263 : {
1264 0 : PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->buf_written_clean);
1265 : }
1266 :
1267 : Datum
1268 0 : pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
1269 : {
1270 0 : PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->maxwritten_clean);
1271 : }
1272 :
1273 : Datum
1274 0 : pg_stat_get_checkpointer_write_time(PG_FUNCTION_ARGS)
1275 : {
1276 : /* time is already in msec, just convert to double for presentation */
1277 0 : PG_RETURN_FLOAT8((double)
1278 : pgstat_fetch_stat_checkpointer()->write_time);
1279 : }
1280 :
1281 : Datum
1282 0 : pg_stat_get_checkpointer_sync_time(PG_FUNCTION_ARGS)
1283 : {
1284 : /* time is already in msec, just convert to double for presentation */
1285 0 : PG_RETURN_FLOAT8((double)
1286 : pgstat_fetch_stat_checkpointer()->sync_time);
1287 : }
1288 :
1289 : Datum
1290 20 : pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
1291 : {
1292 20 : PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
1293 : }
1294 :
1295 : Datum
1296 12 : pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
1297 : {
1298 12 : PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_bgwriter()->stat_reset_timestamp);
1299 : }
1300 :
1301 : Datum
1302 0 : pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
1303 : {
1304 0 : PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->buf_alloc);
1305 : }
1306 :
1307 : /*
1308 : * When adding a new column to the pg_stat_io view and the
1309 : * pg_stat_get_backend_io() function, add a new enum value here above
1310 : * IO_NUM_COLUMNS.
1311 : */
1312 : typedef enum io_stat_col
1313 : {
1314 : IO_COL_INVALID = -1,
1315 : IO_COL_BACKEND_TYPE,
1316 : IO_COL_OBJECT,
1317 : IO_COL_CONTEXT,
1318 : IO_COL_READS,
1319 : IO_COL_READ_BYTES,
1320 : IO_COL_READ_TIME,
1321 : IO_COL_WRITES,
1322 : IO_COL_WRITE_BYTES,
1323 : IO_COL_WRITE_TIME,
1324 : IO_COL_WRITEBACKS,
1325 : IO_COL_WRITEBACK_TIME,
1326 : IO_COL_EXTENDS,
1327 : IO_COL_EXTEND_BYTES,
1328 : IO_COL_EXTEND_TIME,
1329 : IO_COL_HITS,
1330 : IO_COL_EVICTIONS,
1331 : IO_COL_REUSES,
1332 : IO_COL_FSYNCS,
1333 : IO_COL_FSYNC_TIME,
1334 : IO_COL_RESET_TIME,
1335 : IO_NUM_COLUMNS,
1336 : } io_stat_col;
1337 :
1338 : /*
1339 : * When adding a new IOOp, add a new io_stat_col and add a case to this
1340 : * function returning the corresponding io_stat_col.
1341 : */
1342 : static io_stat_col
1343 92432 : pgstat_get_io_op_index(IOOp io_op)
1344 : {
1345 92432 : switch (io_op)
1346 : {
1347 11554 : case IOOP_EVICT:
1348 11554 : return IO_COL_EVICTIONS;
1349 11554 : case IOOP_EXTEND:
1350 11554 : return IO_COL_EXTENDS;
1351 11554 : case IOOP_FSYNC:
1352 11554 : return IO_COL_FSYNCS;
1353 11554 : case IOOP_HIT:
1354 11554 : return IO_COL_HITS;
1355 11554 : case IOOP_READ:
1356 11554 : return IO_COL_READS;
1357 11554 : case IOOP_REUSE:
1358 11554 : return IO_COL_REUSES;
1359 11554 : case IOOP_WRITE:
1360 11554 : return IO_COL_WRITES;
1361 11554 : case IOOP_WRITEBACK:
1362 11554 : return IO_COL_WRITEBACKS;
1363 : }
1364 :
1365 0 : elog(ERROR, "unrecognized IOOp value: %d", io_op);
1366 : pg_unreachable();
1367 : }
1368 :
1369 : /*
1370 : * Get the number of the column containing IO bytes for the specified IOOp.
1371 : * If an IOOp is not tracked in bytes, IO_COL_INVALID is returned.
1372 : */
1373 : static io_stat_col
1374 92432 : pgstat_get_io_byte_index(IOOp io_op)
1375 : {
1376 92432 : switch (io_op)
1377 : {
1378 11554 : case IOOP_EXTEND:
1379 11554 : return IO_COL_EXTEND_BYTES;
1380 11554 : case IOOP_READ:
1381 11554 : return IO_COL_READ_BYTES;
1382 11554 : case IOOP_WRITE:
1383 11554 : return IO_COL_WRITE_BYTES;
1384 57770 : case IOOP_EVICT:
1385 : case IOOP_FSYNC:
1386 : case IOOP_HIT:
1387 : case IOOP_REUSE:
1388 : case IOOP_WRITEBACK:
1389 57770 : return IO_COL_INVALID;
1390 : }
1391 :
1392 0 : elog(ERROR, "unrecognized IOOp value: %d", io_op);
1393 : pg_unreachable();
1394 : }
1395 :
1396 : /*
1397 : * Get the number of the column containing IO times for the specified IOOp.
1398 : * If an op has no associated time, IO_COL_INVALID is returned.
1399 : */
1400 : static io_stat_col
1401 92432 : pgstat_get_io_time_index(IOOp io_op)
1402 : {
1403 92432 : switch (io_op)
1404 : {
1405 11554 : case IOOP_READ:
1406 11554 : return IO_COL_READ_TIME;
1407 11554 : case IOOP_WRITE:
1408 11554 : return IO_COL_WRITE_TIME;
1409 11554 : case IOOP_WRITEBACK:
1410 11554 : return IO_COL_WRITEBACK_TIME;
1411 11554 : case IOOP_EXTEND:
1412 11554 : return IO_COL_EXTEND_TIME;
1413 11554 : case IOOP_FSYNC:
1414 11554 : return IO_COL_FSYNC_TIME;
1415 34662 : case IOOP_EVICT:
1416 : case IOOP_HIT:
1417 : case IOOP_REUSE:
1418 34662 : return IO_COL_INVALID;
1419 : }
1420 :
1421 0 : elog(ERROR, "unrecognized IOOp value: %d", io_op);
1422 : pg_unreachable();
1423 : }
1424 :
1425 : static inline double
1426 39132 : pg_stat_us_to_ms(PgStat_Counter val_ms)
1427 : {
1428 39132 : return val_ms * (double) 0.001;
1429 : }
1430 :
1431 : /*
1432 : * pg_stat_io_build_tuples
1433 : *
1434 : * Helper routine for pg_stat_get_io() and pg_stat_get_backend_io()
1435 : * filling a result tuplestore with one tuple for each object and each
1436 : * context supported by the caller, based on the contents of bktype_stats.
1437 : */
1438 : static void
1439 2030 : pg_stat_io_build_tuples(ReturnSetInfo *rsinfo,
1440 : PgStat_BktypeIO *bktype_stats,
1441 : BackendType bktype,
1442 : TimestampTz stat_reset_timestamp)
1443 : {
1444 2030 : Datum bktype_desc = CStringGetTextDatum(GetBackendTypeDesc(bktype));
1445 :
1446 8120 : for (int io_obj = 0; io_obj < IOOBJECT_NUM_TYPES; io_obj++)
1447 : {
1448 6090 : const char *obj_name = pgstat_get_io_object_name(io_obj);
1449 :
1450 36540 : for (int io_context = 0; io_context < IOCONTEXT_NUM_TYPES; io_context++)
1451 : {
1452 30450 : const char *context_name = pgstat_get_io_context_name(io_context);
1453 :
1454 30450 : Datum values[IO_NUM_COLUMNS] = {0};
1455 30450 : bool nulls[IO_NUM_COLUMNS] = {0};
1456 :
1457 : /*
1458 : * Some combinations of BackendType, IOObject, and IOContext are
1459 : * not valid for any type of IOOp. In such cases, omit the entire
1460 : * row from the view.
1461 : */
1462 30450 : if (!pgstat_tracks_io_object(bktype, io_obj, io_context))
1463 18896 : continue;
1464 :
1465 11554 : values[IO_COL_BACKEND_TYPE] = bktype_desc;
1466 11554 : values[IO_COL_CONTEXT] = CStringGetTextDatum(context_name);
1467 11554 : values[IO_COL_OBJECT] = CStringGetTextDatum(obj_name);
1468 11554 : if (stat_reset_timestamp != 0)
1469 11266 : values[IO_COL_RESET_TIME] = TimestampTzGetDatum(stat_reset_timestamp);
1470 : else
1471 288 : nulls[IO_COL_RESET_TIME] = true;
1472 :
1473 103986 : for (int io_op = 0; io_op < IOOP_NUM_TYPES; io_op++)
1474 : {
1475 92432 : int op_idx = pgstat_get_io_op_index(io_op);
1476 92432 : int time_idx = pgstat_get_io_time_index(io_op);
1477 92432 : int byte_idx = pgstat_get_io_byte_index(io_op);
1478 :
1479 : /*
1480 : * Some combinations of BackendType and IOOp, of IOContext and
1481 : * IOOp, and of IOObject and IOOp are not tracked. Set these
1482 : * cells in the view NULL.
1483 : */
1484 92432 : if (pgstat_tracks_io_op(bktype, io_obj, io_context, io_op))
1485 : {
1486 56518 : PgStat_Counter count =
1487 : bktype_stats->counts[io_obj][io_context][io_op];
1488 :
1489 56518 : values[op_idx] = Int64GetDatum(count);
1490 : }
1491 : else
1492 35914 : nulls[op_idx] = true;
1493 :
1494 92432 : if (!nulls[op_idx])
1495 : {
1496 : /* not every operation is timed */
1497 56518 : if (time_idx != IO_COL_INVALID)
1498 : {
1499 39132 : PgStat_Counter time =
1500 : bktype_stats->times[io_obj][io_context][io_op];
1501 :
1502 39132 : values[time_idx] = Float8GetDatum(pg_stat_us_to_ms(time));
1503 : }
1504 :
1505 : /* not every IO is tracked in bytes */
1506 56518 : if (byte_idx != IO_COL_INVALID)
1507 : {
1508 : char buf[256];
1509 25122 : PgStat_Counter byte =
1510 25122 : bktype_stats->bytes[io_obj][io_context][io_op];
1511 :
1512 : /* Convert to numeric */
1513 25122 : snprintf(buf, sizeof buf, UINT64_FORMAT, byte);
1514 25122 : values[byte_idx] = DirectFunctionCall3(numeric_in,
1515 : CStringGetDatum(buf),
1516 : ObjectIdGetDatum(0),
1517 : Int32GetDatum(-1));
1518 : }
1519 : }
1520 : else
1521 : {
1522 35914 : if (time_idx != IO_COL_INVALID)
1523 18638 : nulls[time_idx] = true;
1524 35914 : if (byte_idx != IO_COL_INVALID)
1525 9540 : nulls[byte_idx] = true;
1526 : }
1527 : }
1528 :
1529 11554 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1530 : values, nulls);
1531 : }
1532 : }
1533 2030 : }
1534 :
1535 : Datum
1536 142 : pg_stat_get_io(PG_FUNCTION_ARGS)
1537 : {
1538 : ReturnSetInfo *rsinfo;
1539 : PgStat_IO *backends_io_stats;
1540 :
1541 142 : InitMaterializedSRF(fcinfo, 0);
1542 142 : rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1543 :
1544 142 : backends_io_stats = pgstat_fetch_stat_io();
1545 :
1546 2698 : for (int bktype = 0; bktype < BACKEND_NUM_TYPES; bktype++)
1547 : {
1548 2556 : PgStat_BktypeIO *bktype_stats = &backends_io_stats->stats[bktype];
1549 :
1550 : /*
1551 : * In Assert builds, we can afford an extra loop through all of the
1552 : * counters (in pg_stat_io_build_tuples()), checking that only
1553 : * expected stats are non-zero, since it keeps the non-Assert code
1554 : * cleaner.
1555 : */
1556 : Assert(pgstat_bktype_io_stats_valid(bktype_stats, bktype));
1557 :
1558 : /*
1559 : * For those BackendTypes without IO Operation stats, skip
1560 : * representing them in the view altogether.
1561 : */
1562 2556 : if (!pgstat_tracks_io_bktype(bktype))
1563 568 : continue;
1564 :
1565 : /* save tuples with data from this PgStat_BktypeIO */
1566 1988 : pg_stat_io_build_tuples(rsinfo, bktype_stats, bktype,
1567 : backends_io_stats->stat_reset_timestamp);
1568 : }
1569 :
1570 142 : return (Datum) 0;
1571 : }
1572 :
1573 : /*
1574 : * Returns I/O statistics for a backend with given PID.
1575 : */
1576 : Datum
1577 54 : pg_stat_get_backend_io(PG_FUNCTION_ARGS)
1578 : {
1579 : ReturnSetInfo *rsinfo;
1580 : BackendType bktype;
1581 : int pid;
1582 : PgStat_Backend *backend_stats;
1583 : PgStat_BktypeIO *bktype_stats;
1584 :
1585 54 : InitMaterializedSRF(fcinfo, 0);
1586 54 : rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1587 :
1588 54 : pid = PG_GETARG_INT32(0);
1589 54 : backend_stats = pgstat_fetch_stat_backend_by_pid(pid, &bktype);
1590 :
1591 54 : if (!backend_stats)
1592 12 : return (Datum) 0;
1593 :
1594 42 : bktype_stats = &backend_stats->io_stats;
1595 :
1596 : /*
1597 : * In Assert builds, we can afford an extra loop through all of the
1598 : * counters (in pg_stat_io_build_tuples()), checking that only expected
1599 : * stats are non-zero, since it keeps the non-Assert code cleaner.
1600 : */
1601 : Assert(pgstat_bktype_io_stats_valid(bktype_stats, bktype));
1602 :
1603 : /* save tuples with data from this PgStat_BktypeIO */
1604 42 : pg_stat_io_build_tuples(rsinfo, bktype_stats, bktype,
1605 : backend_stats->stat_reset_timestamp);
1606 42 : return (Datum) 0;
1607 : }
1608 :
1609 : /*
1610 : * pg_stat_wal_build_tuple
1611 : *
1612 : * Helper routine for pg_stat_get_wal() and pg_stat_get_backend_wal()
1613 : * returning one tuple based on the contents of wal_counters.
1614 : */
1615 : static Datum
1616 84 : pg_stat_wal_build_tuple(PgStat_WalCounters wal_counters,
1617 : TimestampTz stat_reset_timestamp)
1618 : {
1619 : #define PG_STAT_WAL_COLS 5
1620 : TupleDesc tupdesc;
1621 84 : Datum values[PG_STAT_WAL_COLS] = {0};
1622 84 : bool nulls[PG_STAT_WAL_COLS] = {0};
1623 : char buf[256];
1624 :
1625 : /* Initialise attributes information in the tuple descriptor */
1626 84 : tupdesc = CreateTemplateTupleDesc(PG_STAT_WAL_COLS);
1627 84 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "wal_records",
1628 : INT8OID, -1, 0);
1629 84 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "wal_fpi",
1630 : INT8OID, -1, 0);
1631 84 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "wal_bytes",
1632 : NUMERICOID, -1, 0);
1633 84 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_buffers_full",
1634 : INT8OID, -1, 0);
1635 84 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "stats_reset",
1636 : TIMESTAMPTZOID, -1, 0);
1637 :
1638 84 : BlessTupleDesc(tupdesc);
1639 :
1640 : /* Fill values and NULLs */
1641 84 : values[0] = Int64GetDatum(wal_counters.wal_records);
1642 84 : values[1] = Int64GetDatum(wal_counters.wal_fpi);
1643 :
1644 : /* Convert to numeric. */
1645 84 : snprintf(buf, sizeof buf, UINT64_FORMAT, wal_counters.wal_bytes);
1646 84 : values[2] = DirectFunctionCall3(numeric_in,
1647 : CStringGetDatum(buf),
1648 : ObjectIdGetDatum(0),
1649 : Int32GetDatum(-1));
1650 :
1651 84 : values[3] = Int64GetDatum(wal_counters.wal_buffers_full);
1652 :
1653 84 : if (stat_reset_timestamp != 0)
1654 72 : values[4] = TimestampTzGetDatum(stat_reset_timestamp);
1655 : else
1656 12 : nulls[4] = true;
1657 :
1658 : /* Returns the record as Datum */
1659 84 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
1660 : }
1661 :
1662 : /*
1663 : * Returns WAL statistics for a backend with given PID.
1664 : */
1665 : Datum
1666 12 : pg_stat_get_backend_wal(PG_FUNCTION_ARGS)
1667 : {
1668 : int pid;
1669 : PgStat_Backend *backend_stats;
1670 : PgStat_WalCounters bktype_stats;
1671 :
1672 12 : pid = PG_GETARG_INT32(0);
1673 12 : backend_stats = pgstat_fetch_stat_backend_by_pid(pid, NULL);
1674 :
1675 12 : if (!backend_stats)
1676 0 : PG_RETURN_NULL();
1677 :
1678 12 : bktype_stats = backend_stats->wal_counters;
1679 :
1680 : /* save tuples with data from this PgStat_WalCounters */
1681 12 : return (pg_stat_wal_build_tuple(bktype_stats, backend_stats->stat_reset_timestamp));
1682 : }
1683 :
1684 : /*
1685 : * Returns statistics of WAL activity
1686 : */
1687 : Datum
1688 72 : pg_stat_get_wal(PG_FUNCTION_ARGS)
1689 : {
1690 : PgStat_WalStats *wal_stats;
1691 :
1692 : /* Get statistics about WAL activity */
1693 72 : wal_stats = pgstat_fetch_stat_wal();
1694 :
1695 72 : return (pg_stat_wal_build_tuple(wal_stats->wal_counters,
1696 : wal_stats->stat_reset_timestamp));
1697 : }
1698 :
1699 : /*
1700 : * Returns statistics of SLRU caches.
1701 : */
1702 : Datum
1703 124 : pg_stat_get_slru(PG_FUNCTION_ARGS)
1704 : {
1705 : #define PG_STAT_GET_SLRU_COLS 9
1706 124 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1707 : int i;
1708 : PgStat_SLRUStats *stats;
1709 :
1710 124 : InitMaterializedSRF(fcinfo, 0);
1711 :
1712 : /* request SLRU stats from the cumulative stats system */
1713 124 : stats = pgstat_fetch_slru();
1714 :
1715 124 : for (i = 0;; i++)
1716 992 : {
1717 : /* for each row */
1718 1116 : Datum values[PG_STAT_GET_SLRU_COLS] = {0};
1719 1116 : bool nulls[PG_STAT_GET_SLRU_COLS] = {0};
1720 : PgStat_SLRUStats stat;
1721 : const char *name;
1722 :
1723 1116 : name = pgstat_get_slru_name(i);
1724 :
1725 1116 : if (!name)
1726 124 : break;
1727 :
1728 992 : stat = stats[i];
1729 :
1730 992 : values[0] = PointerGetDatum(cstring_to_text(name));
1731 992 : values[1] = Int64GetDatum(stat.blocks_zeroed);
1732 992 : values[2] = Int64GetDatum(stat.blocks_hit);
1733 992 : values[3] = Int64GetDatum(stat.blocks_read);
1734 992 : values[4] = Int64GetDatum(stat.blocks_written);
1735 992 : values[5] = Int64GetDatum(stat.blocks_exists);
1736 992 : values[6] = Int64GetDatum(stat.flush);
1737 992 : values[7] = Int64GetDatum(stat.truncate);
1738 992 : values[8] = TimestampTzGetDatum(stat.stat_reset_timestamp);
1739 :
1740 992 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1741 : }
1742 :
1743 124 : return (Datum) 0;
1744 : }
1745 :
1746 : #define PG_STAT_GET_XACT_RELENTRY_INT64(stat) \
1747 : Datum \
1748 : CppConcat(pg_stat_get_xact_,stat)(PG_FUNCTION_ARGS) \
1749 : { \
1750 : Oid relid = PG_GETARG_OID(0); \
1751 : int64 result; \
1752 : PgStat_TableStatus *tabentry; \
1753 : \
1754 : if ((tabentry = find_tabstat_entry(relid)) == NULL) \
1755 : result = 0; \
1756 : else \
1757 : result = (int64) (tabentry->counts.stat); \
1758 : \
1759 : PG_RETURN_INT64(result); \
1760 : }
1761 :
1762 : /* pg_stat_get_xact_numscans */
1763 0 : PG_STAT_GET_XACT_RELENTRY_INT64(numscans)
1764 :
1765 : /* pg_stat_get_xact_tuples_returned */
1766 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_returned)
1767 :
1768 : /* pg_stat_get_xact_tuples_fetched */
1769 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_fetched)
1770 :
1771 : /* pg_stat_get_xact_tuples_hot_updated */
1772 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_hot_updated)
1773 :
1774 : /* pg_stat_get_xact_tuples_newpage_updated */
1775 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_newpage_updated)
1776 :
1777 : /* pg_stat_get_xact_blocks_fetched */
1778 0 : PG_STAT_GET_XACT_RELENTRY_INT64(blocks_fetched)
1779 :
1780 : /* pg_stat_get_xact_blocks_hit */
1781 0 : PG_STAT_GET_XACT_RELENTRY_INT64(blocks_hit)
1782 :
1783 : /* pg_stat_get_xact_tuples_inserted */
1784 48 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_inserted)
1785 :
1786 : /* pg_stat_get_xact_tuples_updated */
1787 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_updated)
1788 :
1789 : /* pg_stat_get_xact_tuples_deleted */
1790 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_deleted)
1791 :
1792 : Datum
1793 24 : pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
1794 : {
1795 24 : Oid funcid = PG_GETARG_OID(0);
1796 : PgStat_FunctionCounts *funcentry;
1797 :
1798 24 : if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1799 6 : PG_RETURN_NULL();
1800 18 : PG_RETURN_INT64(funcentry->numcalls);
1801 : }
1802 :
1803 : #define PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(stat) \
1804 : Datum \
1805 : CppConcat(pg_stat_get_xact_function_,stat)(PG_FUNCTION_ARGS) \
1806 : { \
1807 : Oid funcid = PG_GETARG_OID(0); \
1808 : PgStat_FunctionCounts *funcentry; \
1809 : \
1810 : if ((funcentry = find_funcstat_entry(funcid)) == NULL) \
1811 : PG_RETURN_NULL(); \
1812 : PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->stat)); \
1813 : }
1814 :
1815 : /* pg_stat_get_xact_function_total_time */
1816 0 : PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(total_time)
1817 :
1818 : /* pg_stat_get_xact_function_self_time */
1819 0 : PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(self_time)
1820 :
1821 : /* Get the timestamp of the current statistics snapshot */
1822 : Datum
1823 60 : pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS)
1824 : {
1825 : bool have_snapshot;
1826 : TimestampTz ts;
1827 :
1828 60 : ts = pgstat_get_stat_snapshot_timestamp(&have_snapshot);
1829 :
1830 60 : if (!have_snapshot)
1831 36 : PG_RETURN_NULL();
1832 :
1833 24 : PG_RETURN_TIMESTAMPTZ(ts);
1834 : }
1835 :
1836 : /* Discard the active statistics snapshot */
1837 : Datum
1838 16 : pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
1839 : {
1840 16 : pgstat_clear_snapshot();
1841 :
1842 16 : PG_RETURN_VOID();
1843 : }
1844 :
1845 :
1846 : /* Force statistics to be reported at the next occasion */
1847 : Datum
1848 428 : pg_stat_force_next_flush(PG_FUNCTION_ARGS)
1849 : {
1850 428 : pgstat_force_next_flush();
1851 :
1852 428 : PG_RETURN_VOID();
1853 : }
1854 :
1855 :
1856 : /* Reset all counters for the current database */
1857 : Datum
1858 26 : pg_stat_reset(PG_FUNCTION_ARGS)
1859 : {
1860 26 : pgstat_reset_counters();
1861 :
1862 26 : PG_RETURN_VOID();
1863 : }
1864 :
1865 : /*
1866 : * Reset some shared cluster-wide counters
1867 : *
1868 : * When adding a new reset target, ideally the name should match that in
1869 : * pgstat_kind_builtin_infos, if relevant.
1870 : */
1871 : Datum
1872 54 : pg_stat_reset_shared(PG_FUNCTION_ARGS)
1873 : {
1874 54 : char *target = NULL;
1875 :
1876 54 : if (PG_ARGISNULL(0))
1877 : {
1878 : /* Reset all the statistics when nothing is specified */
1879 0 : pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
1880 0 : pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
1881 0 : pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
1882 0 : pgstat_reset_of_kind(PGSTAT_KIND_IO);
1883 0 : XLogPrefetchResetStats();
1884 0 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
1885 0 : pgstat_reset_of_kind(PGSTAT_KIND_WAL);
1886 :
1887 0 : PG_RETURN_VOID();
1888 : }
1889 :
1890 54 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1891 :
1892 54 : if (strcmp(target, "archiver") == 0)
1893 8 : pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
1894 46 : else if (strcmp(target, "bgwriter") == 0)
1895 6 : pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
1896 40 : else if (strcmp(target, "checkpointer") == 0)
1897 8 : pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
1898 32 : else if (strcmp(target, "io") == 0)
1899 6 : pgstat_reset_of_kind(PGSTAT_KIND_IO);
1900 26 : else if (strcmp(target, "recovery_prefetch") == 0)
1901 6 : XLogPrefetchResetStats();
1902 20 : else if (strcmp(target, "slru") == 0)
1903 6 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
1904 14 : else if (strcmp(target, "wal") == 0)
1905 8 : pgstat_reset_of_kind(PGSTAT_KIND_WAL);
1906 : else
1907 6 : ereport(ERROR,
1908 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1909 : errmsg("unrecognized reset target: \"%s\"", target),
1910 : errhint("Target must be \"archiver\", \"bgwriter\", \"checkpointer\", \"io\", \"recovery_prefetch\", \"slru\", or \"wal\".")));
1911 :
1912 48 : PG_RETURN_VOID();
1913 : }
1914 :
1915 : /*
1916 : * Reset a statistics for a single object, which may be of current
1917 : * database or shared across all databases in the cluster.
1918 : */
1919 : Datum
1920 12 : pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
1921 : {
1922 12 : Oid taboid = PG_GETARG_OID(0);
1923 12 : Oid dboid = (IsSharedRelation(taboid) ? InvalidOid : MyDatabaseId);
1924 :
1925 12 : pgstat_reset(PGSTAT_KIND_RELATION, dboid, taboid);
1926 :
1927 12 : PG_RETURN_VOID();
1928 : }
1929 :
1930 : Datum
1931 4 : pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
1932 : {
1933 4 : Oid funcoid = PG_GETARG_OID(0);
1934 :
1935 4 : pgstat_reset(PGSTAT_KIND_FUNCTION, MyDatabaseId, funcoid);
1936 :
1937 4 : PG_RETURN_VOID();
1938 : }
1939 :
1940 : /*
1941 : * Reset statistics of backend with given PID.
1942 : */
1943 : Datum
1944 6 : pg_stat_reset_backend_stats(PG_FUNCTION_ARGS)
1945 : {
1946 : PGPROC *proc;
1947 : PgBackendStatus *beentry;
1948 : ProcNumber procNumber;
1949 6 : int backend_pid = PG_GETARG_INT32(0);
1950 :
1951 6 : proc = BackendPidGetProc(backend_pid);
1952 :
1953 : /* This could be an auxiliary process */
1954 6 : if (!proc)
1955 0 : proc = AuxiliaryPidGetProc(backend_pid);
1956 :
1957 6 : if (!proc)
1958 0 : PG_RETURN_VOID();
1959 :
1960 6 : procNumber = GetNumberFromPGProc(proc);
1961 :
1962 6 : beentry = pgstat_get_beentry_by_proc_number(procNumber);
1963 6 : if (!beentry)
1964 0 : PG_RETURN_VOID();
1965 :
1966 : /* Check if the backend type tracks statistics */
1967 6 : if (!pgstat_tracks_backend_bktype(beentry->st_backendType))
1968 0 : PG_RETURN_VOID();
1969 :
1970 6 : pgstat_reset(PGSTAT_KIND_BACKEND, InvalidOid, procNumber);
1971 :
1972 6 : PG_RETURN_VOID();
1973 : }
1974 :
1975 : /* Reset SLRU counters (a specific one or all of them). */
1976 : Datum
1977 12 : pg_stat_reset_slru(PG_FUNCTION_ARGS)
1978 : {
1979 12 : char *target = NULL;
1980 :
1981 12 : if (PG_ARGISNULL(0))
1982 6 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
1983 : else
1984 : {
1985 6 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1986 6 : pgstat_reset_slru(target);
1987 : }
1988 :
1989 12 : PG_RETURN_VOID();
1990 : }
1991 :
1992 : /* Reset replication slots stats (a specific one or all of them). */
1993 : Datum
1994 12 : pg_stat_reset_replication_slot(PG_FUNCTION_ARGS)
1995 : {
1996 12 : char *target = NULL;
1997 :
1998 12 : if (PG_ARGISNULL(0))
1999 4 : pgstat_reset_of_kind(PGSTAT_KIND_REPLSLOT);
2000 : else
2001 : {
2002 8 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
2003 8 : pgstat_reset_replslot(target);
2004 : }
2005 :
2006 10 : PG_RETURN_VOID();
2007 : }
2008 :
2009 : /* Reset subscription stats (a specific one or all of them) */
2010 : Datum
2011 20 : pg_stat_reset_subscription_stats(PG_FUNCTION_ARGS)
2012 : {
2013 : Oid subid;
2014 :
2015 20 : if (PG_ARGISNULL(0))
2016 : {
2017 : /* Clear all subscription stats */
2018 4 : pgstat_reset_of_kind(PGSTAT_KIND_SUBSCRIPTION);
2019 : }
2020 : else
2021 : {
2022 16 : subid = PG_GETARG_OID(0);
2023 :
2024 16 : if (!OidIsValid(subid))
2025 0 : ereport(ERROR,
2026 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2027 : errmsg("invalid subscription OID %u", subid)));
2028 16 : pgstat_reset(PGSTAT_KIND_SUBSCRIPTION, InvalidOid, subid);
2029 : }
2030 :
2031 20 : PG_RETURN_VOID();
2032 : }
2033 :
2034 : Datum
2035 58 : pg_stat_get_archiver(PG_FUNCTION_ARGS)
2036 : {
2037 : TupleDesc tupdesc;
2038 58 : Datum values[7] = {0};
2039 58 : bool nulls[7] = {0};
2040 : PgStat_ArchiverStats *archiver_stats;
2041 :
2042 : /* Initialise attributes information in the tuple descriptor */
2043 58 : tupdesc = CreateTemplateTupleDesc(7);
2044 58 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count",
2045 : INT8OID, -1, 0);
2046 58 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
2047 : TEXTOID, -1, 0);
2048 58 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time",
2049 : TIMESTAMPTZOID, -1, 0);
2050 58 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count",
2051 : INT8OID, -1, 0);
2052 58 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
2053 : TEXTOID, -1, 0);
2054 58 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time",
2055 : TIMESTAMPTZOID, -1, 0);
2056 58 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset",
2057 : TIMESTAMPTZOID, -1, 0);
2058 :
2059 58 : BlessTupleDesc(tupdesc);
2060 :
2061 : /* Get statistics about the archiver process */
2062 58 : archiver_stats = pgstat_fetch_stat_archiver();
2063 :
2064 : /* Fill values and NULLs */
2065 58 : values[0] = Int64GetDatum(archiver_stats->archived_count);
2066 58 : if (*(archiver_stats->last_archived_wal) == '\0')
2067 24 : nulls[1] = true;
2068 : else
2069 34 : values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
2070 :
2071 58 : if (archiver_stats->last_archived_timestamp == 0)
2072 24 : nulls[2] = true;
2073 : else
2074 34 : values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp);
2075 :
2076 58 : values[3] = Int64GetDatum(archiver_stats->failed_count);
2077 58 : if (*(archiver_stats->last_failed_wal) == '\0')
2078 30 : nulls[4] = true;
2079 : else
2080 28 : values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
2081 :
2082 58 : if (archiver_stats->last_failed_timestamp == 0)
2083 30 : nulls[5] = true;
2084 : else
2085 28 : values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp);
2086 :
2087 58 : if (archiver_stats->stat_reset_timestamp == 0)
2088 0 : nulls[6] = true;
2089 : else
2090 58 : values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
2091 :
2092 : /* Returns the record as Datum */
2093 58 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
2094 : }
2095 :
2096 : /*
2097 : * Get the statistics for the replication slot. If the slot statistics is not
2098 : * available, return all-zeroes stats.
2099 : */
2100 : Datum
2101 102 : pg_stat_get_replication_slot(PG_FUNCTION_ARGS)
2102 : {
2103 : #define PG_STAT_GET_REPLICATION_SLOT_COLS 10
2104 102 : text *slotname_text = PG_GETARG_TEXT_P(0);
2105 : NameData slotname;
2106 : TupleDesc tupdesc;
2107 102 : Datum values[PG_STAT_GET_REPLICATION_SLOT_COLS] = {0};
2108 102 : bool nulls[PG_STAT_GET_REPLICATION_SLOT_COLS] = {0};
2109 : PgStat_StatReplSlotEntry *slotent;
2110 : PgStat_StatReplSlotEntry allzero;
2111 :
2112 : /* Initialise attributes information in the tuple descriptor */
2113 102 : tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_REPLICATION_SLOT_COLS);
2114 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "slot_name",
2115 : TEXTOID, -1, 0);
2116 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "spill_txns",
2117 : INT8OID, -1, 0);
2118 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "spill_count",
2119 : INT8OID, -1, 0);
2120 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "spill_bytes",
2121 : INT8OID, -1, 0);
2122 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "stream_txns",
2123 : INT8OID, -1, 0);
2124 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "stream_count",
2125 : INT8OID, -1, 0);
2126 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stream_bytes",
2127 : INT8OID, -1, 0);
2128 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 8, "total_txns",
2129 : INT8OID, -1, 0);
2130 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 9, "total_bytes",
2131 : INT8OID, -1, 0);
2132 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 10, "stats_reset",
2133 : TIMESTAMPTZOID, -1, 0);
2134 102 : BlessTupleDesc(tupdesc);
2135 :
2136 102 : namestrcpy(&slotname, text_to_cstring(slotname_text));
2137 102 : slotent = pgstat_fetch_replslot(slotname);
2138 102 : if (!slotent)
2139 : {
2140 : /*
2141 : * If the slot is not found, initialise its stats. This is possible if
2142 : * the create slot message is lost.
2143 : */
2144 4 : memset(&allzero, 0, sizeof(PgStat_StatReplSlotEntry));
2145 4 : slotent = &allzero;
2146 : }
2147 :
2148 102 : values[0] = CStringGetTextDatum(NameStr(slotname));
2149 102 : values[1] = Int64GetDatum(slotent->spill_txns);
2150 102 : values[2] = Int64GetDatum(slotent->spill_count);
2151 102 : values[3] = Int64GetDatum(slotent->spill_bytes);
2152 102 : values[4] = Int64GetDatum(slotent->stream_txns);
2153 102 : values[5] = Int64GetDatum(slotent->stream_count);
2154 102 : values[6] = Int64GetDatum(slotent->stream_bytes);
2155 102 : values[7] = Int64GetDatum(slotent->total_txns);
2156 102 : values[8] = Int64GetDatum(slotent->total_bytes);
2157 :
2158 102 : if (slotent->stat_reset_timestamp == 0)
2159 54 : nulls[9] = true;
2160 : else
2161 48 : values[9] = TimestampTzGetDatum(slotent->stat_reset_timestamp);
2162 :
2163 : /* Returns the record as Datum */
2164 102 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
2165 : }
2166 :
2167 : /*
2168 : * Get the subscription statistics for the given subscription. If the
2169 : * subscription statistics is not available, return all-zeros stats.
2170 : */
2171 : Datum
2172 82 : pg_stat_get_subscription_stats(PG_FUNCTION_ARGS)
2173 : {
2174 : #define PG_STAT_GET_SUBSCRIPTION_STATS_COLS 11
2175 82 : Oid subid = PG_GETARG_OID(0);
2176 : TupleDesc tupdesc;
2177 82 : Datum values[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
2178 82 : bool nulls[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
2179 : PgStat_StatSubEntry *subentry;
2180 : PgStat_StatSubEntry allzero;
2181 82 : int i = 0;
2182 :
2183 : /* Get subscription stats */
2184 82 : subentry = pgstat_fetch_stat_subscription(subid);
2185 :
2186 : /* Initialise attributes information in the tuple descriptor */
2187 82 : tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_SUBSCRIPTION_STATS_COLS);
2188 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "subid",
2189 : OIDOID, -1, 0);
2190 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "apply_error_count",
2191 : INT8OID, -1, 0);
2192 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "sync_error_count",
2193 : INT8OID, -1, 0);
2194 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "confl_insert_exists",
2195 : INT8OID, -1, 0);
2196 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "confl_update_origin_differs",
2197 : INT8OID, -1, 0);
2198 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "confl_update_exists",
2199 : INT8OID, -1, 0);
2200 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "confl_update_missing",
2201 : INT8OID, -1, 0);
2202 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 8, "confl_delete_origin_differs",
2203 : INT8OID, -1, 0);
2204 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 9, "confl_delete_missing",
2205 : INT8OID, -1, 0);
2206 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 10, "confl_multiple_unique_conflicts",
2207 : INT8OID, -1, 0);
2208 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 11, "stats_reset",
2209 : TIMESTAMPTZOID, -1, 0);
2210 82 : BlessTupleDesc(tupdesc);
2211 :
2212 82 : if (!subentry)
2213 : {
2214 : /* If the subscription is not found, initialise its stats */
2215 0 : memset(&allzero, 0, sizeof(PgStat_StatSubEntry));
2216 0 : subentry = &allzero;
2217 : }
2218 :
2219 : /* subid */
2220 82 : values[i++] = ObjectIdGetDatum(subid);
2221 :
2222 : /* apply_error_count */
2223 82 : values[i++] = Int64GetDatum(subentry->apply_error_count);
2224 :
2225 : /* sync_error_count */
2226 82 : values[i++] = Int64GetDatum(subentry->sync_error_count);
2227 :
2228 : /* conflict count */
2229 656 : for (int nconflict = 0; nconflict < CONFLICT_NUM_TYPES; nconflict++)
2230 574 : values[i++] = Int64GetDatum(subentry->conflict_count[nconflict]);
2231 :
2232 : /* stats_reset */
2233 82 : if (subentry->stat_reset_timestamp == 0)
2234 44 : nulls[i] = true;
2235 : else
2236 38 : values[i] = TimestampTzGetDatum(subentry->stat_reset_timestamp);
2237 :
2238 : Assert(i + 1 == PG_STAT_GET_SUBSCRIPTION_STATS_COLS);
2239 :
2240 : /* Returns the record as Datum */
2241 82 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
2242 : }
2243 :
2244 : /*
2245 : * Checks for presence of stats for object with provided kind, database oid,
2246 : * object oid.
2247 : *
2248 : * This is useful for tests, but not really anything else. Therefore not
2249 : * documented.
2250 : */
2251 : Datum
2252 170 : pg_stat_have_stats(PG_FUNCTION_ARGS)
2253 : {
2254 170 : char *stats_type = text_to_cstring(PG_GETARG_TEXT_P(0));
2255 170 : Oid dboid = PG_GETARG_OID(1);
2256 170 : uint64 objid = PG_GETARG_INT64(2);
2257 170 : PgStat_Kind kind = pgstat_get_kind_from_str(stats_type);
2258 :
2259 164 : PG_RETURN_BOOL(pgstat_have_entry(kind, dboid, objid));
2260 : }
|