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 170 : 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 14 : 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 8326 : 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 104 : 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 104 : 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 104 : funcctx = SRF_PERCALL_SETUP();
245 104 : fctx = funcctx->user_fctx;
246 :
247 104 : 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 104 : if (fctx[0] <= pgstat_fetch_stat_numbackends())
259 : {
260 : /* do when there is more left to send */
261 98 : LocalPgBackendStatus *local_beentry = pgstat_get_local_beentry_by_index(fctx[0]);
262 :
263 98 : 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 2136 : pg_stat_get_activity(PG_FUNCTION_ARGS)
353 : {
354 : #define PG_STAT_GET_ACTIVITY_COLS 31
355 2136 : int num_backends = pgstat_fetch_stat_numbackends();
356 : int curr_backend;
357 2136 : int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
358 2136 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
359 :
360 2136 : InitMaterializedSRF(fcinfo, 0);
361 :
362 : /* 1-based index */
363 25076 : for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
364 : {
365 : /* for each row */
366 22942 : Datum values[PG_STAT_GET_ACTIVITY_COLS] = {0};
367 22942 : bool nulls[PG_STAT_GET_ACTIVITY_COLS] = {0};
368 : LocalPgBackendStatus *local_beentry;
369 : PgBackendStatus *beentry;
370 : PGPROC *proc;
371 22942 : const char *wait_event_type = NULL;
372 22942 : const char *wait_event = NULL;
373 :
374 : /* Get the next one in the list */
375 22942 : local_beentry = pgstat_get_local_beentry_by_index(curr_backend);
376 22942 : beentry = &local_beentry->backendStatus;
377 :
378 : /* If looking for specific PID, ignore all the others */
379 22942 : if (pid != -1 && beentry->st_procpid != pid)
380 0 : continue;
381 :
382 : /* Values available to all callers */
383 22942 : if (beentry->st_databaseid != InvalidOid)
384 4080 : values[0] = ObjectIdGetDatum(beentry->st_databaseid);
385 : else
386 18862 : nulls[0] = true;
387 :
388 22942 : values[1] = Int32GetDatum(beentry->st_procpid);
389 :
390 22942 : if (beentry->st_userid != InvalidOid)
391 7078 : values[2] = ObjectIdGetDatum(beentry->st_userid);
392 : else
393 15864 : nulls[2] = true;
394 :
395 22942 : if (beentry->st_appname)
396 22942 : values[3] = CStringGetTextDatum(beentry->st_appname);
397 : else
398 0 : nulls[3] = true;
399 :
400 22942 : if (TransactionIdIsValid(local_beentry->backend_xid))
401 170 : values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
402 : else
403 22772 : nulls[15] = true;
404 :
405 22942 : if (TransactionIdIsValid(local_beentry->backend_xmin))
406 2468 : values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
407 : else
408 20474 : nulls[16] = true;
409 :
410 : /* Values only available to role member or pg_read_all_stats */
411 22942 : if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
412 22172 : {
413 : char *clipped_activity;
414 :
415 22172 : switch (beentry->st_state)
416 : {
417 2 : case STATE_STARTING:
418 2 : values[4] = CStringGetTextDatum("starting");
419 2 : break;
420 372 : case STATE_IDLE:
421 372 : values[4] = CStringGetTextDatum("idle");
422 372 : break;
423 4536 : case STATE_RUNNING:
424 4536 : values[4] = CStringGetTextDatum("active");
425 4536 : break;
426 52 : case STATE_IDLEINTRANSACTION:
427 52 : values[4] = CStringGetTextDatum("idle in transaction");
428 52 : 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 17204 : case STATE_UNDEFINED:
439 17204 : nulls[4] = true;
440 17204 : break;
441 : }
442 :
443 22172 : clipped_activity = pgstat_clip_activity(beentry->st_activity_raw);
444 22172 : values[5] = CStringGetTextDatum(clipped_activity);
445 22172 : pfree(clipped_activity);
446 :
447 : /* leader_pid */
448 22172 : nulls[29] = true;
449 :
450 22172 : proc = BackendPidGetProc(beentry->st_procpid);
451 :
452 22172 : 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 13372 : 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 22172 : if (proc != NULL)
468 : {
469 : uint32 raw_wait_event;
470 : PGPROC *leader;
471 :
472 22172 : raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
473 22172 : wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
474 22172 : wait_event = pgstat_get_wait_event(raw_wait_event);
475 :
476 22172 : 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 22172 : if (leader && leader->pid != beentry->st_procpid)
484 : {
485 0 : values[29] = Int32GetDatum(leader->pid);
486 0 : nulls[29] = false;
487 : }
488 22172 : else if (beentry->st_backendType == B_BG_WORKER)
489 : {
490 2148 : int leader_pid = GetLeaderApplyWorkerPid(beentry->st_procpid);
491 :
492 2148 : if (leader_pid != InvalidPid)
493 : {
494 0 : values[29] = Int32GetDatum(leader_pid);
495 0 : nulls[29] = false;
496 : }
497 : }
498 : }
499 :
500 22172 : if (wait_event_type)
501 19796 : values[6] = CStringGetTextDatum(wait_event_type);
502 : else
503 2376 : nulls[6] = true;
504 :
505 22172 : if (wait_event)
506 19796 : values[7] = CStringGetTextDatum(wait_event);
507 : else
508 2376 : 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 22172 : if (beentry->st_xact_start_timestamp != 0 &&
516 2562 : beentry->st_backendType != B_WAL_SENDER)
517 2548 : values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
518 : else
519 19624 : nulls[8] = true;
520 :
521 22172 : if (beentry->st_activity_start_timestamp != 0)
522 4832 : values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
523 : else
524 17340 : nulls[9] = true;
525 :
526 22172 : if (beentry->st_proc_start_timestamp != 0)
527 22172 : values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
528 : else
529 0 : nulls[10] = true;
530 :
531 22172 : if (beentry->st_state_start_timestamp != 0)
532 4960 : values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
533 : else
534 17212 : nulls[11] = true;
535 :
536 : /* A zeroed client addr means we don't know */
537 22172 : if (pg_memory_is_all_zeros(&beentry->st_clientaddr,
538 : sizeof(beentry->st_clientaddr)))
539 : {
540 17338 : nulls[12] = true;
541 17338 : nulls[13] = true;
542 17338 : nulls[14] = true;
543 : }
544 : else
545 : {
546 4834 : if (beentry->st_clientaddr.addr.ss_family == AF_INET ||
547 4744 : 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 4744 : 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 4744 : nulls[12] = true;
588 4744 : nulls[13] = true;
589 4744 : 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 22172 : if (beentry->st_backendType == B_BG_WORKER)
601 : {
602 : const char *bgw_type;
603 :
604 2148 : bgw_type = GetBackgroundWorkerTypeByPid(beentry->st_procpid);
605 2148 : if (bgw_type)
606 2148 : values[17] = CStringGetTextDatum(bgw_type);
607 : else
608 0 : nulls[17] = true;
609 : }
610 : else
611 20024 : values[17] =
612 20024 : CStringGetTextDatum(GetBackendTypeDesc(beentry->st_backendType));
613 :
614 : /* SSL information */
615 22172 : 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 22130 : values[18] = BoolGetDatum(false); /* ssl */
643 22130 : nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = true;
644 : }
645 :
646 : /* GSSAPI information */
647 22172 : 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 22172 : values[25] = BoolGetDatum(false); /* gss_auth */
658 22172 : nulls[26] = true; /* No GSS principal */
659 22172 : values[27] = BoolGetDatum(false); /* GSS Encryption not in
660 : * use */
661 22172 : values[28] = BoolGetDatum(false); /* GSS credentials not
662 : * delegated */
663 : }
664 22172 : if (beentry->st_query_id == INT64CONST(0))
665 21750 : nulls[30] = true;
666 : else
667 422 : 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 22942 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
700 :
701 : /* If only a single backend was requested, and we found it, break. */
702 22942 : if (pid != -1)
703 2 : break;
704 : }
705 :
706 2136 : return (Datum) 0;
707 : }
708 :
709 :
710 : Datum
711 1914 : pg_backend_pid(PG_FUNCTION_ARGS)
712 : {
713 1914 : PG_RETURN_INT32(MyProcPid);
714 : }
715 :
716 :
717 : Datum
718 98 : pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
719 : {
720 98 : int32 procNumber = PG_GETARG_INT32(0);
721 : PgBackendStatus *beentry;
722 :
723 98 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
724 0 : PG_RETURN_NULL();
725 :
726 98 : 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 5
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_buffers_full",
1655 : INT8OID, -1, 0);
1656 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "stats_reset",
1657 : TIMESTAMPTZOID, -1, 0);
1658 :
1659 82 : BlessTupleDesc(tupdesc);
1660 :
1661 : /* Fill values and NULLs */
1662 82 : values[0] = Int64GetDatum(wal_counters.wal_records);
1663 82 : values[1] = Int64GetDatum(wal_counters.wal_fpi);
1664 :
1665 : /* Convert to numeric. */
1666 82 : snprintf(buf, sizeof buf, UINT64_FORMAT, wal_counters.wal_bytes);
1667 82 : values[2] = DirectFunctionCall3(numeric_in,
1668 : CStringGetDatum(buf),
1669 : ObjectIdGetDatum(0),
1670 : Int32GetDatum(-1));
1671 :
1672 82 : values[3] = Int64GetDatum(wal_counters.wal_buffers_full);
1673 :
1674 82 : if (stat_reset_timestamp != 0)
1675 70 : values[4] = TimestampTzGetDatum(stat_reset_timestamp);
1676 : else
1677 12 : nulls[4] = true;
1678 :
1679 : /* Returns the record as Datum */
1680 82 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
1681 : }
1682 :
1683 : /*
1684 : * Returns WAL statistics for a backend with given PID.
1685 : */
1686 : Datum
1687 12 : pg_stat_get_backend_wal(PG_FUNCTION_ARGS)
1688 : {
1689 : int pid;
1690 : PgStat_Backend *backend_stats;
1691 : PgStat_WalCounters bktype_stats;
1692 :
1693 12 : pid = PG_GETARG_INT32(0);
1694 12 : backend_stats = pgstat_fetch_stat_backend_by_pid(pid, NULL);
1695 :
1696 12 : if (!backend_stats)
1697 0 : PG_RETURN_NULL();
1698 :
1699 12 : bktype_stats = backend_stats->wal_counters;
1700 :
1701 : /* save tuples with data from this PgStat_WalCounters */
1702 12 : return (pg_stat_wal_build_tuple(bktype_stats, backend_stats->stat_reset_timestamp));
1703 : }
1704 :
1705 : /*
1706 : * Returns statistics of WAL activity
1707 : */
1708 : Datum
1709 70 : pg_stat_get_wal(PG_FUNCTION_ARGS)
1710 : {
1711 : PgStat_WalStats *wal_stats;
1712 :
1713 : /* Get statistics about WAL activity */
1714 70 : wal_stats = pgstat_fetch_stat_wal();
1715 :
1716 70 : return (pg_stat_wal_build_tuple(wal_stats->wal_counters,
1717 : wal_stats->stat_reset_timestamp));
1718 : }
1719 :
1720 : /*
1721 : * Returns statistics of SLRU caches.
1722 : */
1723 : Datum
1724 124 : pg_stat_get_slru(PG_FUNCTION_ARGS)
1725 : {
1726 : #define PG_STAT_GET_SLRU_COLS 9
1727 124 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1728 : int i;
1729 : PgStat_SLRUStats *stats;
1730 :
1731 124 : InitMaterializedSRF(fcinfo, 0);
1732 :
1733 : /* request SLRU stats from the cumulative stats system */
1734 124 : stats = pgstat_fetch_slru();
1735 :
1736 124 : for (i = 0;; i++)
1737 992 : {
1738 : /* for each row */
1739 1116 : Datum values[PG_STAT_GET_SLRU_COLS] = {0};
1740 1116 : bool nulls[PG_STAT_GET_SLRU_COLS] = {0};
1741 : PgStat_SLRUStats stat;
1742 : const char *name;
1743 :
1744 1116 : name = pgstat_get_slru_name(i);
1745 :
1746 1116 : if (!name)
1747 124 : break;
1748 :
1749 992 : stat = stats[i];
1750 :
1751 992 : values[0] = PointerGetDatum(cstring_to_text(name));
1752 992 : values[1] = Int64GetDatum(stat.blocks_zeroed);
1753 992 : values[2] = Int64GetDatum(stat.blocks_hit);
1754 992 : values[3] = Int64GetDatum(stat.blocks_read);
1755 992 : values[4] = Int64GetDatum(stat.blocks_written);
1756 992 : values[5] = Int64GetDatum(stat.blocks_exists);
1757 992 : values[6] = Int64GetDatum(stat.flush);
1758 992 : values[7] = Int64GetDatum(stat.truncate);
1759 992 : values[8] = TimestampTzGetDatum(stat.stat_reset_timestamp);
1760 :
1761 992 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1762 : }
1763 :
1764 124 : return (Datum) 0;
1765 : }
1766 :
1767 : #define PG_STAT_GET_XACT_RELENTRY_INT64(stat) \
1768 : Datum \
1769 : CppConcat(pg_stat_get_xact_,stat)(PG_FUNCTION_ARGS) \
1770 : { \
1771 : Oid relid = PG_GETARG_OID(0); \
1772 : int64 result; \
1773 : PgStat_TableStatus *tabentry; \
1774 : \
1775 : if ((tabentry = find_tabstat_entry(relid)) == NULL) \
1776 : result = 0; \
1777 : else \
1778 : result = (int64) (tabentry->counts.stat); \
1779 : \
1780 : PG_RETURN_INT64(result); \
1781 : }
1782 :
1783 : /* pg_stat_get_xact_numscans */
1784 0 : PG_STAT_GET_XACT_RELENTRY_INT64(numscans)
1785 :
1786 : /* pg_stat_get_xact_tuples_returned */
1787 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_returned)
1788 :
1789 : /* pg_stat_get_xact_tuples_fetched */
1790 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_fetched)
1791 :
1792 : /* pg_stat_get_xact_tuples_hot_updated */
1793 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_hot_updated)
1794 :
1795 : /* pg_stat_get_xact_tuples_newpage_updated */
1796 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_newpage_updated)
1797 :
1798 : /* pg_stat_get_xact_blocks_fetched */
1799 0 : PG_STAT_GET_XACT_RELENTRY_INT64(blocks_fetched)
1800 :
1801 : /* pg_stat_get_xact_blocks_hit */
1802 0 : PG_STAT_GET_XACT_RELENTRY_INT64(blocks_hit)
1803 :
1804 : /* pg_stat_get_xact_tuples_inserted */
1805 48 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_inserted)
1806 :
1807 : /* pg_stat_get_xact_tuples_updated */
1808 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_updated)
1809 :
1810 : /* pg_stat_get_xact_tuples_deleted */
1811 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_deleted)
1812 :
1813 : Datum
1814 24 : pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
1815 : {
1816 24 : Oid funcid = PG_GETARG_OID(0);
1817 : PgStat_FunctionCounts *funcentry;
1818 :
1819 24 : if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1820 6 : PG_RETURN_NULL();
1821 18 : PG_RETURN_INT64(funcentry->numcalls);
1822 : }
1823 :
1824 : #define PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(stat) \
1825 : Datum \
1826 : CppConcat(pg_stat_get_xact_function_,stat)(PG_FUNCTION_ARGS) \
1827 : { \
1828 : Oid funcid = PG_GETARG_OID(0); \
1829 : PgStat_FunctionCounts *funcentry; \
1830 : \
1831 : if ((funcentry = find_funcstat_entry(funcid)) == NULL) \
1832 : PG_RETURN_NULL(); \
1833 : PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->stat)); \
1834 : }
1835 :
1836 : /* pg_stat_get_xact_function_total_time */
1837 0 : PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(total_time)
1838 :
1839 : /* pg_stat_get_xact_function_self_time */
1840 0 : PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(self_time)
1841 :
1842 : /* Get the timestamp of the current statistics snapshot */
1843 : Datum
1844 60 : pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS)
1845 : {
1846 : bool have_snapshot;
1847 : TimestampTz ts;
1848 :
1849 60 : ts = pgstat_get_stat_snapshot_timestamp(&have_snapshot);
1850 :
1851 60 : if (!have_snapshot)
1852 36 : PG_RETURN_NULL();
1853 :
1854 24 : PG_RETURN_TIMESTAMPTZ(ts);
1855 : }
1856 :
1857 : /* Discard the active statistics snapshot */
1858 : Datum
1859 16 : pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
1860 : {
1861 16 : pgstat_clear_snapshot();
1862 :
1863 16 : PG_RETURN_VOID();
1864 : }
1865 :
1866 :
1867 : /* Force statistics to be reported at the next occasion */
1868 : Datum
1869 484 : pg_stat_force_next_flush(PG_FUNCTION_ARGS)
1870 : {
1871 484 : pgstat_force_next_flush();
1872 :
1873 484 : PG_RETURN_VOID();
1874 : }
1875 :
1876 :
1877 : /* Reset all counters for the current database */
1878 : Datum
1879 26 : pg_stat_reset(PG_FUNCTION_ARGS)
1880 : {
1881 26 : pgstat_reset_counters();
1882 :
1883 26 : PG_RETURN_VOID();
1884 : }
1885 :
1886 : /*
1887 : * Reset some shared cluster-wide counters
1888 : *
1889 : * When adding a new reset target, ideally the name should match that in
1890 : * pgstat_kind_builtin_infos, if relevant.
1891 : */
1892 : Datum
1893 56 : pg_stat_reset_shared(PG_FUNCTION_ARGS)
1894 : {
1895 56 : char *target = NULL;
1896 :
1897 56 : if (PG_ARGISNULL(0))
1898 : {
1899 : /* Reset all the statistics when nothing is specified */
1900 0 : pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
1901 0 : pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
1902 0 : pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
1903 0 : pgstat_reset_of_kind(PGSTAT_KIND_IO);
1904 0 : XLogPrefetchResetStats();
1905 0 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
1906 0 : pgstat_reset_of_kind(PGSTAT_KIND_WAL);
1907 :
1908 0 : PG_RETURN_VOID();
1909 : }
1910 :
1911 56 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1912 :
1913 56 : if (strcmp(target, "archiver") == 0)
1914 6 : pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
1915 50 : else if (strcmp(target, "bgwriter") == 0)
1916 6 : pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
1917 44 : else if (strcmp(target, "checkpointer") == 0)
1918 8 : pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
1919 36 : else if (strcmp(target, "io") == 0)
1920 10 : pgstat_reset_of_kind(PGSTAT_KIND_IO);
1921 26 : else if (strcmp(target, "recovery_prefetch") == 0)
1922 6 : XLogPrefetchResetStats();
1923 20 : else if (strcmp(target, "slru") == 0)
1924 6 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
1925 14 : else if (strcmp(target, "wal") == 0)
1926 8 : pgstat_reset_of_kind(PGSTAT_KIND_WAL);
1927 : else
1928 6 : ereport(ERROR,
1929 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1930 : errmsg("unrecognized reset target: \"%s\"", target),
1931 : errhint("Target must be \"archiver\", \"bgwriter\", \"checkpointer\", \"io\", \"recovery_prefetch\", \"slru\", or \"wal\".")));
1932 :
1933 50 : PG_RETURN_VOID();
1934 : }
1935 :
1936 : /*
1937 : * Reset a statistics for a single object, which may be of current
1938 : * database or shared across all databases in the cluster.
1939 : */
1940 : Datum
1941 18 : pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
1942 : {
1943 18 : Oid taboid = PG_GETARG_OID(0);
1944 18 : Oid dboid = (IsSharedRelation(taboid) ? InvalidOid : MyDatabaseId);
1945 :
1946 18 : pgstat_reset(PGSTAT_KIND_RELATION, dboid, taboid);
1947 :
1948 18 : PG_RETURN_VOID();
1949 : }
1950 :
1951 : Datum
1952 4 : pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
1953 : {
1954 4 : Oid funcoid = PG_GETARG_OID(0);
1955 :
1956 4 : pgstat_reset(PGSTAT_KIND_FUNCTION, MyDatabaseId, funcoid);
1957 :
1958 4 : PG_RETURN_VOID();
1959 : }
1960 :
1961 : /*
1962 : * Reset statistics of backend with given PID.
1963 : */
1964 : Datum
1965 6 : pg_stat_reset_backend_stats(PG_FUNCTION_ARGS)
1966 : {
1967 : PGPROC *proc;
1968 : PgBackendStatus *beentry;
1969 : ProcNumber procNumber;
1970 6 : int backend_pid = PG_GETARG_INT32(0);
1971 :
1972 6 : proc = BackendPidGetProc(backend_pid);
1973 :
1974 : /* This could be an auxiliary process */
1975 6 : if (!proc)
1976 0 : proc = AuxiliaryPidGetProc(backend_pid);
1977 :
1978 6 : if (!proc)
1979 0 : PG_RETURN_VOID();
1980 :
1981 6 : procNumber = GetNumberFromPGProc(proc);
1982 :
1983 6 : beentry = pgstat_get_beentry_by_proc_number(procNumber);
1984 6 : if (!beentry)
1985 0 : PG_RETURN_VOID();
1986 :
1987 : /* Check if the backend type tracks statistics */
1988 6 : if (!pgstat_tracks_backend_bktype(beentry->st_backendType))
1989 0 : PG_RETURN_VOID();
1990 :
1991 6 : pgstat_reset(PGSTAT_KIND_BACKEND, InvalidOid, procNumber);
1992 :
1993 6 : PG_RETURN_VOID();
1994 : }
1995 :
1996 : /* Reset SLRU counters (a specific one or all of them). */
1997 : Datum
1998 12 : pg_stat_reset_slru(PG_FUNCTION_ARGS)
1999 : {
2000 12 : char *target = NULL;
2001 :
2002 12 : if (PG_ARGISNULL(0))
2003 6 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
2004 : else
2005 : {
2006 6 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
2007 6 : pgstat_reset_slru(target);
2008 : }
2009 :
2010 12 : PG_RETURN_VOID();
2011 : }
2012 :
2013 : /* Reset replication slots stats (a specific one or all of them). */
2014 : Datum
2015 12 : pg_stat_reset_replication_slot(PG_FUNCTION_ARGS)
2016 : {
2017 12 : char *target = NULL;
2018 :
2019 12 : if (PG_ARGISNULL(0))
2020 4 : pgstat_reset_of_kind(PGSTAT_KIND_REPLSLOT);
2021 : else
2022 : {
2023 8 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
2024 8 : pgstat_reset_replslot(target);
2025 : }
2026 :
2027 10 : PG_RETURN_VOID();
2028 : }
2029 :
2030 : /* Reset subscription stats (a specific one or all of them) */
2031 : Datum
2032 20 : pg_stat_reset_subscription_stats(PG_FUNCTION_ARGS)
2033 : {
2034 : Oid subid;
2035 :
2036 20 : if (PG_ARGISNULL(0))
2037 : {
2038 : /* Clear all subscription stats */
2039 4 : pgstat_reset_of_kind(PGSTAT_KIND_SUBSCRIPTION);
2040 : }
2041 : else
2042 : {
2043 16 : subid = PG_GETARG_OID(0);
2044 :
2045 16 : if (!OidIsValid(subid))
2046 0 : ereport(ERROR,
2047 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2048 : errmsg("invalid subscription OID %u", subid)));
2049 16 : pgstat_reset(PGSTAT_KIND_SUBSCRIPTION, InvalidOid, subid);
2050 : }
2051 :
2052 20 : PG_RETURN_VOID();
2053 : }
2054 :
2055 : Datum
2056 54 : pg_stat_get_archiver(PG_FUNCTION_ARGS)
2057 : {
2058 : TupleDesc tupdesc;
2059 54 : Datum values[7] = {0};
2060 54 : bool nulls[7] = {0};
2061 : PgStat_ArchiverStats *archiver_stats;
2062 :
2063 : /* Initialise attributes information in the tuple descriptor */
2064 54 : tupdesc = CreateTemplateTupleDesc(7);
2065 54 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count",
2066 : INT8OID, -1, 0);
2067 54 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
2068 : TEXTOID, -1, 0);
2069 54 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time",
2070 : TIMESTAMPTZOID, -1, 0);
2071 54 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count",
2072 : INT8OID, -1, 0);
2073 54 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
2074 : TEXTOID, -1, 0);
2075 54 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time",
2076 : TIMESTAMPTZOID, -1, 0);
2077 54 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset",
2078 : TIMESTAMPTZOID, -1, 0);
2079 :
2080 54 : BlessTupleDesc(tupdesc);
2081 :
2082 : /* Get statistics about the archiver process */
2083 54 : archiver_stats = pgstat_fetch_stat_archiver();
2084 :
2085 : /* Fill values and NULLs */
2086 54 : values[0] = Int64GetDatum(archiver_stats->archived_count);
2087 54 : if (*(archiver_stats->last_archived_wal) == '\0')
2088 18 : nulls[1] = true;
2089 : else
2090 36 : values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
2091 :
2092 54 : if (archiver_stats->last_archived_timestamp == 0)
2093 18 : nulls[2] = true;
2094 : else
2095 36 : values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp);
2096 :
2097 54 : values[3] = Int64GetDatum(archiver_stats->failed_count);
2098 54 : if (*(archiver_stats->last_failed_wal) == '\0')
2099 36 : nulls[4] = true;
2100 : else
2101 18 : values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
2102 :
2103 54 : if (archiver_stats->last_failed_timestamp == 0)
2104 36 : nulls[5] = true;
2105 : else
2106 18 : values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp);
2107 :
2108 54 : if (archiver_stats->stat_reset_timestamp == 0)
2109 0 : nulls[6] = true;
2110 : else
2111 54 : values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
2112 :
2113 : /* Returns the record as Datum */
2114 54 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
2115 : }
2116 :
2117 : /*
2118 : * Get the statistics for the replication slot. If the slot statistics is not
2119 : * available, return all-zeroes stats.
2120 : */
2121 : Datum
2122 102 : pg_stat_get_replication_slot(PG_FUNCTION_ARGS)
2123 : {
2124 : #define PG_STAT_GET_REPLICATION_SLOT_COLS 11
2125 102 : text *slotname_text = PG_GETARG_TEXT_P(0);
2126 : NameData slotname;
2127 : TupleDesc tupdesc;
2128 102 : Datum values[PG_STAT_GET_REPLICATION_SLOT_COLS] = {0};
2129 102 : bool nulls[PG_STAT_GET_REPLICATION_SLOT_COLS] = {0};
2130 : PgStat_StatReplSlotEntry *slotent;
2131 : PgStat_StatReplSlotEntry allzero;
2132 :
2133 : /* Initialise attributes information in the tuple descriptor */
2134 102 : tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_REPLICATION_SLOT_COLS);
2135 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "slot_name",
2136 : TEXTOID, -1, 0);
2137 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "spill_txns",
2138 : INT8OID, -1, 0);
2139 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "spill_count",
2140 : INT8OID, -1, 0);
2141 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "spill_bytes",
2142 : INT8OID, -1, 0);
2143 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "stream_txns",
2144 : INT8OID, -1, 0);
2145 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "stream_count",
2146 : INT8OID, -1, 0);
2147 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stream_bytes",
2148 : INT8OID, -1, 0);
2149 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 8, "mem_exceeded_count",
2150 : INT8OID, -1, 0);
2151 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 9, "total_txns",
2152 : INT8OID, -1, 0);
2153 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 10, "total_bytes",
2154 : INT8OID, -1, 0);
2155 102 : TupleDescInitEntry(tupdesc, (AttrNumber) 11, "stats_reset",
2156 : TIMESTAMPTZOID, -1, 0);
2157 102 : BlessTupleDesc(tupdesc);
2158 :
2159 102 : namestrcpy(&slotname, text_to_cstring(slotname_text));
2160 102 : slotent = pgstat_fetch_replslot(slotname);
2161 102 : if (!slotent)
2162 : {
2163 : /*
2164 : * If the slot is not found, initialise its stats. This is possible if
2165 : * the create slot message is lost.
2166 : */
2167 4 : memset(&allzero, 0, sizeof(PgStat_StatReplSlotEntry));
2168 4 : slotent = &allzero;
2169 : }
2170 :
2171 102 : values[0] = CStringGetTextDatum(NameStr(slotname));
2172 102 : values[1] = Int64GetDatum(slotent->spill_txns);
2173 102 : values[2] = Int64GetDatum(slotent->spill_count);
2174 102 : values[3] = Int64GetDatum(slotent->spill_bytes);
2175 102 : values[4] = Int64GetDatum(slotent->stream_txns);
2176 102 : values[5] = Int64GetDatum(slotent->stream_count);
2177 102 : values[6] = Int64GetDatum(slotent->stream_bytes);
2178 102 : values[7] = Int64GetDatum(slotent->mem_exceeded_count);
2179 102 : values[8] = Int64GetDatum(slotent->total_txns);
2180 102 : values[9] = Int64GetDatum(slotent->total_bytes);
2181 :
2182 102 : if (slotent->stat_reset_timestamp == 0)
2183 54 : nulls[10] = true;
2184 : else
2185 48 : values[10] = TimestampTzGetDatum(slotent->stat_reset_timestamp);
2186 :
2187 : /* Returns the record as Datum */
2188 102 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
2189 : }
2190 :
2191 : /*
2192 : * Get the subscription statistics for the given subscription. If the
2193 : * subscription statistics is not available, return all-zeros stats.
2194 : */
2195 : Datum
2196 70 : pg_stat_get_subscription_stats(PG_FUNCTION_ARGS)
2197 : {
2198 : #define PG_STAT_GET_SUBSCRIPTION_STATS_COLS 12
2199 70 : Oid subid = PG_GETARG_OID(0);
2200 : TupleDesc tupdesc;
2201 70 : Datum values[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
2202 70 : bool nulls[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
2203 : PgStat_StatSubEntry *subentry;
2204 : PgStat_StatSubEntry allzero;
2205 70 : int i = 0;
2206 :
2207 : /* Get subscription stats */
2208 70 : subentry = pgstat_fetch_stat_subscription(subid);
2209 :
2210 : /* Initialise attributes information in the tuple descriptor */
2211 70 : tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_SUBSCRIPTION_STATS_COLS);
2212 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "subid",
2213 : OIDOID, -1, 0);
2214 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "apply_error_count",
2215 : INT8OID, -1, 0);
2216 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "sync_error_count",
2217 : INT8OID, -1, 0);
2218 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "confl_insert_exists",
2219 : INT8OID, -1, 0);
2220 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "confl_update_origin_differs",
2221 : INT8OID, -1, 0);
2222 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "confl_update_exists",
2223 : INT8OID, -1, 0);
2224 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "confl_update_deleted",
2225 : INT8OID, -1, 0);
2226 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 8, "confl_update_missing",
2227 : INT8OID, -1, 0);
2228 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 9, "confl_delete_origin_differs",
2229 : INT8OID, -1, 0);
2230 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 10, "confl_delete_missing",
2231 : INT8OID, -1, 0);
2232 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 11, "confl_multiple_unique_conflicts",
2233 : INT8OID, -1, 0);
2234 70 : TupleDescInitEntry(tupdesc, (AttrNumber) 12, "stats_reset",
2235 : TIMESTAMPTZOID, -1, 0);
2236 70 : BlessTupleDesc(tupdesc);
2237 :
2238 70 : if (!subentry)
2239 : {
2240 : /* If the subscription is not found, initialise its stats */
2241 0 : memset(&allzero, 0, sizeof(PgStat_StatSubEntry));
2242 0 : subentry = &allzero;
2243 : }
2244 :
2245 : /* subid */
2246 70 : values[i++] = ObjectIdGetDatum(subid);
2247 :
2248 : /* apply_error_count */
2249 70 : values[i++] = Int64GetDatum(subentry->apply_error_count);
2250 :
2251 : /* sync_error_count */
2252 70 : values[i++] = Int64GetDatum(subentry->sync_error_count);
2253 :
2254 : /* conflict count */
2255 630 : for (int nconflict = 0; nconflict < CONFLICT_NUM_TYPES; nconflict++)
2256 560 : values[i++] = Int64GetDatum(subentry->conflict_count[nconflict]);
2257 :
2258 : /* stats_reset */
2259 70 : if (subentry->stat_reset_timestamp == 0)
2260 32 : nulls[i] = true;
2261 : else
2262 38 : values[i] = TimestampTzGetDatum(subentry->stat_reset_timestamp);
2263 :
2264 : Assert(i + 1 == PG_STAT_GET_SUBSCRIPTION_STATS_COLS);
2265 :
2266 : /* Returns the record as Datum */
2267 70 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
2268 : }
2269 :
2270 : /*
2271 : * Checks for presence of stats for object with provided kind, database oid,
2272 : * object oid.
2273 : *
2274 : * This is useful for tests, but not really anything else. Therefore not
2275 : * documented.
2276 : */
2277 : Datum
2278 166 : pg_stat_have_stats(PG_FUNCTION_ARGS)
2279 : {
2280 166 : char *stats_type = text_to_cstring(PG_GETARG_TEXT_P(0));
2281 166 : Oid dboid = PG_GETARG_OID(1);
2282 166 : uint64 objid = PG_GETARG_INT64(2);
2283 166 : PgStat_Kind kind = pgstat_get_kind_from_str(stats_type);
2284 :
2285 160 : PG_RETURN_BOOL(pgstat_have_entry(kind, dboid, objid));
2286 : }
|