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