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