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