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 0 : PG_STAT_GET_RELENTRY_INT64(autoanalyze_count)
60 :
61 : /* pg_stat_get_autovacuum_count */
62 0 : PG_STAT_GET_RELENTRY_INT64(autovacuum_count)
63 :
64 : /* pg_stat_get_blocks_fetched */
65 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 7542 : 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 72 : 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 72 : 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 76 : 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 76 : 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 76 : funcctx = SRF_PERCALL_SETUP();
196 76 : fctx = funcctx->user_fctx;
197 :
198 76 : 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 76 : if (fctx[0] <= pgstat_fetch_stat_numbackends())
210 : {
211 : /* do when there is more left to send */
212 70 : LocalPgBackendStatus *local_beentry = pgstat_get_local_beentry_by_index(fctx[0]);
213 :
214 70 : 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 12 : pg_stat_get_progress_info(PG_FUNCTION_ARGS)
228 : {
229 : #define PG_STAT_GET_PROGRESS_COLS PGSTAT_NUM_PROGRESS_PARAM + 3
230 12 : int num_backends = pgstat_fetch_stat_numbackends();
231 : int curr_backend;
232 12 : char *cmd = text_to_cstring(PG_GETARG_TEXT_PP(0));
233 : ProgressCommandType cmdtype;
234 12 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
235 :
236 : /* Translate command name into command type code. */
237 12 : if (pg_strcasecmp(cmd, "VACUUM") == 0)
238 0 : cmdtype = PROGRESS_COMMAND_VACUUM;
239 12 : else if (pg_strcasecmp(cmd, "ANALYZE") == 0)
240 0 : cmdtype = PROGRESS_COMMAND_ANALYZE;
241 12 : else if (pg_strcasecmp(cmd, "CLUSTER") == 0)
242 0 : cmdtype = PROGRESS_COMMAND_CLUSTER;
243 12 : else if (pg_strcasecmp(cmd, "CREATE INDEX") == 0)
244 0 : cmdtype = PROGRESS_COMMAND_CREATE_INDEX;
245 12 : else if (pg_strcasecmp(cmd, "BASEBACKUP") == 0)
246 0 : 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 12 : InitMaterializedSRF(fcinfo, 0);
255 :
256 : /* 1-based index */
257 112 : for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
258 : {
259 : LocalPgBackendStatus *local_beentry;
260 : PgBackendStatus *beentry;
261 100 : Datum values[PG_STAT_GET_PROGRESS_COLS] = {0};
262 100 : bool nulls[PG_STAT_GET_PROGRESS_COLS] = {0};
263 : int i;
264 :
265 100 : local_beentry = pgstat_get_local_beentry_by_index(curr_backend);
266 100 : beentry = &local_beentry->backendStatus;
267 :
268 : /*
269 : * Report values for only those backends which are running the given
270 : * command.
271 : */
272 100 : if (beentry->st_progress_command != cmdtype)
273 88 : continue;
274 :
275 : /* Value available to all callers */
276 12 : values[0] = Int32GetDatum(beentry->st_procpid);
277 12 : values[1] = ObjectIdGetDatum(beentry->st_databaseid);
278 :
279 : /* show rest of the values including relid only to role members */
280 12 : if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
281 : {
282 12 : values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
283 252 : for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
284 240 : 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 12 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
294 : }
295 :
296 12 : return (Datum) 0;
297 : }
298 :
299 : /*
300 : * Returns activity of PG backends.
301 : */
302 : Datum
303 1420 : pg_stat_get_activity(PG_FUNCTION_ARGS)
304 : {
305 : #define PG_STAT_GET_ACTIVITY_COLS 31
306 1420 : int num_backends = pgstat_fetch_stat_numbackends();
307 : int curr_backend;
308 1420 : int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
309 1420 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
310 :
311 1420 : InitMaterializedSRF(fcinfo, 0);
312 :
313 : /* 1-based index */
314 11742 : for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
315 : {
316 : /* for each row */
317 10324 : Datum values[PG_STAT_GET_ACTIVITY_COLS] = {0};
318 10324 : bool nulls[PG_STAT_GET_ACTIVITY_COLS] = {0};
319 : LocalPgBackendStatus *local_beentry;
320 : PgBackendStatus *beentry;
321 : PGPROC *proc;
322 10324 : const char *wait_event_type = NULL;
323 10324 : const char *wait_event = NULL;
324 :
325 : /* Get the next one in the list */
326 10324 : local_beentry = pgstat_get_local_beentry_by_index(curr_backend);
327 10324 : beentry = &local_beentry->backendStatus;
328 :
329 : /* If looking for specific PID, ignore all the others */
330 10324 : if (pid != -1 && beentry->st_procpid != pid)
331 0 : continue;
332 :
333 : /* Values available to all callers */
334 10324 : if (beentry->st_databaseid != InvalidOid)
335 2792 : values[0] = ObjectIdGetDatum(beentry->st_databaseid);
336 : else
337 7532 : nulls[0] = true;
338 :
339 10324 : values[1] = Int32GetDatum(beentry->st_procpid);
340 :
341 10324 : if (beentry->st_userid != InvalidOid)
342 4690 : values[2] = ObjectIdGetDatum(beentry->st_userid);
343 : else
344 5634 : nulls[2] = true;
345 :
346 10324 : if (beentry->st_appname)
347 10324 : values[3] = CStringGetTextDatum(beentry->st_appname);
348 : else
349 0 : nulls[3] = true;
350 :
351 10324 : if (TransactionIdIsValid(local_beentry->backend_xid))
352 96 : values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
353 : else
354 10228 : nulls[15] = true;
355 :
356 10324 : if (TransactionIdIsValid(local_beentry->backend_xmin))
357 1564 : values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
358 : else
359 8760 : nulls[16] = true;
360 :
361 : /* Values only available to role member or pg_read_all_stats */
362 10324 : if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
363 9862 : {
364 : SockAddr zero_clientaddr;
365 : char *clipped_activity;
366 :
367 9862 : switch (beentry->st_state)
368 : {
369 204 : case STATE_IDLE:
370 204 : values[4] = CStringGetTextDatum("idle");
371 204 : break;
372 3058 : case STATE_RUNNING:
373 3058 : values[4] = CStringGetTextDatum("active");
374 3058 : break;
375 28 : case STATE_IDLEINTRANSACTION:
376 28 : values[4] = CStringGetTextDatum("idle in transaction");
377 28 : 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 6 : case STATE_DISABLED:
385 6 : values[4] = CStringGetTextDatum("disabled");
386 6 : break;
387 6566 : case STATE_UNDEFINED:
388 6566 : nulls[4] = true;
389 6566 : break;
390 : }
391 :
392 9862 : clipped_activity = pgstat_clip_activity(beentry->st_activity_raw);
393 9862 : values[5] = CStringGetTextDatum(clipped_activity);
394 9862 : pfree(clipped_activity);
395 :
396 : /* leader_pid */
397 9862 : nulls[29] = true;
398 :
399 9862 : proc = BackendPidGetProc(beentry->st_procpid);
400 :
401 9862 : 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 4072 : 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 9862 : if (proc != NULL)
417 : {
418 : uint32 raw_wait_event;
419 : PGPROC *leader;
420 :
421 9862 : raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
422 9862 : wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
423 9862 : wait_event = pgstat_get_wait_event(raw_wait_event);
424 :
425 9862 : 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 9862 : if (leader && leader->pid != beentry->st_procpid)
433 : {
434 0 : values[29] = Int32GetDatum(leader->pid);
435 0 : nulls[29] = false;
436 : }
437 9862 : else if (beentry->st_backendType == B_BG_WORKER)
438 : {
439 1418 : int leader_pid = GetLeaderApplyWorkerPid(beentry->st_procpid);
440 :
441 1418 : if (leader_pid != InvalidPid)
442 : {
443 0 : values[29] = Int32GetDatum(leader_pid);
444 0 : nulls[29] = false;
445 : }
446 : }
447 : }
448 :
449 9862 : if (wait_event_type)
450 8336 : values[6] = CStringGetTextDatum(wait_event_type);
451 : else
452 1526 : nulls[6] = true;
453 :
454 9862 : if (wait_event)
455 8336 : values[7] = CStringGetTextDatum(wait_event);
456 : else
457 1526 : 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 9862 : if (beentry->st_xact_start_timestamp != 0 &&
465 1604 : beentry->st_backendType != B_WAL_SENDER)
466 1592 : values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
467 : else
468 8270 : nulls[8] = true;
469 :
470 9862 : if (beentry->st_activity_start_timestamp != 0)
471 3212 : values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
472 : else
473 6650 : nulls[9] = true;
474 :
475 9862 : if (beentry->st_proc_start_timestamp != 0)
476 9862 : values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
477 : else
478 0 : nulls[10] = true;
479 :
480 9862 : if (beentry->st_state_start_timestamp != 0)
481 3290 : values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
482 : else
483 6572 : nulls[11] = true;
484 :
485 : /* A zeroed client addr means we don't know */
486 9862 : memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
487 9862 : if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
488 : sizeof(zero_clientaddr)) == 0)
489 : {
490 6684 : nulls[12] = true;
491 6684 : nulls[13] = true;
492 6684 : nulls[14] = true;
493 : }
494 : else
495 : {
496 3178 : if (beentry->st_clientaddr.addr.ss_family == AF_INET ||
497 3092 : beentry->st_clientaddr.addr.ss_family == AF_INET6)
498 86 : {
499 : char remote_host[NI_MAXHOST];
500 : char remote_port[NI_MAXSERV];
501 : int ret;
502 :
503 86 : remote_host[0] = '\0';
504 86 : remote_port[0] = '\0';
505 86 : ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
506 86 : beentry->st_clientaddr.salen,
507 : remote_host, sizeof(remote_host),
508 : remote_port, sizeof(remote_port),
509 : NI_NUMERICHOST | NI_NUMERICSERV);
510 86 : if (ret == 0)
511 : {
512 86 : clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
513 86 : values[12] = DirectFunctionCall1(inet_in,
514 : CStringGetDatum(remote_host));
515 86 : if (beentry->st_clienthostname &&
516 86 : beentry->st_clienthostname[0])
517 14 : values[13] = CStringGetTextDatum(beentry->st_clienthostname);
518 : else
519 72 : nulls[13] = true;
520 86 : 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 3092 : 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 3092 : nulls[12] = true;
538 3092 : nulls[13] = true;
539 3092 : 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 9862 : if (beentry->st_backendType == B_BG_WORKER)
551 : {
552 : const char *bgw_type;
553 :
554 1418 : bgw_type = GetBackgroundWorkerTypeByPid(beentry->st_procpid);
555 1418 : if (bgw_type)
556 1418 : values[17] = CStringGetTextDatum(bgw_type);
557 : else
558 0 : nulls[17] = true;
559 : }
560 : else
561 8444 : values[17] =
562 8444 : CStringGetTextDatum(GetBackendTypeDesc(beentry->st_backendType));
563 :
564 : /* SSL information */
565 9862 : if (beentry->st_ssl)
566 : {
567 42 : values[18] = BoolGetDatum(true); /* ssl */
568 42 : values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
569 42 : values[20] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
570 42 : values[21] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
571 :
572 42 : if (beentry->st_sslstatus->ssl_client_dn[0])
573 12 : values[22] = CStringGetTextDatum(beentry->st_sslstatus->ssl_client_dn);
574 : else
575 30 : nulls[22] = true;
576 :
577 42 : 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 30 : nulls[23] = true;
584 :
585 42 : if (beentry->st_sslstatus->ssl_issuer_dn[0])
586 12 : values[24] = CStringGetTextDatum(beentry->st_sslstatus->ssl_issuer_dn);
587 : else
588 30 : nulls[24] = true;
589 : }
590 : else
591 : {
592 9820 : values[18] = BoolGetDatum(false); /* ssl */
593 9820 : nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = true;
594 : }
595 :
596 : /* GSSAPI information */
597 9862 : 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 9862 : values[25] = BoolGetDatum(false); /* gss_auth */
608 9862 : nulls[26] = true; /* No GSS principal */
609 9862 : values[27] = BoolGetDatum(false); /* GSS Encryption not in
610 : * use */
611 9862 : values[28] = BoolGetDatum(false); /* GSS credentials not
612 : * delegated */
613 : }
614 9862 : if (beentry->st_query_id == 0)
615 9794 : nulls[30] = true;
616 : else
617 68 : values[30] = UInt64GetDatum(beentry->st_query_id);
618 : }
619 : else
620 : {
621 : /* No permissions to view data about this session */
622 462 : values[5] = CStringGetTextDatum("<insufficient privilege>");
623 462 : nulls[4] = true;
624 462 : nulls[6] = true;
625 462 : nulls[7] = true;
626 462 : nulls[8] = true;
627 462 : nulls[9] = true;
628 462 : nulls[10] = true;
629 462 : nulls[11] = true;
630 462 : nulls[12] = true;
631 462 : nulls[13] = true;
632 462 : nulls[14] = true;
633 462 : nulls[17] = true;
634 462 : nulls[18] = true;
635 462 : nulls[19] = true;
636 462 : nulls[20] = true;
637 462 : nulls[21] = true;
638 462 : nulls[22] = true;
639 462 : nulls[23] = true;
640 462 : nulls[24] = true;
641 462 : nulls[25] = true;
642 462 : nulls[26] = true;
643 462 : nulls[27] = true;
644 462 : nulls[28] = true;
645 462 : nulls[29] = true;
646 462 : nulls[30] = true;
647 : }
648 :
649 10324 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
650 :
651 : /* If only a single backend was requested, and we found it, break. */
652 10324 : if (pid != -1)
653 2 : break;
654 : }
655 :
656 1420 : return (Datum) 0;
657 : }
658 :
659 :
660 : Datum
661 1222 : pg_backend_pid(PG_FUNCTION_ARGS)
662 : {
663 1222 : PG_RETURN_INT32(MyProcPid);
664 : }
665 :
666 :
667 : Datum
668 70 : pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
669 : {
670 70 : int32 procNumber = PG_GETARG_INT32(0);
671 : PgBackendStatus *beentry;
672 :
673 70 : if ((beentry = pgstat_get_beentry_by_proc_number(procNumber)) == NULL)
674 0 : PG_RETURN_NULL();
675 :
676 70 : 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_num_performed(PG_FUNCTION_ARGS)
1196 : {
1197 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_performed);
1198 : }
1199 :
1200 : Datum
1201 0 : pg_stat_get_checkpointer_restartpoints_timed(PG_FUNCTION_ARGS)
1202 : {
1203 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_timed);
1204 : }
1205 :
1206 : Datum
1207 0 : pg_stat_get_checkpointer_restartpoints_requested(PG_FUNCTION_ARGS)
1208 : {
1209 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_requested);
1210 : }
1211 :
1212 : Datum
1213 0 : pg_stat_get_checkpointer_restartpoints_performed(PG_FUNCTION_ARGS)
1214 : {
1215 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->restartpoints_performed);
1216 : }
1217 :
1218 : Datum
1219 0 : pg_stat_get_checkpointer_buffers_written(PG_FUNCTION_ARGS)
1220 : {
1221 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buffers_written);
1222 : }
1223 :
1224 : Datum
1225 0 : pg_stat_get_checkpointer_slru_written(PG_FUNCTION_ARGS)
1226 : {
1227 0 : PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->slru_written);
1228 : }
1229 :
1230 : Datum
1231 0 : pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)
1232 : {
1233 0 : PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->buf_written_clean);
1234 : }
1235 :
1236 : Datum
1237 0 : pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
1238 : {
1239 0 : PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->maxwritten_clean);
1240 : }
1241 :
1242 : Datum
1243 0 : pg_stat_get_checkpointer_write_time(PG_FUNCTION_ARGS)
1244 : {
1245 : /* time is already in msec, just convert to double for presentation */
1246 0 : PG_RETURN_FLOAT8((double)
1247 : pgstat_fetch_stat_checkpointer()->write_time);
1248 : }
1249 :
1250 : Datum
1251 0 : pg_stat_get_checkpointer_sync_time(PG_FUNCTION_ARGS)
1252 : {
1253 : /* time is already in msec, just convert to double for presentation */
1254 0 : PG_RETURN_FLOAT8((double)
1255 : pgstat_fetch_stat_checkpointer()->sync_time);
1256 : }
1257 :
1258 : Datum
1259 20 : pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
1260 : {
1261 20 : PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
1262 : }
1263 :
1264 : Datum
1265 12 : pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
1266 : {
1267 12 : PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_bgwriter()->stat_reset_timestamp);
1268 : }
1269 :
1270 : Datum
1271 0 : pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
1272 : {
1273 0 : PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->buf_alloc);
1274 : }
1275 :
1276 : /*
1277 : * When adding a new column to the pg_stat_io view, add a new enum value
1278 : * here above IO_NUM_COLUMNS.
1279 : */
1280 : typedef enum io_stat_col
1281 : {
1282 : IO_COL_INVALID = -1,
1283 : IO_COL_BACKEND_TYPE,
1284 : IO_COL_OBJECT,
1285 : IO_COL_CONTEXT,
1286 : IO_COL_READS,
1287 : IO_COL_READ_TIME,
1288 : IO_COL_WRITES,
1289 : IO_COL_WRITE_TIME,
1290 : IO_COL_WRITEBACKS,
1291 : IO_COL_WRITEBACK_TIME,
1292 : IO_COL_EXTENDS,
1293 : IO_COL_EXTEND_TIME,
1294 : IO_COL_CONVERSION,
1295 : IO_COL_HITS,
1296 : IO_COL_EVICTIONS,
1297 : IO_COL_REUSES,
1298 : IO_COL_FSYNCS,
1299 : IO_COL_FSYNC_TIME,
1300 : IO_COL_RESET_TIME,
1301 : IO_NUM_COLUMNS,
1302 : } io_stat_col;
1303 :
1304 : /*
1305 : * When adding a new IOOp, add a new io_stat_col and add a case to this
1306 : * function returning the corresponding io_stat_col.
1307 : */
1308 : static io_stat_col
1309 50960 : pgstat_get_io_op_index(IOOp io_op)
1310 : {
1311 50960 : switch (io_op)
1312 : {
1313 3920 : case IOOP_EVICT:
1314 3920 : return IO_COL_EVICTIONS;
1315 7840 : case IOOP_EXTEND:
1316 7840 : return IO_COL_EXTENDS;
1317 7840 : case IOOP_FSYNC:
1318 7840 : return IO_COL_FSYNCS;
1319 3920 : case IOOP_HIT:
1320 3920 : return IO_COL_HITS;
1321 7840 : case IOOP_READ:
1322 7840 : return IO_COL_READS;
1323 3920 : case IOOP_REUSE:
1324 3920 : return IO_COL_REUSES;
1325 7840 : case IOOP_WRITE:
1326 7840 : return IO_COL_WRITES;
1327 7840 : case IOOP_WRITEBACK:
1328 7840 : return IO_COL_WRITEBACKS;
1329 : }
1330 :
1331 0 : elog(ERROR, "unrecognized IOOp value: %d", io_op);
1332 : pg_unreachable();
1333 : }
1334 :
1335 : /*
1336 : * Get the number of the column containing IO times for the specified IOOp.
1337 : * This function encodes our assumption that IO time for an IOOp is displayed
1338 : * in the view in the column directly after the IOOp counts. If an op has no
1339 : * associated time, IO_COL_INVALID is returned.
1340 : */
1341 : static io_stat_col
1342 31360 : pgstat_get_io_time_index(IOOp io_op)
1343 : {
1344 31360 : switch (io_op)
1345 : {
1346 19600 : case IOOP_READ:
1347 : case IOOP_WRITE:
1348 : case IOOP_WRITEBACK:
1349 : case IOOP_EXTEND:
1350 : case IOOP_FSYNC:
1351 19600 : return pgstat_get_io_op_index(io_op) + 1;
1352 11760 : case IOOP_EVICT:
1353 : case IOOP_HIT:
1354 : case IOOP_REUSE:
1355 11760 : return IO_COL_INVALID;
1356 : }
1357 :
1358 0 : elog(ERROR, "unrecognized IOOp value: %d", io_op);
1359 : pg_unreachable();
1360 : }
1361 :
1362 : static inline double
1363 14896 : pg_stat_us_to_ms(PgStat_Counter val_ms)
1364 : {
1365 14896 : return val_ms * (double) 0.001;
1366 : }
1367 :
1368 : Datum
1369 112 : pg_stat_get_io(PG_FUNCTION_ARGS)
1370 : {
1371 : ReturnSetInfo *rsinfo;
1372 : PgStat_IO *backends_io_stats;
1373 : Datum reset_time;
1374 :
1375 112 : InitMaterializedSRF(fcinfo, 0);
1376 112 : rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1377 :
1378 112 : backends_io_stats = pgstat_fetch_stat_io();
1379 :
1380 112 : reset_time = TimestampTzGetDatum(backends_io_stats->stat_reset_timestamp);
1381 :
1382 1904 : for (int bktype = 0; bktype < BACKEND_NUM_TYPES; bktype++)
1383 : {
1384 1792 : Datum bktype_desc = CStringGetTextDatum(GetBackendTypeDesc(bktype));
1385 1792 : PgStat_BktypeIO *bktype_stats = &backends_io_stats->stats[bktype];
1386 :
1387 : /*
1388 : * In Assert builds, we can afford an extra loop through all of the
1389 : * counters checking that only expected stats are non-zero, since it
1390 : * keeps the non-Assert code cleaner.
1391 : */
1392 : Assert(pgstat_bktype_io_stats_valid(bktype_stats, bktype));
1393 :
1394 : /*
1395 : * For those BackendTypes without IO Operation stats, skip
1396 : * representing them in the view altogether.
1397 : */
1398 1792 : if (!pgstat_tracks_io_bktype(bktype))
1399 672 : continue;
1400 :
1401 3360 : for (int io_obj = 0; io_obj < IOOBJECT_NUM_TYPES; io_obj++)
1402 : {
1403 2240 : const char *obj_name = pgstat_get_io_object_name(io_obj);
1404 :
1405 11200 : for (int io_context = 0; io_context < IOCONTEXT_NUM_TYPES; io_context++)
1406 : {
1407 8960 : const char *context_name = pgstat_get_io_context_name(io_context);
1408 :
1409 8960 : Datum values[IO_NUM_COLUMNS] = {0};
1410 8960 : bool nulls[IO_NUM_COLUMNS] = {0};
1411 :
1412 : /*
1413 : * Some combinations of BackendType, IOObject, and IOContext
1414 : * are not valid for any type of IOOp. In such cases, omit the
1415 : * entire row from the view.
1416 : */
1417 8960 : if (!pgstat_tracks_io_object(bktype, io_obj, io_context))
1418 5040 : continue;
1419 :
1420 3920 : values[IO_COL_BACKEND_TYPE] = bktype_desc;
1421 3920 : values[IO_COL_CONTEXT] = CStringGetTextDatum(context_name);
1422 3920 : values[IO_COL_OBJECT] = CStringGetTextDatum(obj_name);
1423 3920 : values[IO_COL_RESET_TIME] = reset_time;
1424 :
1425 : /*
1426 : * Hard-code this to the value of BLCKSZ for now. Future
1427 : * values could include XLOG_BLCKSZ, once WAL IO is tracked,
1428 : * and constant multipliers, once non-block-oriented IO (e.g.
1429 : * temporary file IO) is tracked.
1430 : */
1431 3920 : values[IO_COL_CONVERSION] = Int64GetDatum(BLCKSZ);
1432 :
1433 35280 : for (int io_op = 0; io_op < IOOP_NUM_TYPES; io_op++)
1434 : {
1435 31360 : int op_idx = pgstat_get_io_op_index(io_op);
1436 31360 : int time_idx = pgstat_get_io_time_index(io_op);
1437 :
1438 : /*
1439 : * Some combinations of BackendType and IOOp, of IOContext
1440 : * and IOOp, and of IOObject and IOOp are not tracked. Set
1441 : * these cells in the view NULL.
1442 : */
1443 31360 : if (pgstat_tracks_io_op(bktype, io_obj, io_context, io_op))
1444 : {
1445 24640 : PgStat_Counter count =
1446 : bktype_stats->counts[io_obj][io_context][io_op];
1447 :
1448 24640 : values[op_idx] = Int64GetDatum(count);
1449 : }
1450 : else
1451 6720 : nulls[op_idx] = true;
1452 :
1453 : /* not every operation is timed */
1454 31360 : if (time_idx == IO_COL_INVALID)
1455 11760 : continue;
1456 :
1457 19600 : if (!nulls[op_idx])
1458 : {
1459 14896 : PgStat_Counter time =
1460 : bktype_stats->times[io_obj][io_context][io_op];
1461 :
1462 14896 : values[time_idx] = Float8GetDatum(pg_stat_us_to_ms(time));
1463 : }
1464 : else
1465 4704 : nulls[time_idx] = true;
1466 : }
1467 :
1468 3920 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1469 : values, nulls);
1470 : }
1471 : }
1472 : }
1473 :
1474 112 : return (Datum) 0;
1475 : }
1476 :
1477 : /*
1478 : * Returns statistics of WAL activity
1479 : */
1480 : Datum
1481 72 : pg_stat_get_wal(PG_FUNCTION_ARGS)
1482 : {
1483 : #define PG_STAT_GET_WAL_COLS 9
1484 : TupleDesc tupdesc;
1485 72 : Datum values[PG_STAT_GET_WAL_COLS] = {0};
1486 72 : bool nulls[PG_STAT_GET_WAL_COLS] = {0};
1487 : char buf[256];
1488 : PgStat_WalStats *wal_stats;
1489 :
1490 : /* Initialise attributes information in the tuple descriptor */
1491 72 : tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_WAL_COLS);
1492 72 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "wal_records",
1493 : INT8OID, -1, 0);
1494 72 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "wal_fpi",
1495 : INT8OID, -1, 0);
1496 72 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "wal_bytes",
1497 : NUMERICOID, -1, 0);
1498 72 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_buffers_full",
1499 : INT8OID, -1, 0);
1500 72 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "wal_write",
1501 : INT8OID, -1, 0);
1502 72 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "wal_sync",
1503 : INT8OID, -1, 0);
1504 72 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "wal_write_time",
1505 : FLOAT8OID, -1, 0);
1506 72 : TupleDescInitEntry(tupdesc, (AttrNumber) 8, "wal_sync_time",
1507 : FLOAT8OID, -1, 0);
1508 72 : TupleDescInitEntry(tupdesc, (AttrNumber) 9, "stats_reset",
1509 : TIMESTAMPTZOID, -1, 0);
1510 :
1511 72 : BlessTupleDesc(tupdesc);
1512 :
1513 : /* Get statistics about WAL activity */
1514 72 : wal_stats = pgstat_fetch_stat_wal();
1515 :
1516 : /* Fill values and NULLs */
1517 72 : values[0] = Int64GetDatum(wal_stats->wal_records);
1518 72 : values[1] = Int64GetDatum(wal_stats->wal_fpi);
1519 :
1520 : /* Convert to numeric. */
1521 72 : snprintf(buf, sizeof buf, UINT64_FORMAT, wal_stats->wal_bytes);
1522 72 : values[2] = DirectFunctionCall3(numeric_in,
1523 : CStringGetDatum(buf),
1524 : ObjectIdGetDatum(0),
1525 : Int32GetDatum(-1));
1526 :
1527 72 : values[3] = Int64GetDatum(wal_stats->wal_buffers_full);
1528 72 : values[4] = Int64GetDatum(wal_stats->wal_write);
1529 72 : values[5] = Int64GetDatum(wal_stats->wal_sync);
1530 :
1531 : /* Convert counters from microsec to millisec for display */
1532 72 : values[6] = Float8GetDatum(((double) wal_stats->wal_write_time) / 1000.0);
1533 72 : values[7] = Float8GetDatum(((double) wal_stats->wal_sync_time) / 1000.0);
1534 :
1535 72 : values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
1536 :
1537 : /* Returns the record as Datum */
1538 72 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
1539 : }
1540 :
1541 : /*
1542 : * Returns statistics of SLRU caches.
1543 : */
1544 : Datum
1545 124 : pg_stat_get_slru(PG_FUNCTION_ARGS)
1546 : {
1547 : #define PG_STAT_GET_SLRU_COLS 9
1548 124 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1549 : int i;
1550 : PgStat_SLRUStats *stats;
1551 :
1552 124 : InitMaterializedSRF(fcinfo, 0);
1553 :
1554 : /* request SLRU stats from the cumulative stats system */
1555 124 : stats = pgstat_fetch_slru();
1556 :
1557 124 : for (i = 0;; i++)
1558 992 : {
1559 : /* for each row */
1560 1116 : Datum values[PG_STAT_GET_SLRU_COLS] = {0};
1561 1116 : bool nulls[PG_STAT_GET_SLRU_COLS] = {0};
1562 : PgStat_SLRUStats stat;
1563 : const char *name;
1564 :
1565 1116 : name = pgstat_get_slru_name(i);
1566 :
1567 1116 : if (!name)
1568 124 : break;
1569 :
1570 992 : stat = stats[i];
1571 :
1572 992 : values[0] = PointerGetDatum(cstring_to_text(name));
1573 992 : values[1] = Int64GetDatum(stat.blocks_zeroed);
1574 992 : values[2] = Int64GetDatum(stat.blocks_hit);
1575 992 : values[3] = Int64GetDatum(stat.blocks_read);
1576 992 : values[4] = Int64GetDatum(stat.blocks_written);
1577 992 : values[5] = Int64GetDatum(stat.blocks_exists);
1578 992 : values[6] = Int64GetDatum(stat.flush);
1579 992 : values[7] = Int64GetDatum(stat.truncate);
1580 992 : values[8] = TimestampTzGetDatum(stat.stat_reset_timestamp);
1581 :
1582 992 : tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1583 : }
1584 :
1585 124 : return (Datum) 0;
1586 : }
1587 :
1588 : #define PG_STAT_GET_XACT_RELENTRY_INT64(stat) \
1589 : Datum \
1590 : CppConcat(pg_stat_get_xact_,stat)(PG_FUNCTION_ARGS) \
1591 : { \
1592 : Oid relid = PG_GETARG_OID(0); \
1593 : int64 result; \
1594 : PgStat_TableStatus *tabentry; \
1595 : \
1596 : if ((tabentry = find_tabstat_entry(relid)) == NULL) \
1597 : result = 0; \
1598 : else \
1599 : result = (int64) (tabentry->counts.stat); \
1600 : \
1601 : PG_RETURN_INT64(result); \
1602 : }
1603 :
1604 : /* pg_stat_get_xact_numscans */
1605 0 : PG_STAT_GET_XACT_RELENTRY_INT64(numscans)
1606 :
1607 : /* pg_stat_get_xact_tuples_returned */
1608 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_returned)
1609 :
1610 : /* pg_stat_get_xact_tuples_fetched */
1611 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_fetched)
1612 :
1613 : /* pg_stat_get_xact_tuples_hot_updated */
1614 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_hot_updated)
1615 :
1616 : /* pg_stat_get_xact_tuples_newpage_updated */
1617 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_newpage_updated)
1618 :
1619 : /* pg_stat_get_xact_blocks_fetched */
1620 0 : PG_STAT_GET_XACT_RELENTRY_INT64(blocks_fetched)
1621 :
1622 : /* pg_stat_get_xact_blocks_hit */
1623 0 : PG_STAT_GET_XACT_RELENTRY_INT64(blocks_hit)
1624 :
1625 : /* pg_stat_get_xact_tuples_inserted */
1626 48 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_inserted)
1627 :
1628 : /* pg_stat_get_xact_tuples_updated */
1629 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_updated)
1630 :
1631 : /* pg_stat_get_xact_tuples_deleted */
1632 0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_deleted)
1633 :
1634 : Datum
1635 24 : pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
1636 : {
1637 24 : Oid funcid = PG_GETARG_OID(0);
1638 : PgStat_FunctionCounts *funcentry;
1639 :
1640 24 : if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1641 6 : PG_RETURN_NULL();
1642 18 : PG_RETURN_INT64(funcentry->numcalls);
1643 : }
1644 :
1645 : #define PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(stat) \
1646 : Datum \
1647 : CppConcat(pg_stat_get_xact_function_,stat)(PG_FUNCTION_ARGS) \
1648 : { \
1649 : Oid funcid = PG_GETARG_OID(0); \
1650 : PgStat_FunctionCounts *funcentry; \
1651 : \
1652 : if ((funcentry = find_funcstat_entry(funcid)) == NULL) \
1653 : PG_RETURN_NULL(); \
1654 : PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->stat)); \
1655 : }
1656 :
1657 : /* pg_stat_get_xact_function_total_time */
1658 0 : PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(total_time)
1659 :
1660 : /* pg_stat_get_xact_function_self_time */
1661 0 : PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(self_time)
1662 :
1663 : /* Get the timestamp of the current statistics snapshot */
1664 : Datum
1665 60 : pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS)
1666 : {
1667 : bool have_snapshot;
1668 : TimestampTz ts;
1669 :
1670 60 : ts = pgstat_get_stat_snapshot_timestamp(&have_snapshot);
1671 :
1672 60 : if (!have_snapshot)
1673 36 : PG_RETURN_NULL();
1674 :
1675 24 : PG_RETURN_TIMESTAMPTZ(ts);
1676 : }
1677 :
1678 : /* Discard the active statistics snapshot */
1679 : Datum
1680 14 : pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
1681 : {
1682 14 : pgstat_clear_snapshot();
1683 :
1684 14 : PG_RETURN_VOID();
1685 : }
1686 :
1687 :
1688 : /* Force statistics to be reported at the next occasion */
1689 : Datum
1690 408 : pg_stat_force_next_flush(PG_FUNCTION_ARGS)
1691 : {
1692 408 : pgstat_force_next_flush();
1693 :
1694 408 : PG_RETURN_VOID();
1695 : }
1696 :
1697 :
1698 : /* Reset all counters for the current database */
1699 : Datum
1700 26 : pg_stat_reset(PG_FUNCTION_ARGS)
1701 : {
1702 26 : pgstat_reset_counters();
1703 :
1704 26 : PG_RETURN_VOID();
1705 : }
1706 :
1707 : /*
1708 : * Reset some shared cluster-wide counters
1709 : *
1710 : * When adding a new reset target, ideally the name should match that in
1711 : * pgstat_kind_builtin_infos, if relevant.
1712 : */
1713 : Datum
1714 54 : pg_stat_reset_shared(PG_FUNCTION_ARGS)
1715 : {
1716 54 : char *target = NULL;
1717 :
1718 54 : if (PG_ARGISNULL(0))
1719 : {
1720 : /* Reset all the statistics when nothing is specified */
1721 0 : pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
1722 0 : pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
1723 0 : pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
1724 0 : pgstat_reset_of_kind(PGSTAT_KIND_IO);
1725 0 : XLogPrefetchResetStats();
1726 0 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
1727 0 : pgstat_reset_of_kind(PGSTAT_KIND_WAL);
1728 :
1729 0 : PG_RETURN_VOID();
1730 : }
1731 :
1732 54 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1733 :
1734 54 : if (strcmp(target, "archiver") == 0)
1735 8 : pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
1736 46 : else if (strcmp(target, "bgwriter") == 0)
1737 6 : pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
1738 40 : else if (strcmp(target, "checkpointer") == 0)
1739 8 : pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
1740 32 : else if (strcmp(target, "io") == 0)
1741 6 : pgstat_reset_of_kind(PGSTAT_KIND_IO);
1742 26 : else if (strcmp(target, "recovery_prefetch") == 0)
1743 6 : XLogPrefetchResetStats();
1744 20 : else if (strcmp(target, "slru") == 0)
1745 6 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
1746 14 : else if (strcmp(target, "wal") == 0)
1747 8 : pgstat_reset_of_kind(PGSTAT_KIND_WAL);
1748 : else
1749 6 : ereport(ERROR,
1750 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1751 : errmsg("unrecognized reset target: \"%s\"", target),
1752 : errhint("Target must be \"archiver\", \"bgwriter\", \"checkpointer\", \"io\", \"recovery_prefetch\", \"slru\", or \"wal\".")));
1753 :
1754 48 : PG_RETURN_VOID();
1755 : }
1756 :
1757 : /*
1758 : * Reset a statistics for a single object, which may be of current
1759 : * database or shared across all databases in the cluster.
1760 : */
1761 : Datum
1762 12 : pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
1763 : {
1764 12 : Oid taboid = PG_GETARG_OID(0);
1765 12 : Oid dboid = (IsSharedRelation(taboid) ? InvalidOid : MyDatabaseId);
1766 :
1767 12 : pgstat_reset(PGSTAT_KIND_RELATION, dboid, taboid);
1768 :
1769 12 : PG_RETURN_VOID();
1770 : }
1771 :
1772 : Datum
1773 4 : pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
1774 : {
1775 4 : Oid funcoid = PG_GETARG_OID(0);
1776 :
1777 4 : pgstat_reset(PGSTAT_KIND_FUNCTION, MyDatabaseId, funcoid);
1778 :
1779 4 : PG_RETURN_VOID();
1780 : }
1781 :
1782 : /* Reset SLRU counters (a specific one or all of them). */
1783 : Datum
1784 12 : pg_stat_reset_slru(PG_FUNCTION_ARGS)
1785 : {
1786 12 : char *target = NULL;
1787 :
1788 12 : if (PG_ARGISNULL(0))
1789 6 : pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
1790 : else
1791 : {
1792 6 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1793 6 : pgstat_reset_slru(target);
1794 : }
1795 :
1796 12 : PG_RETURN_VOID();
1797 : }
1798 :
1799 : /* Reset replication slots stats (a specific one or all of them). */
1800 : Datum
1801 12 : pg_stat_reset_replication_slot(PG_FUNCTION_ARGS)
1802 : {
1803 12 : char *target = NULL;
1804 :
1805 12 : if (PG_ARGISNULL(0))
1806 4 : pgstat_reset_of_kind(PGSTAT_KIND_REPLSLOT);
1807 : else
1808 : {
1809 8 : target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1810 8 : pgstat_reset_replslot(target);
1811 : }
1812 :
1813 10 : PG_RETURN_VOID();
1814 : }
1815 :
1816 : /* Reset subscription stats (a specific one or all of them) */
1817 : Datum
1818 20 : pg_stat_reset_subscription_stats(PG_FUNCTION_ARGS)
1819 : {
1820 : Oid subid;
1821 :
1822 20 : if (PG_ARGISNULL(0))
1823 : {
1824 : /* Clear all subscription stats */
1825 4 : pgstat_reset_of_kind(PGSTAT_KIND_SUBSCRIPTION);
1826 : }
1827 : else
1828 : {
1829 16 : subid = PG_GETARG_OID(0);
1830 :
1831 16 : if (!OidIsValid(subid))
1832 0 : ereport(ERROR,
1833 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1834 : errmsg("invalid subscription OID %u", subid)));
1835 16 : pgstat_reset(PGSTAT_KIND_SUBSCRIPTION, InvalidOid, subid);
1836 : }
1837 :
1838 20 : PG_RETURN_VOID();
1839 : }
1840 :
1841 : Datum
1842 60 : pg_stat_get_archiver(PG_FUNCTION_ARGS)
1843 : {
1844 : TupleDesc tupdesc;
1845 60 : Datum values[7] = {0};
1846 60 : bool nulls[7] = {0};
1847 : PgStat_ArchiverStats *archiver_stats;
1848 :
1849 : /* Initialise attributes information in the tuple descriptor */
1850 60 : tupdesc = CreateTemplateTupleDesc(7);
1851 60 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count",
1852 : INT8OID, -1, 0);
1853 60 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
1854 : TEXTOID, -1, 0);
1855 60 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time",
1856 : TIMESTAMPTZOID, -1, 0);
1857 60 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count",
1858 : INT8OID, -1, 0);
1859 60 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
1860 : TEXTOID, -1, 0);
1861 60 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time",
1862 : TIMESTAMPTZOID, -1, 0);
1863 60 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset",
1864 : TIMESTAMPTZOID, -1, 0);
1865 :
1866 60 : BlessTupleDesc(tupdesc);
1867 :
1868 : /* Get statistics about the archiver process */
1869 60 : archiver_stats = pgstat_fetch_stat_archiver();
1870 :
1871 : /* Fill values and NULLs */
1872 60 : values[0] = Int64GetDatum(archiver_stats->archived_count);
1873 60 : if (*(archiver_stats->last_archived_wal) == '\0')
1874 24 : nulls[1] = true;
1875 : else
1876 36 : values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
1877 :
1878 60 : if (archiver_stats->last_archived_timestamp == 0)
1879 24 : nulls[2] = true;
1880 : else
1881 36 : values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp);
1882 :
1883 60 : values[3] = Int64GetDatum(archiver_stats->failed_count);
1884 60 : if (*(archiver_stats->last_failed_wal) == '\0')
1885 30 : nulls[4] = true;
1886 : else
1887 30 : values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
1888 :
1889 60 : if (archiver_stats->last_failed_timestamp == 0)
1890 30 : nulls[5] = true;
1891 : else
1892 30 : values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp);
1893 :
1894 60 : if (archiver_stats->stat_reset_timestamp == 0)
1895 0 : nulls[6] = true;
1896 : else
1897 60 : values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
1898 :
1899 : /* Returns the record as Datum */
1900 60 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
1901 : }
1902 :
1903 : /*
1904 : * Get the statistics for the replication slot. If the slot statistics is not
1905 : * available, return all-zeroes stats.
1906 : */
1907 : Datum
1908 94 : pg_stat_get_replication_slot(PG_FUNCTION_ARGS)
1909 : {
1910 : #define PG_STAT_GET_REPLICATION_SLOT_COLS 10
1911 94 : text *slotname_text = PG_GETARG_TEXT_P(0);
1912 : NameData slotname;
1913 : TupleDesc tupdesc;
1914 94 : Datum values[PG_STAT_GET_REPLICATION_SLOT_COLS] = {0};
1915 94 : bool nulls[PG_STAT_GET_REPLICATION_SLOT_COLS] = {0};
1916 : PgStat_StatReplSlotEntry *slotent;
1917 : PgStat_StatReplSlotEntry allzero;
1918 :
1919 : /* Initialise attributes information in the tuple descriptor */
1920 94 : tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_REPLICATION_SLOT_COLS);
1921 94 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "slot_name",
1922 : TEXTOID, -1, 0);
1923 94 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "spill_txns",
1924 : INT8OID, -1, 0);
1925 94 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "spill_count",
1926 : INT8OID, -1, 0);
1927 94 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "spill_bytes",
1928 : INT8OID, -1, 0);
1929 94 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "stream_txns",
1930 : INT8OID, -1, 0);
1931 94 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "stream_count",
1932 : INT8OID, -1, 0);
1933 94 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stream_bytes",
1934 : INT8OID, -1, 0);
1935 94 : TupleDescInitEntry(tupdesc, (AttrNumber) 8, "total_txns",
1936 : INT8OID, -1, 0);
1937 94 : TupleDescInitEntry(tupdesc, (AttrNumber) 9, "total_bytes",
1938 : INT8OID, -1, 0);
1939 94 : TupleDescInitEntry(tupdesc, (AttrNumber) 10, "stats_reset",
1940 : TIMESTAMPTZOID, -1, 0);
1941 94 : BlessTupleDesc(tupdesc);
1942 :
1943 94 : namestrcpy(&slotname, text_to_cstring(slotname_text));
1944 94 : slotent = pgstat_fetch_replslot(slotname);
1945 94 : if (!slotent)
1946 : {
1947 : /*
1948 : * If the slot is not found, initialise its stats. This is possible if
1949 : * the create slot message is lost.
1950 : */
1951 4 : memset(&allzero, 0, sizeof(PgStat_StatReplSlotEntry));
1952 4 : slotent = &allzero;
1953 : }
1954 :
1955 94 : values[0] = CStringGetTextDatum(NameStr(slotname));
1956 94 : values[1] = Int64GetDatum(slotent->spill_txns);
1957 94 : values[2] = Int64GetDatum(slotent->spill_count);
1958 94 : values[3] = Int64GetDatum(slotent->spill_bytes);
1959 94 : values[4] = Int64GetDatum(slotent->stream_txns);
1960 94 : values[5] = Int64GetDatum(slotent->stream_count);
1961 94 : values[6] = Int64GetDatum(slotent->stream_bytes);
1962 94 : values[7] = Int64GetDatum(slotent->total_txns);
1963 94 : values[8] = Int64GetDatum(slotent->total_bytes);
1964 :
1965 94 : if (slotent->stat_reset_timestamp == 0)
1966 52 : nulls[9] = true;
1967 : else
1968 42 : values[9] = TimestampTzGetDatum(slotent->stat_reset_timestamp);
1969 :
1970 : /* Returns the record as Datum */
1971 94 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
1972 : }
1973 :
1974 : /*
1975 : * Get the subscription statistics for the given subscription. If the
1976 : * subscription statistics is not available, return all-zeros stats.
1977 : */
1978 : Datum
1979 82 : pg_stat_get_subscription_stats(PG_FUNCTION_ARGS)
1980 : {
1981 : #define PG_STAT_GET_SUBSCRIPTION_STATS_COLS 10
1982 82 : Oid subid = PG_GETARG_OID(0);
1983 : TupleDesc tupdesc;
1984 82 : Datum values[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
1985 82 : bool nulls[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
1986 : PgStat_StatSubEntry *subentry;
1987 : PgStat_StatSubEntry allzero;
1988 82 : int i = 0;
1989 :
1990 : /* Get subscription stats */
1991 82 : subentry = pgstat_fetch_stat_subscription(subid);
1992 :
1993 : /* Initialise attributes information in the tuple descriptor */
1994 82 : tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_SUBSCRIPTION_STATS_COLS);
1995 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "subid",
1996 : OIDOID, -1, 0);
1997 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "apply_error_count",
1998 : INT8OID, -1, 0);
1999 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "sync_error_count",
2000 : INT8OID, -1, 0);
2001 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "confl_insert_exists",
2002 : INT8OID, -1, 0);
2003 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "confl_update_origin_differs",
2004 : INT8OID, -1, 0);
2005 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "confl_update_exists",
2006 : INT8OID, -1, 0);
2007 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "confl_update_missing",
2008 : INT8OID, -1, 0);
2009 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 8, "confl_delete_origin_differs",
2010 : INT8OID, -1, 0);
2011 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 9, "confl_delete_missing",
2012 : INT8OID, -1, 0);
2013 82 : TupleDescInitEntry(tupdesc, (AttrNumber) 10, "stats_reset",
2014 : TIMESTAMPTZOID, -1, 0);
2015 82 : BlessTupleDesc(tupdesc);
2016 :
2017 82 : if (!subentry)
2018 : {
2019 : /* If the subscription is not found, initialise its stats */
2020 0 : memset(&allzero, 0, sizeof(PgStat_StatSubEntry));
2021 0 : subentry = &allzero;
2022 : }
2023 :
2024 : /* subid */
2025 82 : values[i++] = ObjectIdGetDatum(subid);
2026 :
2027 : /* apply_error_count */
2028 82 : values[i++] = Int64GetDatum(subentry->apply_error_count);
2029 :
2030 : /* sync_error_count */
2031 82 : values[i++] = Int64GetDatum(subentry->sync_error_count);
2032 :
2033 : /* conflict count */
2034 574 : for (int nconflict = 0; nconflict < CONFLICT_NUM_TYPES; nconflict++)
2035 492 : values[i++] = Int64GetDatum(subentry->conflict_count[nconflict]);
2036 :
2037 : /* stats_reset */
2038 82 : if (subentry->stat_reset_timestamp == 0)
2039 44 : nulls[i] = true;
2040 : else
2041 38 : values[i] = TimestampTzGetDatum(subentry->stat_reset_timestamp);
2042 :
2043 : Assert(i + 1 == PG_STAT_GET_SUBSCRIPTION_STATS_COLS);
2044 :
2045 : /* Returns the record as Datum */
2046 82 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
2047 : }
2048 :
2049 : /*
2050 : * Checks for presence of stats for object with provided kind, database oid,
2051 : * object oid.
2052 : *
2053 : * This is useful for tests, but not really anything else. Therefore not
2054 : * documented.
2055 : */
2056 : Datum
2057 170 : pg_stat_have_stats(PG_FUNCTION_ARGS)
2058 : {
2059 170 : char *stats_type = text_to_cstring(PG_GETARG_TEXT_P(0));
2060 170 : Oid dboid = PG_GETARG_OID(1);
2061 170 : uint64 objid = PG_GETARG_INT64(2);
2062 170 : PgStat_Kind kind = pgstat_get_kind_from_str(stats_type);
2063 :
2064 164 : PG_RETURN_BOOL(pgstat_have_entry(kind, dboid, objid));
2065 : }
|