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