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