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 5747 : 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 15 : pg_stat_get_progress_info(PG_FUNCTION_ARGS)
279 : {
280 : #define PG_STAT_GET_PROGRESS_COLS PGSTAT_NUM_PROGRESS_PARAM + 3
281 15 : int num_backends = pgstat_fetch_stat_numbackends();
282 : int curr_backend;
283 15 : char *cmd = text_to_cstring(PG_GETARG_TEXT_PP(0));
284 : ProgressCommandType cmdtype;
285 15 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
286 :
287 : /* Translate command name into command type code. */
288 15 : if (pg_strcasecmp(cmd, "VACUUM") == 0)
289 1 : cmdtype = PROGRESS_COMMAND_VACUUM;
290 14 : else if (pg_strcasecmp(cmd, "ANALYZE") == 0)
291 0 : cmdtype = PROGRESS_COMMAND_ANALYZE;
292 14 : else if (pg_strcasecmp(cmd, "REPACK") == 0)
293 0 : cmdtype = PROGRESS_COMMAND_REPACK;
294 14 : else if (pg_strcasecmp(cmd, "CREATE INDEX") == 0)
295 0 : cmdtype = PROGRESS_COMMAND_CREATE_INDEX;
296 14 : else if (pg_strcasecmp(cmd, "BASEBACKUP") == 0)
297 2 : 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 15 : InitMaterializedSRF(fcinfo, 0);
308 :
309 : /* 1-based index */
310 183 : for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
311 : {
312 : LocalPgBackendStatus *local_beentry;
313 : PgBackendStatus *beentry;
314 168 : Datum values[PG_STAT_GET_PROGRESS_COLS] = {0};
315 168 : bool nulls[PG_STAT_GET_PROGRESS_COLS] = {0};
316 : int i;
317 :
318 168 : local_beentry = pgstat_get_local_beentry_by_index(curr_backend);
319 168 : beentry = &local_beentry->backendStatus;
320 :
321 : /*
322 : * Report values for only those backends which are running the given
323 : * command.
324 : */
325 168 : if (beentry->st_progress_command != cmdtype)
326 153 : continue;
327 :
328 : /* Value available to all callers */
329 15 : values[0] = Int32GetDatum(beentry->st_procpid);
330 15 : values[1] = ObjectIdGetDatum(beentry->st_databaseid);
331 :
332 : /* show rest of the values including relid only to role members */
333 30 : if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
334 : {
335 15 : values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
336 315 : for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
337 300 : 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 15 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
347 : }
348 :
349 15 : return (Datum) 0;
350 : }
351 :
352 : /*
353 : * Returns activity of PG backends.
354 : */
355 : Datum
356 918 : pg_stat_get_activity(PG_FUNCTION_ARGS)
357 : {
358 : #define PG_STAT_GET_ACTIVITY_COLS 31
359 918 : int num_backends = pgstat_fetch_stat_numbackends();
360 : int curr_backend;
361 918 : int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
362 918 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
363 :
364 918 : InitMaterializedSRF(fcinfo, 0);
365 :
366 : /* 1-based index */
367 10836 : for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
368 : {
369 : /* for each row */
370 9919 : Datum values[PG_STAT_GET_ACTIVITY_COLS] = {0};
371 9919 : bool nulls[PG_STAT_GET_ACTIVITY_COLS] = {0};
372 : LocalPgBackendStatus *local_beentry;
373 : PgBackendStatus *beentry;
374 : PGPROC *proc;
375 9919 : const char *wait_event_type = NULL;
376 9919 : const char *wait_event = NULL;
377 :
378 : /* Get the next one in the list */
379 9919 : local_beentry = pgstat_get_local_beentry_by_index(curr_backend);
380 9919 : beentry = &local_beentry->backendStatus;
381 :
382 : /* If looking for specific PID, ignore all the others */
383 9919 : if (pid != -1 && beentry->st_procpid != pid)
384 0 : continue;
385 :
386 : /* Values available to all callers */
387 9919 : if (beentry->st_databaseid != InvalidOid)
388 2046 : values[0] = ObjectIdGetDatum(beentry->st_databaseid);
389 : else
390 7873 : nulls[0] = true;
391 :
392 9919 : values[1] = Int32GetDatum(beentry->st_procpid);
393 :
394 9919 : if (beentry->st_userid != InvalidOid)
395 3207 : values[2] = ObjectIdGetDatum(beentry->st_userid);
396 : else
397 6712 : nulls[2] = true;
398 :
399 9919 : if (beentry->st_appname)
400 9919 : values[3] = CStringGetTextDatum(beentry->st_appname);
401 : else
402 0 : nulls[3] = true;
403 :
404 9919 : if (TransactionIdIsValid(local_beentry->backend_xid))
405 73 : values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
406 : else
407 9846 : nulls[15] = true;
408 :
409 9919 : if (TransactionIdIsValid(local_beentry->backend_xmin))
410 1138 : values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
411 : else
412 8781 : nulls[16] = true;
413 :
414 : /* Values only available to role member or pg_read_all_stats */
415 9919 : if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
416 9534 : {
417 : char *clipped_activity;
418 :
419 9534 : switch (beentry->st_state)
420 : {
421 2 : case STATE_STARTING:
422 2 : values[4] = CStringGetTextDatum("starting");
423 2 : break;
424 271 : case STATE_IDLE:
425 271 : values[4] = CStringGetTextDatum("idle");
426 271 : break;
427 2012 : case STATE_RUNNING:
428 2012 : values[4] = CStringGetTextDatum("active");
429 2012 : break;
430 22 : case STATE_IDLEINTRANSACTION:
431 22 : values[4] = CStringGetTextDatum("idle in transaction");
432 22 : 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 7223 : case STATE_UNDEFINED:
443 7223 : nulls[4] = true;
444 7223 : break;
445 : }
446 :
447 9534 : clipped_activity = pgstat_clip_activity(beentry->st_activity_raw);
448 9534 : values[5] = CStringGetTextDatum(clipped_activity);
449 9534 : pfree(clipped_activity);
450 :
451 : /* leader_pid */
452 9534 : nulls[29] = true;
453 :
454 9534 : proc = BackendPidGetProc(beentry->st_procpid);
455 :
456 9534 : 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 5598 : 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 9534 : if (proc != NULL)
472 : {
473 : uint32 raw_wait_event;
474 : PGPROC *leader;
475 :
476 9534 : raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
477 9534 : wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
478 9534 : wait_event = pgstat_get_wait_event(raw_wait_event);
479 :
480 9534 : 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 9534 : if (leader && leader->pid != beentry->st_procpid)
488 : {
489 1 : values[29] = Int32GetDatum(leader->pid);
490 1 : nulls[29] = false;
491 : }
492 9533 : else if (beentry->st_backendType == B_BG_WORKER)
493 : {
494 916 : int leader_pid = GetLeaderApplyWorkerPid(beentry->st_procpid);
495 :
496 916 : if (leader_pid != InvalidPid)
497 : {
498 0 : values[29] = Int32GetDatum(leader_pid);
499 0 : nulls[29] = false;
500 : }
501 : }
502 : }
503 :
504 9534 : if (wait_event_type)
505 8520 : values[6] = CStringGetTextDatum(wait_event_type);
506 : else
507 1014 : nulls[6] = true;
508 :
509 9534 : if (wait_event)
510 8520 : values[7] = CStringGetTextDatum(wait_event);
511 : else
512 1014 : 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 9534 : if (beentry->st_xact_start_timestamp != 0 &&
520 1219 : beentry->st_backendType != B_WAL_SENDER)
521 1218 : values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
522 : else
523 8316 : nulls[8] = true;
524 :
525 9534 : if (beentry->st_activity_start_timestamp != 0)
526 2248 : values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
527 : else
528 7286 : nulls[9] = true;
529 :
530 9534 : if (beentry->st_proc_start_timestamp != 0)
531 9534 : values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
532 : else
533 0 : nulls[10] = true;
534 :
535 9534 : if (beentry->st_state_start_timestamp != 0)
536 2305 : values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
537 : else
538 7229 : nulls[11] = true;
539 :
540 : /* A zeroed client addr means we don't know */
541 9534 : if (pg_memory_is_all_zeros(&beentry->st_clientaddr,
542 : sizeof(beentry->st_clientaddr)))
543 : {
544 7291 : nulls[12] = true;
545 7291 : nulls[13] = true;
546 7291 : nulls[14] = true;
547 : }
548 : else
549 : {
550 2243 : if (beentry->st_clientaddr.addr.ss_family == AF_INET ||
551 2198 : 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 2198 : 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 2198 : nulls[12] = true;
592 2198 : nulls[13] = true;
593 2198 : 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 9534 : if (beentry->st_backendType == B_BG_WORKER)
605 : {
606 : const char *bgw_type;
607 :
608 917 : bgw_type = GetBackgroundWorkerTypeByPid(beentry->st_procpid);
609 917 : if (bgw_type)
610 917 : values[17] = CStringGetTextDatum(bgw_type);
611 : else
612 0 : nulls[17] = true;
613 : }
614 : else
615 8617 : values[17] =
616 8617 : CStringGetTextDatum(GetBackendTypeDesc(beentry->st_backendType));
617 :
618 : /* SSL information */
619 9534 : 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 9513 : values[18] = BoolGetDatum(false); /* ssl */
647 9513 : nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = true;
648 : }
649 :
650 : /* GSSAPI information */
651 9534 : 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 9534 : values[25] = BoolGetDatum(false); /* gss_auth */
662 9534 : nulls[26] = true; /* No GSS principal */
663 9534 : values[27] = BoolGetDatum(false); /* GSS Encryption not in
664 : * use */
665 9534 : values[28] = BoolGetDatum(false); /* GSS credentials not
666 : * delegated */
667 : }
668 9534 : if (beentry->st_query_id == INT64CONST(0))
669 9478 : nulls[30] = true;
670 : else
671 56 : values[30] = Int64GetDatum(beentry->st_query_id);
672 : }
673 : else
674 : {
675 : /* No permissions to view data about this session */
676 385 : values[5] = CStringGetTextDatum("<insufficient privilege>");
677 385 : nulls[4] = true;
678 385 : nulls[6] = true;
679 385 : nulls[7] = true;
680 385 : nulls[8] = true;
681 385 : nulls[9] = true;
682 385 : nulls[10] = true;
683 385 : nulls[11] = true;
684 385 : nulls[12] = true;
685 385 : nulls[13] = true;
686 385 : nulls[14] = true;
687 385 : nulls[17] = true;
688 385 : nulls[18] = true;
689 385 : nulls[19] = true;
690 385 : nulls[20] = true;
691 385 : nulls[21] = true;
692 385 : nulls[22] = true;
693 385 : nulls[23] = true;
694 385 : nulls[24] = true;
695 385 : nulls[25] = true;
696 385 : nulls[26] = true;
697 385 : nulls[27] = true;
698 385 : nulls[28] = true;
699 385 : nulls[29] = true;
700 385 : nulls[30] = true;
701 : }
702 :
703 9919 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
704 :
705 : /* If only a single backend was requested, and we found it, break. */
706 9919 : if (pid != -1)
707 1 : break;
708 : }
709 :
710 918 : return (Datum) 0;
711 : }
712 :
713 :
714 : Datum
715 1013 : pg_backend_pid(PG_FUNCTION_ARGS)
716 : {
717 1013 : 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 16 : pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)
1143 : {
1144 16 : Oid dbid = PG_GETARG_OID(0);
1145 : TimestampTz result;
1146 : PgStat_StatDBEntry *dbentry;
1147 :
1148 16 : if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1149 0 : result = 0;
1150 : else
1151 16 : result = dbentry->stat_reset_timestamp;
1152 :
1153 16 : if (result == 0)
1154 0 : PG_RETURN_NULL();
1155 : else
1156 16 : 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 31362 : pg_stat_us_to_ms(PgStat_Counter val_ms)
1459 : {
1460 31362 : 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 45694 : PgStat_Counter count =
1519 : bktype_stats->counts[io_obj][io_context][io_op];
1520 :
1521 45694 : values[op_idx] = Int64GetDatum(count);
1522 : }
1523 : else
1524 27538 : nulls[op_idx] = true;
1525 :
1526 73232 : if (!nulls[op_idx])
1527 : {
1528 : /* not every operation is timed */
1529 45694 : if (time_idx != IO_COL_INVALID)
1530 : {
1531 31362 : PgStat_Counter time =
1532 : bktype_stats->times[io_obj][io_context][io_op];
1533 :
1534 31362 : values[time_idx] = Float8GetDatum(pg_stat_us_to_ms(time));
1535 : }
1536 :
1537 : /* not every IO is tracked in bytes */
1538 45694 : if (byte_idx != IO_COL_INVALID)
1539 : {
1540 : char buf[256];
1541 20394 : PgStat_Counter byte =
1542 20394 : bktype_stats->bytes[io_obj][io_context][io_op];
1543 :
1544 : /* Convert to numeric */
1545 20394 : snprintf(buf, sizeof buf, INT64_FORMAT, byte);
1546 20394 : values[byte_idx] = DirectFunctionCall3(numeric_in,
1547 : CStringGetDatum(buf),
1548 : ObjectIdGetDatum(0),
1549 : Int32GetDatum(-1));
1550 : }
1551 : }
1552 : else
1553 : {
1554 27538 : if (time_idx != IO_COL_INVALID)
1555 14408 : nulls[time_idx] = true;
1556 27538 : if (byte_idx != IO_COL_INVALID)
1557 7068 : 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 49 : 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 49 : Datum values[PG_STAT_WAL_COLS] = {0};
1654 49 : bool nulls[PG_STAT_WAL_COLS] = {0};
1655 : char buf[256];
1656 :
1657 : /* Initialise attributes information in the tuple descriptor */
1658 49 : tupdesc = CreateTemplateTupleDesc(PG_STAT_WAL_COLS);
1659 49 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "wal_records",
1660 : INT8OID, -1, 0);
1661 49 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "wal_fpi",
1662 : INT8OID, -1, 0);
1663 49 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "wal_bytes",
1664 : NUMERICOID, -1, 0);
1665 49 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_fpi_bytes",
1666 : NUMERICOID, -1, 0);
1667 49 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "wal_buffers_full",
1668 : INT8OID, -1, 0);
1669 49 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "stats_reset",
1670 : TIMESTAMPTZOID, -1, 0);
1671 :
1672 49 : TupleDescFinalize(tupdesc);
1673 49 : BlessTupleDesc(tupdesc);
1674 :
1675 : /* Fill values and NULLs */
1676 49 : values[0] = Int64GetDatum(wal_counters.wal_records);
1677 49 : values[1] = Int64GetDatum(wal_counters.wal_fpi);
1678 :
1679 : /* Convert to numeric. */
1680 49 : snprintf(buf, sizeof buf, UINT64_FORMAT, wal_counters.wal_bytes);
1681 49 : values[2] = DirectFunctionCall3(numeric_in,
1682 : CStringGetDatum(buf),
1683 : ObjectIdGetDatum(0),
1684 : Int32GetDatum(-1));
1685 :
1686 49 : snprintf(buf, sizeof buf, UINT64_FORMAT, wal_counters.wal_fpi_bytes);
1687 49 : values[3] = DirectFunctionCall3(numeric_in,
1688 : CStringGetDatum(buf),
1689 : ObjectIdGetDatum(0),
1690 : Int32GetDatum(-1));
1691 :
1692 49 : values[4] = Int64GetDatum(wal_counters.wal_buffers_full);
1693 :
1694 49 : if (stat_reset_timestamp != 0)
1695 41 : values[5] = TimestampTzGetDatum(stat_reset_timestamp);
1696 : else
1697 8 : nulls[5] = true;
1698 :
1699 : /* Returns the record as Datum */
1700 49 : 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 41 : pg_stat_get_wal(PG_FUNCTION_ARGS)
1730 : {
1731 : PgStat_WalStats *wal_stats;
1732 :
1733 : /* Get statistics about WAL activity */
1734 41 : wal_stats = pgstat_fetch_stat_wal();
1735 :
1736 41 : return (pg_stat_wal_build_tuple(wal_stats->wal_counters,
1737 : wal_stats->stat_reset_timestamp));
1738 : }
1739 :
1740 : Datum
1741 8 : pg_stat_get_lock(PG_FUNCTION_ARGS)
1742 : {
1743 : #define PG_STAT_LOCK_COLS 5
1744 : ReturnSetInfo *rsinfo;
1745 : PgStat_Lock *lock_stats;
1746 :
1747 8 : InitMaterializedSRF(fcinfo, 0);
1748 8 : rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1749 :
1750 8 : lock_stats = pgstat_fetch_stat_lock();
1751 :
1752 104 : for (int lcktype = 0; lcktype <= LOCKTAG_LAST_TYPE; lcktype++)
1753 : {
1754 : const char *locktypename;
1755 96 : Datum values[PG_STAT_LOCK_COLS] = {0};
1756 96 : bool nulls[PG_STAT_LOCK_COLS] = {0};
1757 96 : PgStat_LockEntry *lck_stats = &lock_stats->stats[lcktype];
1758 96 : int i = 0;
1759 :
1760 96 : locktypename = LockTagTypeNames[lcktype];
1761 :
1762 96 : values[i++] = CStringGetTextDatum(locktypename);
1763 96 : values[i++] = Int64GetDatum(lck_stats->waits);
1764 96 : values[i++] = Int64GetDatum(lck_stats->wait_time);
1765 96 : values[i++] = Int64GetDatum(lck_stats->fastpath_exceeded);
1766 96 : values[i] = TimestampTzGetDatum(lock_stats->stat_reset_timestamp);
1767 :
1768 : Assert(i + 1 == PG_STAT_LOCK_COLS);
1769 :
1770 96 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1771 : }
1772 :
1773 8 : return (Datum) 0;
1774 : }
1775 :
1776 : /*
1777 : * Returns statistics of SLRU caches.
1778 : */
1779 : Datum
1780 71 : pg_stat_get_slru(PG_FUNCTION_ARGS)
1781 : {
1782 : #define PG_STAT_GET_SLRU_COLS 9
1783 71 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1784 : int i;
1785 : PgStat_SLRUStats *stats;
1786 :
1787 71 : InitMaterializedSRF(fcinfo, 0);
1788 :
1789 : /* request SLRU stats from the cumulative stats system */
1790 71 : stats = pgstat_fetch_slru();
1791 :
1792 71 : for (i = 0;; i++)
1793 568 : {
1794 : /* for each row */
1795 639 : Datum values[PG_STAT_GET_SLRU_COLS] = {0};
1796 639 : bool nulls[PG_STAT_GET_SLRU_COLS] = {0};
1797 : PgStat_SLRUStats stat;
1798 : const char *name;
1799 :
1800 639 : name = pgstat_get_slru_name(i);
1801 :
1802 639 : if (!name)
1803 71 : break;
1804 :
1805 568 : stat = stats[i];
1806 :
1807 568 : values[0] = PointerGetDatum(cstring_to_text(name));
1808 568 : values[1] = Int64GetDatum(stat.blocks_zeroed);
1809 568 : values[2] = Int64GetDatum(stat.blocks_hit);
1810 568 : values[3] = Int64GetDatum(stat.blocks_read);
1811 568 : values[4] = Int64GetDatum(stat.blocks_written);
1812 568 : values[5] = Int64GetDatum(stat.blocks_exists);
1813 568 : values[6] = Int64GetDatum(stat.flush);
1814 568 : values[7] = Int64GetDatum(stat.truncate);
1815 568 : values[8] = TimestampTzGetDatum(stat.stat_reset_timestamp);
1816 :
1817 568 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1818 : }
1819 :
1820 71 : return (Datum) 0;
1821 : }
1822 :
1823 : #define PG_STAT_GET_XACT_RELENTRY_INT64(stat) \
1824 : Datum \
1825 : CppConcat(pg_stat_get_xact_,stat)(PG_FUNCTION_ARGS) \
1826 : { \
1827 : Oid relid = PG_GETARG_OID(0); \
1828 : int64 result; \
1829 : PgStat_TableStatus *tabentry; \
1830 : \
1831 : if ((tabentry = find_tabstat_entry(relid)) == NULL) \
1832 : result = 0; \
1833 : else \
1834 : result = (int64) (tabentry->counts.stat); \
1835 : \
1836 : PG_RETURN_INT64(result); \
1837 : }
1838 :
1839 : /* pg_stat_get_xact_numscans */
1840 0 : PG_STAT_GET_XACT_RELENTRY_INT64(numscans)
1841 :
1842 : /* pg_stat_get_xact_tuples_returned */
1843 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_returned)
1844 :
1845 : /* pg_stat_get_xact_tuples_fetched */
1846 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_fetched)
1847 :
1848 : /* pg_stat_get_xact_tuples_hot_updated */
1849 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_hot_updated)
1850 :
1851 : /* pg_stat_get_xact_tuples_newpage_updated */
1852 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_newpage_updated)
1853 :
1854 : /* pg_stat_get_xact_blocks_fetched */
1855 0 : PG_STAT_GET_XACT_RELENTRY_INT64(blocks_fetched)
1856 :
1857 : /* pg_stat_get_xact_blocks_hit */
1858 0 : PG_STAT_GET_XACT_RELENTRY_INT64(blocks_hit)
1859 :
1860 : /* pg_stat_get_xact_tuples_inserted */
1861 32 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_inserted)
1862 :
1863 : /* pg_stat_get_xact_tuples_updated */
1864 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_updated)
1865 :
1866 : /* pg_stat_get_xact_tuples_deleted */
1867 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_deleted)
1868 :
1869 : Datum
1870 16 : pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
1871 : {
1872 16 : Oid funcid = PG_GETARG_OID(0);
1873 : PgStat_FunctionCounts *funcentry;
1874 :
1875 16 : if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1876 4 : PG_RETURN_NULL();
1877 12 : PG_RETURN_INT64(funcentry->numcalls);
1878 : }
1879 :
1880 : #define PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(stat) \
1881 : Datum \
1882 : CppConcat(pg_stat_get_xact_function_,stat)(PG_FUNCTION_ARGS) \
1883 : { \
1884 : Oid funcid = PG_GETARG_OID(0); \
1885 : PgStat_FunctionCounts *funcentry; \
1886 : \
1887 : if ((funcentry = find_funcstat_entry(funcid)) == NULL) \
1888 : PG_RETURN_NULL(); \
1889 : PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->stat)); \
1890 : }
1891 :
1892 : /* pg_stat_get_xact_function_total_time */
1893 0 : PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(total_time)
1894 :
1895 : /* pg_stat_get_xact_function_self_time */
1896 0 : PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(self_time)
1897 :
1898 : /* Get the timestamp of the current statistics snapshot */
1899 : Datum
1900 40 : pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS)
1901 : {
1902 : bool have_snapshot;
1903 : TimestampTz ts;
1904 :
1905 40 : ts = pgstat_get_stat_snapshot_timestamp(&have_snapshot);
1906 :
1907 40 : if (!have_snapshot)
1908 24 : PG_RETURN_NULL();
1909 :
1910 16 : PG_RETURN_TIMESTAMPTZ(ts);
1911 : }
1912 :
1913 : /* Discard the active statistics snapshot */
1914 : Datum
1915 8 : pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
1916 : {
1917 8 : pgstat_clear_snapshot();
1918 :
1919 8 : PG_RETURN_VOID();
1920 : }
1921 :
1922 :
1923 : /* Force statistics to be reported at the next occasion */
1924 : Datum
1925 335 : pg_stat_force_next_flush(PG_FUNCTION_ARGS)
1926 : {
1927 335 : pgstat_force_next_flush();
1928 :
1929 335 : PG_RETURN_VOID();
1930 : }
1931 :
1932 :
1933 : /* Reset all counters for the current database */
1934 : Datum
1935 15 : pg_stat_reset(PG_FUNCTION_ARGS)
1936 : {
1937 15 : pgstat_reset_counters();
1938 :
1939 15 : PG_RETURN_VOID();
1940 : }
1941 :
1942 : /*
1943 : * Reset some shared cluster-wide counters
1944 : *
1945 : * When adding a new reset target, ideally the name should match that in
1946 : * pgstat_kind_builtin_infos, if relevant.
1947 : */
1948 : Datum
1949 40 : pg_stat_reset_shared(PG_FUNCTION_ARGS)
1950 : {
1951 40 : char *target = NULL;
1952 :
1953 40 : if (PG_ARGISNULL(0))
1954 : {
1955 : /* Reset all the statistics when nothing is specified */
1956 0 : pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
1957 0 : pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
1958 0 : pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
1959 0 : pgstat_reset_of_kind(PGSTAT_KIND_IO);
1960 0 : pgstat_reset_of_kind(PGSTAT_KIND_LOCK);
1961 0 : XLogPrefetchResetStats();
1962 0 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
1963 0 : pgstat_reset_of_kind(PGSTAT_KIND_WAL);
1964 :
1965 0 : PG_RETURN_VOID();
1966 : }
1967 :
1968 40 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1969 :
1970 40 : if (strcmp(target, "archiver") == 0)
1971 4 : pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
1972 36 : else if (strcmp(target, "bgwriter") == 0)
1973 4 : pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
1974 32 : else if (strcmp(target, "checkpointer") == 0)
1975 5 : pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
1976 27 : else if (strcmp(target, "io") == 0)
1977 6 : pgstat_reset_of_kind(PGSTAT_KIND_IO);
1978 21 : else if (strcmp(target, "lock") == 0)
1979 4 : pgstat_reset_of_kind(PGSTAT_KIND_LOCK);
1980 17 : else if (strcmp(target, "recovery_prefetch") == 0)
1981 4 : XLogPrefetchResetStats();
1982 13 : else if (strcmp(target, "slru") == 0)
1983 4 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
1984 9 : else if (strcmp(target, "wal") == 0)
1985 5 : pgstat_reset_of_kind(PGSTAT_KIND_WAL);
1986 : else
1987 4 : ereport(ERROR,
1988 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1989 : errmsg("unrecognized reset target: \"%s\"", target),
1990 : errhint("Target must be \"archiver\", \"bgwriter\", \"checkpointer\", \"io\", \"recovery_prefetch\", \"slru\", or \"wal\".")));
1991 :
1992 36 : PG_RETURN_VOID();
1993 : }
1994 :
1995 : /*
1996 : * Reset statistics for a single object, which may be of current
1997 : * database or shared across all databases in the cluster.
1998 : */
1999 : Datum
2000 20 : pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
2001 : {
2002 20 : Oid taboid = PG_GETARG_OID(0);
2003 20 : Oid dboid = (IsSharedRelation(taboid) ? InvalidOid : MyDatabaseId);
2004 :
2005 20 : pgstat_reset(PGSTAT_KIND_RELATION, dboid, taboid);
2006 :
2007 20 : PG_RETURN_VOID();
2008 : }
2009 :
2010 : Datum
2011 2 : pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
2012 : {
2013 2 : Oid funcoid = PG_GETARG_OID(0);
2014 :
2015 2 : pgstat_reset(PGSTAT_KIND_FUNCTION, MyDatabaseId, funcoid);
2016 :
2017 2 : PG_RETURN_VOID();
2018 : }
2019 :
2020 : /*
2021 : * Reset statistics of backend with given PID.
2022 : */
2023 : Datum
2024 4 : pg_stat_reset_backend_stats(PG_FUNCTION_ARGS)
2025 : {
2026 : PGPROC *proc;
2027 : PgBackendStatus *beentry;
2028 : ProcNumber procNumber;
2029 4 : int backend_pid = PG_GETARG_INT32(0);
2030 :
2031 4 : proc = BackendPidGetProc(backend_pid);
2032 :
2033 : /* This could be an auxiliary process */
2034 4 : if (!proc)
2035 0 : proc = AuxiliaryPidGetProc(backend_pid);
2036 :
2037 4 : if (!proc)
2038 0 : PG_RETURN_VOID();
2039 :
2040 4 : procNumber = GetNumberFromPGProc(proc);
2041 :
2042 4 : beentry = pgstat_get_beentry_by_proc_number(procNumber);
2043 4 : if (!beentry)
2044 0 : PG_RETURN_VOID();
2045 :
2046 : /* Check if the backend type tracks statistics */
2047 4 : if (!pgstat_tracks_backend_bktype(beentry->st_backendType))
2048 0 : PG_RETURN_VOID();
2049 :
2050 4 : pgstat_reset(PGSTAT_KIND_BACKEND, InvalidOid, procNumber);
2051 :
2052 4 : PG_RETURN_VOID();
2053 : }
2054 :
2055 : /* Reset SLRU counters (a specific one or all of them). */
2056 : Datum
2057 8 : pg_stat_reset_slru(PG_FUNCTION_ARGS)
2058 : {
2059 8 : char *target = NULL;
2060 :
2061 8 : if (PG_ARGISNULL(0))
2062 4 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
2063 : else
2064 : {
2065 4 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
2066 4 : pgstat_reset_slru(target);
2067 : }
2068 :
2069 8 : PG_RETURN_VOID();
2070 : }
2071 :
2072 : /* Reset replication slots stats (a specific one or all of them). */
2073 : Datum
2074 6 : pg_stat_reset_replication_slot(PG_FUNCTION_ARGS)
2075 : {
2076 6 : char *target = NULL;
2077 :
2078 6 : if (PG_ARGISNULL(0))
2079 2 : pgstat_reset_of_kind(PGSTAT_KIND_REPLSLOT);
2080 : else
2081 : {
2082 4 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
2083 4 : pgstat_reset_replslot(target);
2084 : }
2085 :
2086 5 : PG_RETURN_VOID();
2087 : }
2088 :
2089 : /* Reset subscription stats (a specific one or all of them) */
2090 : Datum
2091 12 : pg_stat_reset_subscription_stats(PG_FUNCTION_ARGS)
2092 : {
2093 : Oid subid;
2094 :
2095 12 : if (PG_ARGISNULL(0))
2096 : {
2097 : /* Clear all subscription stats */
2098 2 : pgstat_reset_of_kind(PGSTAT_KIND_SUBSCRIPTION);
2099 : }
2100 : else
2101 : {
2102 10 : subid = PG_GETARG_OID(0);
2103 :
2104 10 : if (!OidIsValid(subid))
2105 0 : ereport(ERROR,
2106 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2107 : errmsg("invalid subscription OID %u", subid)));
2108 10 : pgstat_reset(PGSTAT_KIND_SUBSCRIPTION, InvalidOid, subid);
2109 : }
2110 :
2111 12 : PG_RETURN_VOID();
2112 : }
2113 :
2114 : Datum
2115 20 : pg_stat_get_archiver(PG_FUNCTION_ARGS)
2116 : {
2117 : TupleDesc tupdesc;
2118 20 : Datum values[7] = {0};
2119 20 : bool nulls[7] = {0};
2120 : PgStat_ArchiverStats *archiver_stats;
2121 :
2122 : /* Initialise attributes information in the tuple descriptor */
2123 20 : tupdesc = CreateTemplateTupleDesc(7);
2124 20 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count",
2125 : INT8OID, -1, 0);
2126 20 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
2127 : TEXTOID, -1, 0);
2128 20 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time",
2129 : TIMESTAMPTZOID, -1, 0);
2130 20 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count",
2131 : INT8OID, -1, 0);
2132 20 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
2133 : TEXTOID, -1, 0);
2134 20 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time",
2135 : TIMESTAMPTZOID, -1, 0);
2136 20 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset",
2137 : TIMESTAMPTZOID, -1, 0);
2138 :
2139 20 : TupleDescFinalize(tupdesc);
2140 20 : BlessTupleDesc(tupdesc);
2141 :
2142 : /* Get statistics about the archiver process */
2143 20 : archiver_stats = pgstat_fetch_stat_archiver();
2144 :
2145 : /* Fill values and NULLs */
2146 20 : values[0] = Int64GetDatum(archiver_stats->archived_count);
2147 20 : if (*(archiver_stats->last_archived_wal) == '\0')
2148 9 : nulls[1] = true;
2149 : else
2150 11 : values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
2151 :
2152 20 : if (archiver_stats->last_archived_timestamp == 0)
2153 9 : nulls[2] = true;
2154 : else
2155 11 : values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp);
2156 :
2157 20 : values[3] = Int64GetDatum(archiver_stats->failed_count);
2158 20 : if (*(archiver_stats->last_failed_wal) == '\0')
2159 13 : nulls[4] = true;
2160 : else
2161 7 : values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
2162 :
2163 20 : if (archiver_stats->last_failed_timestamp == 0)
2164 13 : nulls[5] = true;
2165 : else
2166 7 : values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp);
2167 :
2168 20 : if (archiver_stats->stat_reset_timestamp == 0)
2169 0 : nulls[6] = true;
2170 : else
2171 20 : values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
2172 :
2173 : /* Returns the record as Datum */
2174 20 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
2175 : }
2176 :
2177 : /*
2178 : * Get the statistics for the replication slot. If the slot statistics is not
2179 : * available, return all-zeroes stats.
2180 : */
2181 : Datum
2182 52 : pg_stat_get_replication_slot(PG_FUNCTION_ARGS)
2183 : {
2184 : #define PG_STAT_GET_REPLICATION_SLOT_COLS 13
2185 52 : text *slotname_text = PG_GETARG_TEXT_P(0);
2186 : NameData slotname;
2187 : TupleDesc tupdesc;
2188 52 : Datum values[PG_STAT_GET_REPLICATION_SLOT_COLS] = {0};
2189 52 : bool nulls[PG_STAT_GET_REPLICATION_SLOT_COLS] = {0};
2190 : PgStat_StatReplSlotEntry *slotent;
2191 : PgStat_StatReplSlotEntry allzero;
2192 :
2193 : /* Initialise attributes information in the tuple descriptor */
2194 52 : tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_REPLICATION_SLOT_COLS);
2195 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "slot_name",
2196 : TEXTOID, -1, 0);
2197 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "spill_txns",
2198 : INT8OID, -1, 0);
2199 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "spill_count",
2200 : INT8OID, -1, 0);
2201 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "spill_bytes",
2202 : INT8OID, -1, 0);
2203 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "stream_txns",
2204 : INT8OID, -1, 0);
2205 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "stream_count",
2206 : INT8OID, -1, 0);
2207 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stream_bytes",
2208 : INT8OID, -1, 0);
2209 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 8, "mem_exceeded_count",
2210 : INT8OID, -1, 0);
2211 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 9, "total_txns",
2212 : INT8OID, -1, 0);
2213 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 10, "total_bytes",
2214 : INT8OID, -1, 0);
2215 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 11, "slotsync_skip_count",
2216 : INT8OID, -1, 0);
2217 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 12, "slotsync_last_skip",
2218 : TIMESTAMPTZOID, -1, 0);
2219 52 : TupleDescInitEntry(tupdesc, (AttrNumber) 13, "stats_reset",
2220 : TIMESTAMPTZOID, -1, 0);
2221 52 : TupleDescFinalize(tupdesc);
2222 52 : BlessTupleDesc(tupdesc);
2223 :
2224 52 : namestrcpy(&slotname, text_to_cstring(slotname_text));
2225 52 : slotent = pgstat_fetch_replslot(slotname);
2226 52 : if (!slotent)
2227 : {
2228 : /*
2229 : * If the slot is not found, initialise its stats. This is possible if
2230 : * the create slot message is lost.
2231 : */
2232 2 : memset(&allzero, 0, sizeof(PgStat_StatReplSlotEntry));
2233 2 : slotent = &allzero;
2234 : }
2235 :
2236 52 : values[0] = CStringGetTextDatum(NameStr(slotname));
2237 52 : values[1] = Int64GetDatum(slotent->spill_txns);
2238 52 : values[2] = Int64GetDatum(slotent->spill_count);
2239 52 : values[3] = Int64GetDatum(slotent->spill_bytes);
2240 52 : values[4] = Int64GetDatum(slotent->stream_txns);
2241 52 : values[5] = Int64GetDatum(slotent->stream_count);
2242 52 : values[6] = Int64GetDatum(slotent->stream_bytes);
2243 52 : values[7] = Int64GetDatum(slotent->mem_exceeded_count);
2244 52 : values[8] = Int64GetDatum(slotent->total_txns);
2245 52 : values[9] = Int64GetDatum(slotent->total_bytes);
2246 52 : values[10] = Int64GetDatum(slotent->slotsync_skip_count);
2247 :
2248 52 : if (slotent->slotsync_last_skip == 0)
2249 51 : nulls[11] = true;
2250 : else
2251 1 : values[11] = TimestampTzGetDatum(slotent->slotsync_last_skip);
2252 :
2253 52 : if (slotent->stat_reset_timestamp == 0)
2254 28 : nulls[12] = true;
2255 : else
2256 24 : values[12] = TimestampTzGetDatum(slotent->stat_reset_timestamp);
2257 :
2258 : /* Returns the record as Datum */
2259 52 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
2260 : }
2261 :
2262 : /*
2263 : * Get the subscription statistics for the given subscription. If the
2264 : * subscription statistics is not available, return all-zeros stats.
2265 : */
2266 : Datum
2267 39 : pg_stat_get_subscription_stats(PG_FUNCTION_ARGS)
2268 : {
2269 : #define PG_STAT_GET_SUBSCRIPTION_STATS_COLS 13
2270 39 : Oid subid = PG_GETARG_OID(0);
2271 : TupleDesc tupdesc;
2272 39 : Datum values[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
2273 39 : bool nulls[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
2274 : PgStat_StatSubEntry *subentry;
2275 : PgStat_StatSubEntry allzero;
2276 39 : int i = 0;
2277 :
2278 : /* Get subscription stats */
2279 39 : subentry = pgstat_fetch_stat_subscription(subid);
2280 :
2281 : /* Initialise attributes information in the tuple descriptor */
2282 39 : tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_SUBSCRIPTION_STATS_COLS);
2283 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "subid",
2284 : OIDOID, -1, 0);
2285 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "apply_error_count",
2286 : INT8OID, -1, 0);
2287 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "sync_seq_error_count",
2288 : INT8OID, -1, 0);
2289 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "sync_table_error_count",
2290 : INT8OID, -1, 0);
2291 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "confl_insert_exists",
2292 : INT8OID, -1, 0);
2293 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "confl_update_origin_differs",
2294 : INT8OID, -1, 0);
2295 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "confl_update_exists",
2296 : INT8OID, -1, 0);
2297 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 8, "confl_update_deleted",
2298 : INT8OID, -1, 0);
2299 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 9, "confl_update_missing",
2300 : INT8OID, -1, 0);
2301 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 10, "confl_delete_origin_differs",
2302 : INT8OID, -1, 0);
2303 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 11, "confl_delete_missing",
2304 : INT8OID, -1, 0);
2305 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 12, "confl_multiple_unique_conflicts",
2306 : INT8OID, -1, 0);
2307 39 : TupleDescInitEntry(tupdesc, (AttrNumber) 13, "stats_reset",
2308 : TIMESTAMPTZOID, -1, 0);
2309 39 : TupleDescFinalize(tupdesc);
2310 39 : BlessTupleDesc(tupdesc);
2311 :
2312 39 : if (!subentry)
2313 : {
2314 : /* If the subscription is not found, initialise its stats */
2315 0 : memset(&allzero, 0, sizeof(PgStat_StatSubEntry));
2316 0 : subentry = &allzero;
2317 : }
2318 :
2319 : /* subid */
2320 39 : values[i++] = ObjectIdGetDatum(subid);
2321 :
2322 : /* apply_error_count */
2323 39 : values[i++] = Int64GetDatum(subentry->apply_error_count);
2324 :
2325 : /* sync_seq_error_count */
2326 39 : values[i++] = Int64GetDatum(subentry->sync_seq_error_count);
2327 :
2328 : /* sync_table_error_count */
2329 39 : values[i++] = Int64GetDatum(subentry->sync_table_error_count);
2330 :
2331 : /* conflict count */
2332 351 : for (int nconflict = 0; nconflict < CONFLICT_NUM_TYPES; nconflict++)
2333 312 : values[i++] = Int64GetDatum(subentry->conflict_count[nconflict]);
2334 :
2335 : /* stats_reset */
2336 39 : if (subentry->stat_reset_timestamp == 0)
2337 17 : nulls[i] = true;
2338 : else
2339 22 : values[i] = TimestampTzGetDatum(subentry->stat_reset_timestamp);
2340 :
2341 : Assert(i + 1 == PG_STAT_GET_SUBSCRIPTION_STATS_COLS);
2342 :
2343 : /* Returns the record as Datum */
2344 39 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
2345 : }
2346 :
2347 : /*
2348 : * Checks for presence of stats for object with provided kind, database oid,
2349 : * object oid.
2350 : *
2351 : * This is useful for tests, but not really anything else. Therefore not
2352 : * documented.
2353 : */
2354 : Datum
2355 99 : pg_stat_have_stats(PG_FUNCTION_ARGS)
2356 : {
2357 99 : char *stats_type = text_to_cstring(PG_GETARG_TEXT_P(0));
2358 99 : Oid dboid = PG_GETARG_OID(1);
2359 99 : uint64 objid = PG_GETARG_INT64(2);
2360 99 : PgStat_Kind kind = pgstat_get_kind_from_str(stats_type);
2361 :
2362 95 : PG_RETURN_BOOL(pgstat_have_entry(kind, dboid, objid));
2363 : }
|