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