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