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