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