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