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