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