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