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