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