1 /*-------------------------------------------------------------------------
2 *
3 * pgstatfuncs.c
4 * Functions for accessing the statistics collector data
5 *
6 * Portions Copyright (c) 1996-2018, 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 "catalog/pg_authid.h"
19 #include "catalog/pg_type.h"
20 #include "common/ip.h"
21 #include "funcapi.h"
22 #include "miscadmin.h"
23 #include "pgstat.h"
24 #include "postmaster/bgworker_internals.h"
25 #include "postmaster/postmaster.h"
26 #include "storage/proc.h"
27 #include "storage/procarray.h"
28 #include "utils/acl.h"
29 #include "utils/builtins.h"
30 #include "utils/inet.h"
31 #include "utils/timestamp.h"
32
33 #define UINT32_ACCESS_ONCE(var) ((uint32)(*((volatile uint32 *)&(var))))
34
35 #define HAS_PGSTAT_PERMISSIONS(role) (is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role))
36
37 /* Global bgwriter statistics, from bgwriter.c */
38 extern PgStat_MsgBgWriter bgwriterStats;
39
40 Datum
pg_stat_get_numscans(PG_FUNCTION_ARGS)41 pg_stat_get_numscans(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->numscans);
51
52 PG_RETURN_INT64(result);
53 }
54
55
56 Datum
pg_stat_get_tuples_returned(PG_FUNCTION_ARGS)57 pg_stat_get_tuples_returned(PG_FUNCTION_ARGS)
58 {
59 Oid relid = PG_GETARG_OID(0);
60 int64 result;
61 PgStat_StatTabEntry *tabentry;
62
63 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
64 result = 0;
65 else
66 result = (int64) (tabentry->tuples_returned);
67
68 PG_RETURN_INT64(result);
69 }
70
71
72 Datum
pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS)73 pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS)
74 {
75 Oid relid = PG_GETARG_OID(0);
76 int64 result;
77 PgStat_StatTabEntry *tabentry;
78
79 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
80 result = 0;
81 else
82 result = (int64) (tabentry->tuples_fetched);
83
84 PG_RETURN_INT64(result);
85 }
86
87
88 Datum
pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS)89 pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS)
90 {
91 Oid relid = PG_GETARG_OID(0);
92 int64 result;
93 PgStat_StatTabEntry *tabentry;
94
95 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
96 result = 0;
97 else
98 result = (int64) (tabentry->tuples_inserted);
99
100 PG_RETURN_INT64(result);
101 }
102
103
104 Datum
pg_stat_get_tuples_updated(PG_FUNCTION_ARGS)105 pg_stat_get_tuples_updated(PG_FUNCTION_ARGS)
106 {
107 Oid relid = PG_GETARG_OID(0);
108 int64 result;
109 PgStat_StatTabEntry *tabentry;
110
111 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
112 result = 0;
113 else
114 result = (int64) (tabentry->tuples_updated);
115
116 PG_RETURN_INT64(result);
117 }
118
119
120 Datum
pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS)121 pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS)
122 {
123 Oid relid = PG_GETARG_OID(0);
124 int64 result;
125 PgStat_StatTabEntry *tabentry;
126
127 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
128 result = 0;
129 else
130 result = (int64) (tabentry->tuples_deleted);
131
132 PG_RETURN_INT64(result);
133 }
134
135
136 Datum
pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS)137 pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS)
138 {
139 Oid relid = PG_GETARG_OID(0);
140 int64 result;
141 PgStat_StatTabEntry *tabentry;
142
143 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
144 result = 0;
145 else
146 result = (int64) (tabentry->tuples_hot_updated);
147
148 PG_RETURN_INT64(result);
149 }
150
151
152 Datum
pg_stat_get_live_tuples(PG_FUNCTION_ARGS)153 pg_stat_get_live_tuples(PG_FUNCTION_ARGS)
154 {
155 Oid relid = PG_GETARG_OID(0);
156 int64 result;
157 PgStat_StatTabEntry *tabentry;
158
159 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
160 result = 0;
161 else
162 result = (int64) (tabentry->n_live_tuples);
163
164 PG_RETURN_INT64(result);
165 }
166
167
168 Datum
pg_stat_get_dead_tuples(PG_FUNCTION_ARGS)169 pg_stat_get_dead_tuples(PG_FUNCTION_ARGS)
170 {
171 Oid relid = PG_GETARG_OID(0);
172 int64 result;
173 PgStat_StatTabEntry *tabentry;
174
175 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
176 result = 0;
177 else
178 result = (int64) (tabentry->n_dead_tuples);
179
180 PG_RETURN_INT64(result);
181 }
182
183
184 Datum
pg_stat_get_mod_since_analyze(PG_FUNCTION_ARGS)185 pg_stat_get_mod_since_analyze(PG_FUNCTION_ARGS)
186 {
187 Oid relid = PG_GETARG_OID(0);
188 int64 result;
189 PgStat_StatTabEntry *tabentry;
190
191 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
192 result = 0;
193 else
194 result = (int64) (tabentry->changes_since_analyze);
195
196 PG_RETURN_INT64(result);
197 }
198
199
200 Datum
pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS)201 pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS)
202 {
203 Oid relid = PG_GETARG_OID(0);
204 int64 result;
205 PgStat_StatTabEntry *tabentry;
206
207 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
208 result = 0;
209 else
210 result = (int64) (tabentry->blocks_fetched);
211
212 PG_RETURN_INT64(result);
213 }
214
215
216 Datum
pg_stat_get_blocks_hit(PG_FUNCTION_ARGS)217 pg_stat_get_blocks_hit(PG_FUNCTION_ARGS)
218 {
219 Oid relid = PG_GETARG_OID(0);
220 int64 result;
221 PgStat_StatTabEntry *tabentry;
222
223 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
224 result = 0;
225 else
226 result = (int64) (tabentry->blocks_hit);
227
228 PG_RETURN_INT64(result);
229 }
230
231 Datum
pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS)232 pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS)
233 {
234 Oid relid = PG_GETARG_OID(0);
235 TimestampTz result;
236 PgStat_StatTabEntry *tabentry;
237
238 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
239 result = 0;
240 else
241 result = tabentry->vacuum_timestamp;
242
243 if (result == 0)
244 PG_RETURN_NULL();
245 else
246 PG_RETURN_TIMESTAMPTZ(result);
247 }
248
249 Datum
pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS)250 pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS)
251 {
252 Oid relid = PG_GETARG_OID(0);
253 TimestampTz result;
254 PgStat_StatTabEntry *tabentry;
255
256 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
257 result = 0;
258 else
259 result = tabentry->autovac_vacuum_timestamp;
260
261 if (result == 0)
262 PG_RETURN_NULL();
263 else
264 PG_RETURN_TIMESTAMPTZ(result);
265 }
266
267 Datum
pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS)268 pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS)
269 {
270 Oid relid = PG_GETARG_OID(0);
271 TimestampTz result;
272 PgStat_StatTabEntry *tabentry;
273
274 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
275 result = 0;
276 else
277 result = tabentry->analyze_timestamp;
278
279 if (result == 0)
280 PG_RETURN_NULL();
281 else
282 PG_RETURN_TIMESTAMPTZ(result);
283 }
284
285 Datum
pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS)286 pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS)
287 {
288 Oid relid = PG_GETARG_OID(0);
289 TimestampTz result;
290 PgStat_StatTabEntry *tabentry;
291
292 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
293 result = 0;
294 else
295 result = tabentry->autovac_analyze_timestamp;
296
297 if (result == 0)
298 PG_RETURN_NULL();
299 else
300 PG_RETURN_TIMESTAMPTZ(result);
301 }
302
303 Datum
pg_stat_get_vacuum_count(PG_FUNCTION_ARGS)304 pg_stat_get_vacuum_count(PG_FUNCTION_ARGS)
305 {
306 Oid relid = PG_GETARG_OID(0);
307 int64 result;
308 PgStat_StatTabEntry *tabentry;
309
310 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
311 result = 0;
312 else
313 result = (int64) (tabentry->vacuum_count);
314
315 PG_RETURN_INT64(result);
316 }
317
318 Datum
pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS)319 pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS)
320 {
321 Oid relid = PG_GETARG_OID(0);
322 int64 result;
323 PgStat_StatTabEntry *tabentry;
324
325 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
326 result = 0;
327 else
328 result = (int64) (tabentry->autovac_vacuum_count);
329
330 PG_RETURN_INT64(result);
331 }
332
333 Datum
pg_stat_get_analyze_count(PG_FUNCTION_ARGS)334 pg_stat_get_analyze_count(PG_FUNCTION_ARGS)
335 {
336 Oid relid = PG_GETARG_OID(0);
337 int64 result;
338 PgStat_StatTabEntry *tabentry;
339
340 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
341 result = 0;
342 else
343 result = (int64) (tabentry->analyze_count);
344
345 PG_RETURN_INT64(result);
346 }
347
348 Datum
pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS)349 pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS)
350 {
351 Oid relid = PG_GETARG_OID(0);
352 int64 result;
353 PgStat_StatTabEntry *tabentry;
354
355 if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
356 result = 0;
357 else
358 result = (int64) (tabentry->autovac_analyze_count);
359
360 PG_RETURN_INT64(result);
361 }
362
363 Datum
pg_stat_get_function_calls(PG_FUNCTION_ARGS)364 pg_stat_get_function_calls(PG_FUNCTION_ARGS)
365 {
366 Oid funcid = PG_GETARG_OID(0);
367 PgStat_StatFuncEntry *funcentry;
368
369 if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
370 PG_RETURN_NULL();
371 PG_RETURN_INT64(funcentry->f_numcalls);
372 }
373
374 Datum
pg_stat_get_function_total_time(PG_FUNCTION_ARGS)375 pg_stat_get_function_total_time(PG_FUNCTION_ARGS)
376 {
377 Oid funcid = PG_GETARG_OID(0);
378 PgStat_StatFuncEntry *funcentry;
379
380 if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
381 PG_RETURN_NULL();
382 /* convert counter from microsec to millisec for display */
383 PG_RETURN_FLOAT8(((double) funcentry->f_total_time) / 1000.0);
384 }
385
386 Datum
pg_stat_get_function_self_time(PG_FUNCTION_ARGS)387 pg_stat_get_function_self_time(PG_FUNCTION_ARGS)
388 {
389 Oid funcid = PG_GETARG_OID(0);
390 PgStat_StatFuncEntry *funcentry;
391
392 if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
393 PG_RETURN_NULL();
394 /* convert counter from microsec to millisec for display */
395 PG_RETURN_FLOAT8(((double) funcentry->f_self_time) / 1000.0);
396 }
397
398 Datum
pg_stat_get_backend_idset(PG_FUNCTION_ARGS)399 pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
400 {
401 FuncCallContext *funcctx;
402 int *fctx;
403 int32 result;
404
405 /* stuff done only on the first call of the function */
406 if (SRF_IS_FIRSTCALL())
407 {
408 /* create a function context for cross-call persistence */
409 funcctx = SRF_FIRSTCALL_INIT();
410
411 fctx = MemoryContextAlloc(funcctx->multi_call_memory_ctx,
412 2 * sizeof(int));
413 funcctx->user_fctx = fctx;
414
415 fctx[0] = 0;
416 fctx[1] = pgstat_fetch_stat_numbackends();
417 }
418
419 /* stuff done on every call of the function */
420 funcctx = SRF_PERCALL_SETUP();
421 fctx = funcctx->user_fctx;
422
423 fctx[0] += 1;
424 result = fctx[0];
425
426 if (result <= fctx[1])
427 {
428 /* do when there is more left to send */
429 SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
430 }
431 else
432 {
433 /* do when there is no more left */
434 SRF_RETURN_DONE(funcctx);
435 }
436 }
437
438 /*
439 * Returns command progress information for the named command.
440 */
441 Datum
pg_stat_get_progress_info(PG_FUNCTION_ARGS)442 pg_stat_get_progress_info(PG_FUNCTION_ARGS)
443 {
444 #define PG_STAT_GET_PROGRESS_COLS PGSTAT_NUM_PROGRESS_PARAM + 3
445 int num_backends = pgstat_fetch_stat_numbackends();
446 int curr_backend;
447 char *cmd = text_to_cstring(PG_GETARG_TEXT_PP(0));
448 ProgressCommandType cmdtype;
449 TupleDesc tupdesc;
450 Tuplestorestate *tupstore;
451 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
452 MemoryContext per_query_ctx;
453 MemoryContext oldcontext;
454
455 /* check to see if caller supports us returning a tuplestore */
456 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
457 ereport(ERROR,
458 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
459 errmsg("set-valued function called in context that cannot accept a set")));
460 if (!(rsinfo->allowedModes & SFRM_Materialize))
461 ereport(ERROR,
462 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
463 errmsg("materialize mode required, but it is not " \
464 "allowed in this context")));
465
466 /* Build a tuple descriptor for our result type */
467 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
468 elog(ERROR, "return type must be a row type");
469
470 /* Translate command name into command type code. */
471 if (pg_strcasecmp(cmd, "VACUUM") == 0)
472 cmdtype = PROGRESS_COMMAND_VACUUM;
473 else
474 ereport(ERROR,
475 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
476 errmsg("invalid command name: \"%s\"", cmd)));
477
478 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
479 oldcontext = MemoryContextSwitchTo(per_query_ctx);
480
481 tupstore = tuplestore_begin_heap(true, false, work_mem);
482 rsinfo->returnMode = SFRM_Materialize;
483 rsinfo->setResult = tupstore;
484 rsinfo->setDesc = tupdesc;
485 MemoryContextSwitchTo(oldcontext);
486
487 /* 1-based index */
488 for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
489 {
490 LocalPgBackendStatus *local_beentry;
491 PgBackendStatus *beentry;
492 Datum values[PG_STAT_GET_PROGRESS_COLS];
493 bool nulls[PG_STAT_GET_PROGRESS_COLS];
494 int i;
495
496 MemSet(values, 0, sizeof(values));
497 MemSet(nulls, 0, sizeof(nulls));
498
499 local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
500
501 if (!local_beentry)
502 continue;
503
504 beentry = &local_beentry->backendStatus;
505
506 /*
507 * Report values for only those backends which are running the given
508 * command.
509 */
510 if (!beentry || beentry->st_progress_command != cmdtype)
511 continue;
512
513 /* Value available to all callers */
514 values[0] = Int32GetDatum(beentry->st_procpid);
515 values[1] = ObjectIdGetDatum(beentry->st_databaseid);
516
517 /* show rest of the values including relid only to role members */
518 if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
519 {
520 values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
521 for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
522 values[i + 3] = Int64GetDatum(beentry->st_progress_param[i]);
523 }
524 else
525 {
526 nulls[2] = true;
527 for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
528 nulls[i + 3] = true;
529 }
530
531 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
532 }
533
534 /* clean up and return the tuplestore */
535 tuplestore_donestoring(tupstore);
536
537 return (Datum) 0;
538 }
539
540 /*
541 * Returns activity of PG backends.
542 */
543 Datum
pg_stat_get_activity(PG_FUNCTION_ARGS)544 pg_stat_get_activity(PG_FUNCTION_ARGS)
545 {
546 #define PG_STAT_GET_ACTIVITY_COLS 24
547 int num_backends = pgstat_fetch_stat_numbackends();
548 int curr_backend;
549 int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
550 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
551 TupleDesc tupdesc;
552 Tuplestorestate *tupstore;
553 MemoryContext per_query_ctx;
554 MemoryContext oldcontext;
555
556 /* check to see if caller supports us returning a tuplestore */
557 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
558 ereport(ERROR,
559 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
560 errmsg("set-valued function called in context that cannot accept a set")));
561 if (!(rsinfo->allowedModes & SFRM_Materialize))
562 ereport(ERROR,
563 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
564 errmsg("materialize mode required, but it is not " \
565 "allowed in this context")));
566
567 /* Build a tuple descriptor for our result type */
568 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
569 elog(ERROR, "return type must be a row type");
570
571 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
572 oldcontext = MemoryContextSwitchTo(per_query_ctx);
573
574 tupstore = tuplestore_begin_heap(true, false, work_mem);
575 rsinfo->returnMode = SFRM_Materialize;
576 rsinfo->setResult = tupstore;
577 rsinfo->setDesc = tupdesc;
578
579 MemoryContextSwitchTo(oldcontext);
580
581 /* 1-based index */
582 for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
583 {
584 /* for each row */
585 Datum values[PG_STAT_GET_ACTIVITY_COLS];
586 bool nulls[PG_STAT_GET_ACTIVITY_COLS];
587 LocalPgBackendStatus *local_beentry;
588 PgBackendStatus *beentry;
589 PGPROC *proc;
590 const char *wait_event_type = NULL;
591 const char *wait_event = NULL;
592
593 MemSet(values, 0, sizeof(values));
594 MemSet(nulls, 0, sizeof(nulls));
595
596 /* Get the next one in the list */
597 local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
598 if (!local_beentry)
599 {
600 int i;
601
602 /* Ignore missing entries if looking for specific PID */
603 if (pid != -1)
604 continue;
605
606 for (i = 0; i < lengthof(nulls); i++)
607 nulls[i] = true;
608
609 nulls[5] = false;
610 values[5] = CStringGetTextDatum("<backend information not available>");
611
612 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
613 continue;
614 }
615
616 beentry = &local_beentry->backendStatus;
617
618 /* If looking for specific PID, ignore all the others */
619 if (pid != -1 && beentry->st_procpid != pid)
620 continue;
621
622 /* Values available to all callers */
623 if (beentry->st_databaseid != InvalidOid)
624 values[0] = ObjectIdGetDatum(beentry->st_databaseid);
625 else
626 nulls[0] = true;
627
628 values[1] = Int32GetDatum(beentry->st_procpid);
629
630 if (beentry->st_userid != InvalidOid)
631 values[2] = ObjectIdGetDatum(beentry->st_userid);
632 else
633 nulls[2] = true;
634
635 if (beentry->st_appname)
636 values[3] = CStringGetTextDatum(beentry->st_appname);
637 else
638 nulls[3] = true;
639
640 if (TransactionIdIsValid(local_beentry->backend_xid))
641 values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
642 else
643 nulls[15] = true;
644
645 if (TransactionIdIsValid(local_beentry->backend_xmin))
646 values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
647 else
648 nulls[16] = true;
649
650 if (beentry->st_ssl)
651 {
652 values[18] = BoolGetDatum(true); /* ssl */
653 values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
654 values[20] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
655 values[21] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
656 values[22] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
657 values[23] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
658 }
659 else
660 {
661 values[18] = BoolGetDatum(false); /* ssl */
662 nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = true;
663 }
664
665 /* Values only available to role member or pg_read_all_stats */
666 if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
667 {
668 SockAddr zero_clientaddr;
669 char *clipped_activity;
670
671 switch (beentry->st_state)
672 {
673 case STATE_IDLE:
674 values[4] = CStringGetTextDatum("idle");
675 break;
676 case STATE_RUNNING:
677 values[4] = CStringGetTextDatum("active");
678 break;
679 case STATE_IDLEINTRANSACTION:
680 values[4] = CStringGetTextDatum("idle in transaction");
681 break;
682 case STATE_FASTPATH:
683 values[4] = CStringGetTextDatum("fastpath function call");
684 break;
685 case STATE_IDLEINTRANSACTION_ABORTED:
686 values[4] = CStringGetTextDatum("idle in transaction (aborted)");
687 break;
688 case STATE_DISABLED:
689 values[4] = CStringGetTextDatum("disabled");
690 break;
691 case STATE_UNDEFINED:
692 nulls[4] = true;
693 break;
694 }
695
696 clipped_activity = pgstat_clip_activity(beentry->st_activity_raw);
697 values[5] = CStringGetTextDatum(clipped_activity);
698 pfree(clipped_activity);
699
700 proc = BackendPidGetProc(beentry->st_procpid);
701 if (proc != NULL)
702 {
703 uint32 raw_wait_event;
704
705 raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
706 wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
707 wait_event = pgstat_get_wait_event(raw_wait_event);
708
709 }
710 else if (beentry->st_backendType != B_BACKEND)
711 {
712 /*
713 * For an auxiliary process, retrieve process info from
714 * AuxiliaryProcs stored in shared-memory.
715 */
716 proc = AuxiliaryPidGetProc(beentry->st_procpid);
717
718 if (proc != NULL)
719 {
720 uint32 raw_wait_event;
721
722 raw_wait_event =
723 UINT32_ACCESS_ONCE(proc->wait_event_info);
724 wait_event_type =
725 pgstat_get_wait_event_type(raw_wait_event);
726 wait_event = pgstat_get_wait_event(raw_wait_event);
727 }
728 }
729
730 if (wait_event_type)
731 values[6] = CStringGetTextDatum(wait_event_type);
732 else
733 nulls[6] = true;
734
735 if (wait_event)
736 values[7] = CStringGetTextDatum(wait_event);
737 else
738 nulls[7] = true;
739
740 /*
741 * Don't expose transaction time for walsenders; it confuses
742 * monitoring, particularly because we don't keep the time up-to-
743 * date.
744 */
745 if (beentry->st_xact_start_timestamp != 0 &&
746 beentry->st_backendType != B_WAL_SENDER)
747 values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
748 else
749 nulls[8] = true;
750
751 if (beentry->st_activity_start_timestamp != 0)
752 values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
753 else
754 nulls[9] = true;
755
756 if (beentry->st_proc_start_timestamp != 0)
757 values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
758 else
759 nulls[10] = true;
760
761 if (beentry->st_state_start_timestamp != 0)
762 values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
763 else
764 nulls[11] = true;
765
766 /* A zeroed client addr means we don't know */
767 memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
768 if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
769 sizeof(zero_clientaddr)) == 0)
770 {
771 nulls[12] = true;
772 nulls[13] = true;
773 nulls[14] = true;
774 }
775 else
776 {
777 if (beentry->st_clientaddr.addr.ss_family == AF_INET
778 #ifdef HAVE_IPV6
779 || beentry->st_clientaddr.addr.ss_family == AF_INET6
780 #endif
781 )
782 {
783 char remote_host[NI_MAXHOST];
784 char remote_port[NI_MAXSERV];
785 int ret;
786
787 remote_host[0] = '\0';
788 remote_port[0] = '\0';
789 ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
790 beentry->st_clientaddr.salen,
791 remote_host, sizeof(remote_host),
792 remote_port, sizeof(remote_port),
793 NI_NUMERICHOST | NI_NUMERICSERV);
794 if (ret == 0)
795 {
796 clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
797 values[12] = DirectFunctionCall1(inet_in,
798 CStringGetDatum(remote_host));
799 if (beentry->st_clienthostname &&
800 beentry->st_clienthostname[0])
801 values[13] = CStringGetTextDatum(beentry->st_clienthostname);
802 else
803 nulls[13] = true;
804 values[14] = Int32GetDatum(atoi(remote_port));
805 }
806 else
807 {
808 nulls[12] = true;
809 nulls[13] = true;
810 nulls[14] = true;
811 }
812 }
813 else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
814 {
815 /*
816 * Unix sockets always reports NULL for host and -1 for
817 * port, so it's possible to tell the difference to
818 * connections we have no permissions to view, or with
819 * errors.
820 */
821 nulls[12] = true;
822 nulls[13] = true;
823 values[14] = Int32GetDatum(-1);
824 }
825 else
826 {
827 /* Unknown address type, should never happen */
828 nulls[12] = true;
829 nulls[13] = true;
830 nulls[14] = true;
831 }
832 }
833 /* Add backend type */
834 if (beentry->st_backendType == B_BG_WORKER)
835 {
836 const char *bgw_type;
837
838 bgw_type = GetBackgroundWorkerTypeByPid(beentry->st_procpid);
839 if (bgw_type)
840 values[17] = CStringGetTextDatum(bgw_type);
841 else
842 nulls[17] = true;
843 }
844 else
845 values[17] =
846 CStringGetTextDatum(pgstat_get_backend_desc(beentry->st_backendType));
847 }
848 else
849 {
850 /* No permissions to view data about this session */
851 values[5] = CStringGetTextDatum("<insufficient privilege>");
852 nulls[4] = true;
853 nulls[6] = true;
854 nulls[7] = true;
855 nulls[8] = true;
856 nulls[9] = true;
857 nulls[10] = true;
858 nulls[11] = true;
859 nulls[12] = true;
860 nulls[13] = true;
861 nulls[14] = true;
862 nulls[17] = true;
863 }
864
865 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
866
867 /* If only a single backend was requested, and we found it, break. */
868 if (pid != -1)
869 break;
870 }
871
872 /* clean up and return the tuplestore */
873 tuplestore_donestoring(tupstore);
874
875 return (Datum) 0;
876 }
877
878
879 Datum
pg_backend_pid(PG_FUNCTION_ARGS)880 pg_backend_pid(PG_FUNCTION_ARGS)
881 {
882 PG_RETURN_INT32(MyProcPid);
883 }
884
885
886 Datum
pg_stat_get_backend_pid(PG_FUNCTION_ARGS)887 pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
888 {
889 int32 beid = PG_GETARG_INT32(0);
890 PgBackendStatus *beentry;
891
892 if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
893 PG_RETURN_NULL();
894
895 PG_RETURN_INT32(beentry->st_procpid);
896 }
897
898
899 Datum
pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)900 pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
901 {
902 int32 beid = PG_GETARG_INT32(0);
903 PgBackendStatus *beentry;
904
905 if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
906 PG_RETURN_NULL();
907
908 PG_RETURN_OID(beentry->st_databaseid);
909 }
910
911
912 Datum
pg_stat_get_backend_userid(PG_FUNCTION_ARGS)913 pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
914 {
915 int32 beid = PG_GETARG_INT32(0);
916 PgBackendStatus *beentry;
917
918 if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
919 PG_RETURN_NULL();
920
921 PG_RETURN_OID(beentry->st_userid);
922 }
923
924
925 Datum
pg_stat_get_backend_activity(PG_FUNCTION_ARGS)926 pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
927 {
928 int32 beid = PG_GETARG_INT32(0);
929 PgBackendStatus *beentry;
930 const char *activity;
931 char *clipped_activity;
932 text *ret;
933
934 if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
935 activity = "<backend information not available>";
936 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
937 activity = "<insufficient privilege>";
938 else if (*(beentry->st_activity_raw) == '\0')
939 activity = "<command string not enabled>";
940 else
941 activity = beentry->st_activity_raw;
942
943 clipped_activity = pgstat_clip_activity(activity);
944 ret = cstring_to_text(activity);
945 pfree(clipped_activity);
946
947 PG_RETURN_TEXT_P(ret);
948 }
949
950 Datum
pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS)951 pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS)
952 {
953 int32 beid = PG_GETARG_INT32(0);
954 PgBackendStatus *beentry;
955 PGPROC *proc;
956 const char *wait_event_type = NULL;
957
958 if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
959 wait_event_type = "<backend information not available>";
960 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
961 wait_event_type = "<insufficient privilege>";
962 else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
963 wait_event_type = pgstat_get_wait_event_type(proc->wait_event_info);
964
965 if (!wait_event_type)
966 PG_RETURN_NULL();
967
968 PG_RETURN_TEXT_P(cstring_to_text(wait_event_type));
969 }
970
971 Datum
pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS)972 pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS)
973 {
974 int32 beid = PG_GETARG_INT32(0);
975 PgBackendStatus *beentry;
976 PGPROC *proc;
977 const char *wait_event = NULL;
978
979 if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
980 wait_event = "<backend information not available>";
981 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
982 wait_event = "<insufficient privilege>";
983 else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
984 wait_event = pgstat_get_wait_event(proc->wait_event_info);
985
986 if (!wait_event)
987 PG_RETURN_NULL();
988
989 PG_RETURN_TEXT_P(cstring_to_text(wait_event));
990 }
991
992
993 Datum
pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)994 pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
995 {
996 int32 beid = PG_GETARG_INT32(0);
997 TimestampTz result;
998 PgBackendStatus *beentry;
999
1000 if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
1001 PG_RETURN_NULL();
1002
1003 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
1004 PG_RETURN_NULL();
1005
1006 result = beentry->st_activity_start_timestamp;
1007
1008 /*
1009 * No time recorded for start of current query -- this is the case if the
1010 * user hasn't enabled query-level stats collection.
1011 */
1012 if (result == 0)
1013 PG_RETURN_NULL();
1014
1015 PG_RETURN_TIMESTAMPTZ(result);
1016 }
1017
1018
1019 Datum
pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)1020 pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)
1021 {
1022 int32 beid = PG_GETARG_INT32(0);
1023 TimestampTz result;
1024 PgBackendStatus *beentry;
1025
1026 if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
1027 PG_RETURN_NULL();
1028
1029 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
1030 PG_RETURN_NULL();
1031
1032 result = beentry->st_xact_start_timestamp;
1033
1034 if (result == 0) /* not in a transaction */
1035 PG_RETURN_NULL();
1036
1037 PG_RETURN_TIMESTAMPTZ(result);
1038 }
1039
1040
1041 Datum
pg_stat_get_backend_start(PG_FUNCTION_ARGS)1042 pg_stat_get_backend_start(PG_FUNCTION_ARGS)
1043 {
1044 int32 beid = PG_GETARG_INT32(0);
1045 TimestampTz result;
1046 PgBackendStatus *beentry;
1047
1048 if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
1049 PG_RETURN_NULL();
1050
1051 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
1052 PG_RETURN_NULL();
1053
1054 result = beentry->st_proc_start_timestamp;
1055
1056 if (result == 0) /* probably can't happen? */
1057 PG_RETURN_NULL();
1058
1059 PG_RETURN_TIMESTAMPTZ(result);
1060 }
1061
1062
1063 Datum
pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)1064 pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
1065 {
1066 int32 beid = PG_GETARG_INT32(0);
1067 PgBackendStatus *beentry;
1068 SockAddr zero_clientaddr;
1069 char remote_host[NI_MAXHOST];
1070 int ret;
1071
1072 if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
1073 PG_RETURN_NULL();
1074
1075 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
1076 PG_RETURN_NULL();
1077
1078 /* A zeroed client addr means we don't know */
1079 memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
1080 if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
1081 sizeof(zero_clientaddr)) == 0)
1082 PG_RETURN_NULL();
1083
1084 switch (beentry->st_clientaddr.addr.ss_family)
1085 {
1086 case AF_INET:
1087 #ifdef HAVE_IPV6
1088 case AF_INET6:
1089 #endif
1090 break;
1091 default:
1092 PG_RETURN_NULL();
1093 }
1094
1095 remote_host[0] = '\0';
1096 ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
1097 beentry->st_clientaddr.salen,
1098 remote_host, sizeof(remote_host),
1099 NULL, 0,
1100 NI_NUMERICHOST | NI_NUMERICSERV);
1101 if (ret != 0)
1102 PG_RETURN_NULL();
1103
1104 clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
1105
1106 PG_RETURN_INET_P(DirectFunctionCall1(inet_in,
1107 CStringGetDatum(remote_host)));
1108 }
1109
1110 Datum
pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)1111 pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
1112 {
1113 int32 beid = PG_GETARG_INT32(0);
1114 PgBackendStatus *beentry;
1115 SockAddr zero_clientaddr;
1116 char remote_port[NI_MAXSERV];
1117 int ret;
1118
1119 if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
1120 PG_RETURN_NULL();
1121
1122 else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
1123 PG_RETURN_NULL();
1124
1125 /* A zeroed client addr means we don't know */
1126 memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
1127 if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
1128 sizeof(zero_clientaddr)) == 0)
1129 PG_RETURN_NULL();
1130
1131 switch (beentry->st_clientaddr.addr.ss_family)
1132 {
1133 case AF_INET:
1134 #ifdef HAVE_IPV6
1135 case AF_INET6:
1136 #endif
1137 break;
1138 case AF_UNIX:
1139 PG_RETURN_INT32(-1);
1140 default:
1141 PG_RETURN_NULL();
1142 }
1143
1144 remote_port[0] = '\0';
1145 ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
1146 beentry->st_clientaddr.salen,
1147 NULL, 0,
1148 remote_port, sizeof(remote_port),
1149 NI_NUMERICHOST | NI_NUMERICSERV);
1150 if (ret != 0)
1151 PG_RETURN_NULL();
1152
1153 PG_RETURN_DATUM(DirectFunctionCall1(int4in,
1154 CStringGetDatum(remote_port)));
1155 }
1156
1157
1158 Datum
pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)1159 pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
1160 {
1161 Oid dbid = PG_GETARG_OID(0);
1162 int32 result;
1163 int tot_backends = pgstat_fetch_stat_numbackends();
1164 int beid;
1165
1166 result = 0;
1167 for (beid = 1; beid <= tot_backends; beid++)
1168 {
1169 PgBackendStatus *beentry = pgstat_fetch_stat_beentry(beid);
1170
1171 if (beentry && beentry->st_databaseid == dbid)
1172 result++;
1173 }
1174
1175 PG_RETURN_INT32(result);
1176 }
1177
1178
1179 Datum
pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS)1180 pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS)
1181 {
1182 Oid dbid = PG_GETARG_OID(0);
1183 int64 result;
1184 PgStat_StatDBEntry *dbentry;
1185
1186 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1187 result = 0;
1188 else
1189 result = (int64) (dbentry->n_xact_commit);
1190
1191 PG_RETURN_INT64(result);
1192 }
1193
1194
1195 Datum
pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)1196 pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)
1197 {
1198 Oid dbid = PG_GETARG_OID(0);
1199 int64 result;
1200 PgStat_StatDBEntry *dbentry;
1201
1202 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1203 result = 0;
1204 else
1205 result = (int64) (dbentry->n_xact_rollback);
1206
1207 PG_RETURN_INT64(result);
1208 }
1209
1210
1211 Datum
pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)1212 pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)
1213 {
1214 Oid dbid = PG_GETARG_OID(0);
1215 int64 result;
1216 PgStat_StatDBEntry *dbentry;
1217
1218 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1219 result = 0;
1220 else
1221 result = (int64) (dbentry->n_blocks_fetched);
1222
1223 PG_RETURN_INT64(result);
1224 }
1225
1226
1227 Datum
pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)1228 pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)
1229 {
1230 Oid dbid = PG_GETARG_OID(0);
1231 int64 result;
1232 PgStat_StatDBEntry *dbentry;
1233
1234 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1235 result = 0;
1236 else
1237 result = (int64) (dbentry->n_blocks_hit);
1238
1239 PG_RETURN_INT64(result);
1240 }
1241
1242
1243 Datum
pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS)1244 pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS)
1245 {
1246 Oid dbid = PG_GETARG_OID(0);
1247 int64 result;
1248 PgStat_StatDBEntry *dbentry;
1249
1250 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1251 result = 0;
1252 else
1253 result = (int64) (dbentry->n_tuples_returned);
1254
1255 PG_RETURN_INT64(result);
1256 }
1257
1258
1259 Datum
pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS)1260 pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS)
1261 {
1262 Oid dbid = PG_GETARG_OID(0);
1263 int64 result;
1264 PgStat_StatDBEntry *dbentry;
1265
1266 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1267 result = 0;
1268 else
1269 result = (int64) (dbentry->n_tuples_fetched);
1270
1271 PG_RETURN_INT64(result);
1272 }
1273
1274
1275 Datum
pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS)1276 pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS)
1277 {
1278 Oid dbid = PG_GETARG_OID(0);
1279 int64 result;
1280 PgStat_StatDBEntry *dbentry;
1281
1282 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1283 result = 0;
1284 else
1285 result = (int64) (dbentry->n_tuples_inserted);
1286
1287 PG_RETURN_INT64(result);
1288 }
1289
1290
1291 Datum
pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS)1292 pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS)
1293 {
1294 Oid dbid = PG_GETARG_OID(0);
1295 int64 result;
1296 PgStat_StatDBEntry *dbentry;
1297
1298 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1299 result = 0;
1300 else
1301 result = (int64) (dbentry->n_tuples_updated);
1302
1303 PG_RETURN_INT64(result);
1304 }
1305
1306
1307 Datum
pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS)1308 pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS)
1309 {
1310 Oid dbid = PG_GETARG_OID(0);
1311 int64 result;
1312 PgStat_StatDBEntry *dbentry;
1313
1314 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1315 result = 0;
1316 else
1317 result = (int64) (dbentry->n_tuples_deleted);
1318
1319 PG_RETURN_INT64(result);
1320 }
1321
1322 Datum
pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)1323 pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)
1324 {
1325 Oid dbid = PG_GETARG_OID(0);
1326 TimestampTz result;
1327 PgStat_StatDBEntry *dbentry;
1328
1329 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1330 result = 0;
1331 else
1332 result = dbentry->stat_reset_timestamp;
1333
1334 if (result == 0)
1335 PG_RETURN_NULL();
1336 else
1337 PG_RETURN_TIMESTAMPTZ(result);
1338 }
1339
1340 Datum
pg_stat_get_db_temp_files(PG_FUNCTION_ARGS)1341 pg_stat_get_db_temp_files(PG_FUNCTION_ARGS)
1342 {
1343 Oid dbid = PG_GETARG_OID(0);
1344 int64 result;
1345 PgStat_StatDBEntry *dbentry;
1346
1347 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1348 result = 0;
1349 else
1350 result = dbentry->n_temp_files;
1351
1352 PG_RETURN_INT64(result);
1353 }
1354
1355
1356 Datum
pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS)1357 pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS)
1358 {
1359 Oid dbid = PG_GETARG_OID(0);
1360 int64 result;
1361 PgStat_StatDBEntry *dbentry;
1362
1363 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1364 result = 0;
1365 else
1366 result = dbentry->n_temp_bytes;
1367
1368 PG_RETURN_INT64(result);
1369 }
1370
1371 Datum
pg_stat_get_db_conflict_tablespace(PG_FUNCTION_ARGS)1372 pg_stat_get_db_conflict_tablespace(PG_FUNCTION_ARGS)
1373 {
1374 Oid dbid = PG_GETARG_OID(0);
1375 int64 result;
1376 PgStat_StatDBEntry *dbentry;
1377
1378 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1379 result = 0;
1380 else
1381 result = (int64) (dbentry->n_conflict_tablespace);
1382
1383 PG_RETURN_INT64(result);
1384 }
1385
1386 Datum
pg_stat_get_db_conflict_lock(PG_FUNCTION_ARGS)1387 pg_stat_get_db_conflict_lock(PG_FUNCTION_ARGS)
1388 {
1389 Oid dbid = PG_GETARG_OID(0);
1390 int64 result;
1391 PgStat_StatDBEntry *dbentry;
1392
1393 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1394 result = 0;
1395 else
1396 result = (int64) (dbentry->n_conflict_lock);
1397
1398 PG_RETURN_INT64(result);
1399 }
1400
1401 Datum
pg_stat_get_db_conflict_snapshot(PG_FUNCTION_ARGS)1402 pg_stat_get_db_conflict_snapshot(PG_FUNCTION_ARGS)
1403 {
1404 Oid dbid = PG_GETARG_OID(0);
1405 int64 result;
1406 PgStat_StatDBEntry *dbentry;
1407
1408 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1409 result = 0;
1410 else
1411 result = (int64) (dbentry->n_conflict_snapshot);
1412
1413 PG_RETURN_INT64(result);
1414 }
1415
1416 Datum
pg_stat_get_db_conflict_bufferpin(PG_FUNCTION_ARGS)1417 pg_stat_get_db_conflict_bufferpin(PG_FUNCTION_ARGS)
1418 {
1419 Oid dbid = PG_GETARG_OID(0);
1420 int64 result;
1421 PgStat_StatDBEntry *dbentry;
1422
1423 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1424 result = 0;
1425 else
1426 result = (int64) (dbentry->n_conflict_bufferpin);
1427
1428 PG_RETURN_INT64(result);
1429 }
1430
1431 Datum
pg_stat_get_db_conflict_startup_deadlock(PG_FUNCTION_ARGS)1432 pg_stat_get_db_conflict_startup_deadlock(PG_FUNCTION_ARGS)
1433 {
1434 Oid dbid = PG_GETARG_OID(0);
1435 int64 result;
1436 PgStat_StatDBEntry *dbentry;
1437
1438 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1439 result = 0;
1440 else
1441 result = (int64) (dbentry->n_conflict_startup_deadlock);
1442
1443 PG_RETURN_INT64(result);
1444 }
1445
1446 Datum
pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS)1447 pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS)
1448 {
1449 Oid dbid = PG_GETARG_OID(0);
1450 int64 result;
1451 PgStat_StatDBEntry *dbentry;
1452
1453 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1454 result = 0;
1455 else
1456 result = (int64) (
1457 dbentry->n_conflict_tablespace +
1458 dbentry->n_conflict_lock +
1459 dbentry->n_conflict_snapshot +
1460 dbentry->n_conflict_bufferpin +
1461 dbentry->n_conflict_startup_deadlock);
1462
1463 PG_RETURN_INT64(result);
1464 }
1465
1466 Datum
pg_stat_get_db_deadlocks(PG_FUNCTION_ARGS)1467 pg_stat_get_db_deadlocks(PG_FUNCTION_ARGS)
1468 {
1469 Oid dbid = PG_GETARG_OID(0);
1470 int64 result;
1471 PgStat_StatDBEntry *dbentry;
1472
1473 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1474 result = 0;
1475 else
1476 result = (int64) (dbentry->n_deadlocks);
1477
1478 PG_RETURN_INT64(result);
1479 }
1480
1481 Datum
pg_stat_get_db_blk_read_time(PG_FUNCTION_ARGS)1482 pg_stat_get_db_blk_read_time(PG_FUNCTION_ARGS)
1483 {
1484 Oid dbid = PG_GETARG_OID(0);
1485 double result;
1486 PgStat_StatDBEntry *dbentry;
1487
1488 /* convert counter from microsec to millisec for display */
1489 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1490 result = 0;
1491 else
1492 result = ((double) dbentry->n_block_read_time) / 1000.0;
1493
1494 PG_RETURN_FLOAT8(result);
1495 }
1496
1497 Datum
pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS)1498 pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS)
1499 {
1500 Oid dbid = PG_GETARG_OID(0);
1501 double result;
1502 PgStat_StatDBEntry *dbentry;
1503
1504 /* convert counter from microsec to millisec for display */
1505 if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1506 result = 0;
1507 else
1508 result = ((double) dbentry->n_block_write_time) / 1000.0;
1509
1510 PG_RETURN_FLOAT8(result);
1511 }
1512
1513 Datum
pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)1514 pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
1515 {
1516 PG_RETURN_INT64(pgstat_fetch_global()->timed_checkpoints);
1517 }
1518
1519 Datum
pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)1520 pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
1521 {
1522 PG_RETURN_INT64(pgstat_fetch_global()->requested_checkpoints);
1523 }
1524
1525 Datum
pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)1526 pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
1527 {
1528 PG_RETURN_INT64(pgstat_fetch_global()->buf_written_checkpoints);
1529 }
1530
1531 Datum
pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)1532 pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)
1533 {
1534 PG_RETURN_INT64(pgstat_fetch_global()->buf_written_clean);
1535 }
1536
1537 Datum
pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)1538 pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
1539 {
1540 PG_RETURN_INT64(pgstat_fetch_global()->maxwritten_clean);
1541 }
1542
1543 Datum
pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS)1544 pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS)
1545 {
1546 /* time is already in msec, just convert to double for presentation */
1547 PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_write_time);
1548 }
1549
1550 Datum
pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)1551 pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
1552 {
1553 /* time is already in msec, just convert to double for presentation */
1554 PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_sync_time);
1555 }
1556
1557 Datum
pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)1558 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
1559 {
1560 PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stat_reset_timestamp);
1561 }
1562
1563 Datum
pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)1564 pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
1565 {
1566 PG_RETURN_INT64(pgstat_fetch_global()->buf_written_backend);
1567 }
1568
1569 Datum
pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)1570 pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)
1571 {
1572 PG_RETURN_INT64(pgstat_fetch_global()->buf_fsync_backend);
1573 }
1574
1575 Datum
pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)1576 pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
1577 {
1578 PG_RETURN_INT64(pgstat_fetch_global()->buf_alloc);
1579 }
1580
1581 Datum
pg_stat_get_xact_numscans(PG_FUNCTION_ARGS)1582 pg_stat_get_xact_numscans(PG_FUNCTION_ARGS)
1583 {
1584 Oid relid = PG_GETARG_OID(0);
1585 int64 result;
1586 PgStat_TableStatus *tabentry;
1587
1588 if ((tabentry = find_tabstat_entry(relid)) == NULL)
1589 result = 0;
1590 else
1591 result = (int64) (tabentry->t_counts.t_numscans);
1592
1593 PG_RETURN_INT64(result);
1594 }
1595
1596 Datum
pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS)1597 pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS)
1598 {
1599 Oid relid = PG_GETARG_OID(0);
1600 int64 result;
1601 PgStat_TableStatus *tabentry;
1602
1603 if ((tabentry = find_tabstat_entry(relid)) == NULL)
1604 result = 0;
1605 else
1606 result = (int64) (tabentry->t_counts.t_tuples_returned);
1607
1608 PG_RETURN_INT64(result);
1609 }
1610
1611 Datum
pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS)1612 pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS)
1613 {
1614 Oid relid = PG_GETARG_OID(0);
1615 int64 result;
1616 PgStat_TableStatus *tabentry;
1617
1618 if ((tabentry = find_tabstat_entry(relid)) == NULL)
1619 result = 0;
1620 else
1621 result = (int64) (tabentry->t_counts.t_tuples_fetched);
1622
1623 PG_RETURN_INT64(result);
1624 }
1625
1626 Datum
pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS)1627 pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS)
1628 {
1629 Oid relid = PG_GETARG_OID(0);
1630 int64 result;
1631 PgStat_TableStatus *tabentry;
1632 PgStat_TableXactStatus *trans;
1633
1634 if ((tabentry = find_tabstat_entry(relid)) == NULL)
1635 result = 0;
1636 else
1637 {
1638 result = tabentry->t_counts.t_tuples_inserted;
1639 /* live subtransactions' counts aren't in t_tuples_inserted yet */
1640 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1641 result += trans->tuples_inserted;
1642 }
1643
1644 PG_RETURN_INT64(result);
1645 }
1646
1647 Datum
pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS)1648 pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS)
1649 {
1650 Oid relid = PG_GETARG_OID(0);
1651 int64 result;
1652 PgStat_TableStatus *tabentry;
1653 PgStat_TableXactStatus *trans;
1654
1655 if ((tabentry = find_tabstat_entry(relid)) == NULL)
1656 result = 0;
1657 else
1658 {
1659 result = tabentry->t_counts.t_tuples_updated;
1660 /* live subtransactions' counts aren't in t_tuples_updated yet */
1661 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1662 result += trans->tuples_updated;
1663 }
1664
1665 PG_RETURN_INT64(result);
1666 }
1667
1668 Datum
pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS)1669 pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS)
1670 {
1671 Oid relid = PG_GETARG_OID(0);
1672 int64 result;
1673 PgStat_TableStatus *tabentry;
1674 PgStat_TableXactStatus *trans;
1675
1676 if ((tabentry = find_tabstat_entry(relid)) == NULL)
1677 result = 0;
1678 else
1679 {
1680 result = tabentry->t_counts.t_tuples_deleted;
1681 /* live subtransactions' counts aren't in t_tuples_deleted yet */
1682 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1683 result += trans->tuples_deleted;
1684 }
1685
1686 PG_RETURN_INT64(result);
1687 }
1688
1689 Datum
pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS)1690 pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS)
1691 {
1692 Oid relid = PG_GETARG_OID(0);
1693 int64 result;
1694 PgStat_TableStatus *tabentry;
1695
1696 if ((tabentry = find_tabstat_entry(relid)) == NULL)
1697 result = 0;
1698 else
1699 result = (int64) (tabentry->t_counts.t_tuples_hot_updated);
1700
1701 PG_RETURN_INT64(result);
1702 }
1703
1704 Datum
pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS)1705 pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS)
1706 {
1707 Oid relid = PG_GETARG_OID(0);
1708 int64 result;
1709 PgStat_TableStatus *tabentry;
1710
1711 if ((tabentry = find_tabstat_entry(relid)) == NULL)
1712 result = 0;
1713 else
1714 result = (int64) (tabentry->t_counts.t_blocks_fetched);
1715
1716 PG_RETURN_INT64(result);
1717 }
1718
1719 Datum
pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS)1720 pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS)
1721 {
1722 Oid relid = PG_GETARG_OID(0);
1723 int64 result;
1724 PgStat_TableStatus *tabentry;
1725
1726 if ((tabentry = find_tabstat_entry(relid)) == NULL)
1727 result = 0;
1728 else
1729 result = (int64) (tabentry->t_counts.t_blocks_hit);
1730
1731 PG_RETURN_INT64(result);
1732 }
1733
1734 Datum
pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)1735 pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
1736 {
1737 Oid funcid = PG_GETARG_OID(0);
1738 PgStat_BackendFunctionEntry *funcentry;
1739
1740 if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1741 PG_RETURN_NULL();
1742 PG_RETURN_INT64(funcentry->f_counts.f_numcalls);
1743 }
1744
1745 Datum
pg_stat_get_xact_function_total_time(PG_FUNCTION_ARGS)1746 pg_stat_get_xact_function_total_time(PG_FUNCTION_ARGS)
1747 {
1748 Oid funcid = PG_GETARG_OID(0);
1749 PgStat_BackendFunctionEntry *funcentry;
1750
1751 if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1752 PG_RETURN_NULL();
1753 PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_total_time));
1754 }
1755
1756 Datum
pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS)1757 pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS)
1758 {
1759 Oid funcid = PG_GETARG_OID(0);
1760 PgStat_BackendFunctionEntry *funcentry;
1761
1762 if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1763 PG_RETURN_NULL();
1764 PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_self_time));
1765 }
1766
1767
1768 /* Get the timestamp of the current statistics snapshot */
1769 Datum
pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS)1770 pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS)
1771 {
1772 PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stats_timestamp);
1773 }
1774
1775 /* Discard the active statistics snapshot */
1776 Datum
pg_stat_clear_snapshot(PG_FUNCTION_ARGS)1777 pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
1778 {
1779 pgstat_clear_snapshot();
1780
1781 PG_RETURN_VOID();
1782 }
1783
1784
1785 /* Reset all counters for the current database */
1786 Datum
pg_stat_reset(PG_FUNCTION_ARGS)1787 pg_stat_reset(PG_FUNCTION_ARGS)
1788 {
1789 pgstat_reset_counters();
1790
1791 PG_RETURN_VOID();
1792 }
1793
1794 /* Reset some shared cluster-wide counters */
1795 Datum
pg_stat_reset_shared(PG_FUNCTION_ARGS)1796 pg_stat_reset_shared(PG_FUNCTION_ARGS)
1797 {
1798 char *target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1799
1800 pgstat_reset_shared_counters(target);
1801
1802 PG_RETURN_VOID();
1803 }
1804
1805 /* Reset a single counter in the current database */
1806 Datum
pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)1807 pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
1808 {
1809 Oid taboid = PG_GETARG_OID(0);
1810
1811 pgstat_reset_single_counter(taboid, RESET_TABLE);
1812
1813 PG_RETURN_VOID();
1814 }
1815
1816 Datum
pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)1817 pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
1818 {
1819 Oid funcoid = PG_GETARG_OID(0);
1820
1821 pgstat_reset_single_counter(funcoid, RESET_FUNCTION);
1822
1823 PG_RETURN_VOID();
1824 }
1825
1826 Datum
pg_stat_get_archiver(PG_FUNCTION_ARGS)1827 pg_stat_get_archiver(PG_FUNCTION_ARGS)
1828 {
1829 TupleDesc tupdesc;
1830 Datum values[7];
1831 bool nulls[7];
1832 PgStat_ArchiverStats *archiver_stats;
1833
1834 /* Initialise values and NULL flags arrays */
1835 MemSet(values, 0, sizeof(values));
1836 MemSet(nulls, 0, sizeof(nulls));
1837
1838 /* Initialise attributes information in the tuple descriptor */
1839 tupdesc = CreateTemplateTupleDesc(7, false);
1840 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count",
1841 INT8OID, -1, 0);
1842 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
1843 TEXTOID, -1, 0);
1844 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time",
1845 TIMESTAMPTZOID, -1, 0);
1846 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count",
1847 INT8OID, -1, 0);
1848 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
1849 TEXTOID, -1, 0);
1850 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time",
1851 TIMESTAMPTZOID, -1, 0);
1852 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset",
1853 TIMESTAMPTZOID, -1, 0);
1854
1855 BlessTupleDesc(tupdesc);
1856
1857 /* Get statistics about the archiver process */
1858 archiver_stats = pgstat_fetch_stat_archiver();
1859
1860 /* Fill values and NULLs */
1861 values[0] = Int64GetDatum(archiver_stats->archived_count);
1862 if (*(archiver_stats->last_archived_wal) == '\0')
1863 nulls[1] = true;
1864 else
1865 values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
1866
1867 if (archiver_stats->last_archived_timestamp == 0)
1868 nulls[2] = true;
1869 else
1870 values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp);
1871
1872 values[3] = Int64GetDatum(archiver_stats->failed_count);
1873 if (*(archiver_stats->last_failed_wal) == '\0')
1874 nulls[4] = true;
1875 else
1876 values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
1877
1878 if (archiver_stats->last_failed_timestamp == 0)
1879 nulls[5] = true;
1880 else
1881 values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp);
1882
1883 if (archiver_stats->stat_reset_timestamp == 0)
1884 nulls[6] = true;
1885 else
1886 values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
1887
1888 /* Returns the record as Datum */
1889 PG_RETURN_DATUM(HeapTupleGetDatum(
1890 heap_form_tuple(tupdesc, values, nulls)));
1891 }
1892