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