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