]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/pgstatfuncs.c
Make pg_stat_activity.application_name visible to all users, rather than
[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-2009, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.56 2009/11/29 18:14:30 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "funcapi.h"
18 #include "miscadmin.h"
19 #include "pgstat.h"
20 #include "catalog/pg_type.h"
21 #include "utils/builtins.h"
22 #include "utils/inet.h"
23 #include "libpq/ip.h"
24
25 /* bogus ... these externs should be in a header file */
26 extern Datum pg_stat_get_numscans(PG_FUNCTION_ARGS);
27 extern Datum pg_stat_get_tuples_returned(PG_FUNCTION_ARGS);
28 extern Datum pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS);
29 extern Datum pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS);
30 extern Datum pg_stat_get_tuples_updated(PG_FUNCTION_ARGS);
31 extern Datum pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS);
32 extern Datum pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS);
33 extern Datum pg_stat_get_live_tuples(PG_FUNCTION_ARGS);
34 extern Datum pg_stat_get_dead_tuples(PG_FUNCTION_ARGS);
35 extern Datum pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS);
36 extern Datum pg_stat_get_blocks_hit(PG_FUNCTION_ARGS);
37 extern Datum pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS);
38 extern Datum pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS);
39 extern Datum pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS);
40 extern Datum pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS);
41
42 extern Datum pg_stat_get_function_calls(PG_FUNCTION_ARGS);
43 extern Datum pg_stat_get_function_time(PG_FUNCTION_ARGS);
44 extern Datum pg_stat_get_function_self_time(PG_FUNCTION_ARGS);
45
46 extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS);
47 extern Datum pg_stat_get_activity(PG_FUNCTION_ARGS);
48 extern Datum pg_backend_pid(PG_FUNCTION_ARGS);
49 extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS);
50 extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS);
51 extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS);
52 extern Datum pg_stat_get_backend_activity(PG_FUNCTION_ARGS);
53 extern Datum pg_stat_get_backend_waiting(PG_FUNCTION_ARGS);
54 extern Datum pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS);
55 extern Datum pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS);
56 extern Datum pg_stat_get_backend_start(PG_FUNCTION_ARGS);
57 extern Datum pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS);
58 extern Datum pg_stat_get_backend_client_port(PG_FUNCTION_ARGS);
59
60 extern Datum pg_stat_get_db_numbackends(PG_FUNCTION_ARGS);
61 extern Datum pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS);
62 extern Datum pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS);
63 extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS);
64 extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS);
65 extern Datum pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS);
66 extern Datum pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS);
67 extern Datum pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS);
68 extern Datum pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS);
69 extern Datum pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS);
70
71 extern Datum pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS);
72 extern Datum pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS);
73 extern Datum pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS);
74 extern Datum pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS);
75 extern Datum pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS);
76 extern Datum pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS);
77 extern Datum pg_stat_get_buf_alloc(PG_FUNCTION_ARGS);
78
79 extern Datum pg_stat_clear_snapshot(PG_FUNCTION_ARGS);
80 extern Datum pg_stat_reset(PG_FUNCTION_ARGS);
81
82 /* Global bgwriter statistics, from bgwriter.c */
83 extern PgStat_MsgBgWriter bgwriterStats;
84
85 Datum
86 pg_stat_get_numscans(PG_FUNCTION_ARGS)
87 {
88         Oid                     relid = PG_GETARG_OID(0);
89         int64           result;
90         PgStat_StatTabEntry *tabentry;
91
92         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
93                 result = 0;
94         else
95                 result = (int64) (tabentry->numscans);
96
97         PG_RETURN_INT64(result);
98 }
99
100
101 Datum
102 pg_stat_get_tuples_returned(PG_FUNCTION_ARGS)
103 {
104         Oid                     relid = PG_GETARG_OID(0);
105         int64           result;
106         PgStat_StatTabEntry *tabentry;
107
108         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
109                 result = 0;
110         else
111                 result = (int64) (tabentry->tuples_returned);
112
113         PG_RETURN_INT64(result);
114 }
115
116
117 Datum
118 pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS)
119 {
120         Oid                     relid = PG_GETARG_OID(0);
121         int64           result;
122         PgStat_StatTabEntry *tabentry;
123
124         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
125                 result = 0;
126         else
127                 result = (int64) (tabentry->tuples_fetched);
128
129         PG_RETURN_INT64(result);
130 }
131
132
133 Datum
134 pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS)
135 {
136         Oid                     relid = PG_GETARG_OID(0);
137         int64           result;
138         PgStat_StatTabEntry *tabentry;
139
140         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
141                 result = 0;
142         else
143                 result = (int64) (tabentry->tuples_inserted);
144
145         PG_RETURN_INT64(result);
146 }
147
148
149 Datum
150 pg_stat_get_tuples_updated(PG_FUNCTION_ARGS)
151 {
152         Oid                     relid = PG_GETARG_OID(0);
153         int64           result;
154         PgStat_StatTabEntry *tabentry;
155
156         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
157                 result = 0;
158         else
159                 result = (int64) (tabentry->tuples_updated);
160
161         PG_RETURN_INT64(result);
162 }
163
164
165 Datum
166 pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS)
167 {
168         Oid                     relid = PG_GETARG_OID(0);
169         int64           result;
170         PgStat_StatTabEntry *tabentry;
171
172         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
173                 result = 0;
174         else
175                 result = (int64) (tabentry->tuples_deleted);
176
177         PG_RETURN_INT64(result);
178 }
179
180
181 Datum
182 pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS)
183 {
184         Oid                     relid = PG_GETARG_OID(0);
185         int64           result;
186         PgStat_StatTabEntry *tabentry;
187
188         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
189                 result = 0;
190         else
191                 result = (int64) (tabentry->tuples_hot_updated);
192
193         PG_RETURN_INT64(result);
194 }
195
196
197 Datum
198 pg_stat_get_live_tuples(PG_FUNCTION_ARGS)
199 {
200         Oid                     relid = PG_GETARG_OID(0);
201         int64           result;
202         PgStat_StatTabEntry *tabentry;
203
204         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
205                 result = 0;
206         else
207                 result = (int64) (tabentry->n_live_tuples);
208
209         PG_RETURN_INT64(result);
210 }
211
212
213 Datum
214 pg_stat_get_dead_tuples(PG_FUNCTION_ARGS)
215 {
216         Oid                     relid = PG_GETARG_OID(0);
217         int64           result;
218         PgStat_StatTabEntry *tabentry;
219
220         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
221                 result = 0;
222         else
223                 result = (int64) (tabentry->n_dead_tuples);
224
225         PG_RETURN_INT64(result);
226 }
227
228
229 Datum
230 pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS)
231 {
232         Oid                     relid = PG_GETARG_OID(0);
233         int64           result;
234         PgStat_StatTabEntry *tabentry;
235
236         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
237                 result = 0;
238         else
239                 result = (int64) (tabentry->blocks_fetched);
240
241         PG_RETURN_INT64(result);
242 }
243
244
245 Datum
246 pg_stat_get_blocks_hit(PG_FUNCTION_ARGS)
247 {
248         Oid                     relid = PG_GETARG_OID(0);
249         int64           result;
250         PgStat_StatTabEntry *tabentry;
251
252         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
253                 result = 0;
254         else
255                 result = (int64) (tabentry->blocks_hit);
256
257         PG_RETURN_INT64(result);
258 }
259
260 Datum
261 pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS)
262 {
263         Oid                     relid = PG_GETARG_OID(0);
264         TimestampTz result;
265         PgStat_StatTabEntry *tabentry;
266
267         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
268                 result = 0;
269         else
270                 result = tabentry->vacuum_timestamp;
271
272         if (result == 0)
273                 PG_RETURN_NULL();
274         else
275                 PG_RETURN_TIMESTAMPTZ(result);
276 }
277
278 Datum
279 pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS)
280 {
281         Oid                     relid = PG_GETARG_OID(0);
282         TimestampTz result;
283         PgStat_StatTabEntry *tabentry;
284
285         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
286                 result = 0;
287         else
288                 result = tabentry->autovac_vacuum_timestamp;
289
290         if (result == 0)
291                 PG_RETURN_NULL();
292         else
293                 PG_RETURN_TIMESTAMPTZ(result);
294 }
295
296 Datum
297 pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS)
298 {
299         Oid                     relid = PG_GETARG_OID(0);
300         TimestampTz result;
301         PgStat_StatTabEntry *tabentry;
302
303         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
304                 result = 0;
305         else
306                 result = tabentry->analyze_timestamp;
307
308         if (result == 0)
309                 PG_RETURN_NULL();
310         else
311                 PG_RETURN_TIMESTAMPTZ(result);
312 }
313
314 Datum
315 pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS)
316 {
317         Oid                     relid = PG_GETARG_OID(0);
318         TimestampTz result;
319         PgStat_StatTabEntry *tabentry;
320
321         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
322                 result = 0;
323         else
324                 result = tabentry->autovac_analyze_timestamp;
325
326         if (result == 0)
327                 PG_RETURN_NULL();
328         else
329                 PG_RETURN_TIMESTAMPTZ(result);
330 }
331
332 Datum
333 pg_stat_get_function_calls(PG_FUNCTION_ARGS)
334 {
335         Oid                     funcid = PG_GETARG_OID(0);
336         PgStat_StatFuncEntry *funcentry;
337
338         if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
339                 PG_RETURN_NULL();
340         PG_RETURN_INT64(funcentry->f_numcalls);
341 }
342
343 Datum
344 pg_stat_get_function_time(PG_FUNCTION_ARGS)
345 {
346         Oid                     funcid = PG_GETARG_OID(0);
347         PgStat_StatFuncEntry *funcentry;
348
349         if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
350                 PG_RETURN_NULL();
351         PG_RETURN_INT64(funcentry->f_time);
352 }
353
354 Datum
355 pg_stat_get_function_self_time(PG_FUNCTION_ARGS)
356 {
357         Oid                     funcid = PG_GETARG_OID(0);
358         PgStat_StatFuncEntry *funcentry;
359
360         if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
361                 PG_RETURN_NULL();
362         PG_RETURN_INT64(funcentry->f_time_self);
363 }
364
365 Datum
366 pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
367 {
368         FuncCallContext *funcctx;
369         int                *fctx;
370         int32           result;
371
372         /* stuff done only on the first call of the function */
373         if (SRF_IS_FIRSTCALL())
374         {
375                 /* create a function context for cross-call persistence */
376                 funcctx = SRF_FIRSTCALL_INIT();
377
378                 fctx = MemoryContextAlloc(funcctx->multi_call_memory_ctx,
379                                                                   2 * sizeof(int));
380                 funcctx->user_fctx = fctx;
381
382                 fctx[0] = 0;
383                 fctx[1] = pgstat_fetch_stat_numbackends();
384         }
385
386         /* stuff done on every call of the function */
387         funcctx = SRF_PERCALL_SETUP();
388         fctx = funcctx->user_fctx;
389
390         fctx[0] += 1;
391         result = fctx[0];
392
393         if (result <= fctx[1])
394         {
395                 /* do when there is more left to send */
396                 SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
397         }
398         else
399         {
400                 /* do when there is no more left */
401                 SRF_RETURN_DONE(funcctx);
402         }
403 }
404
405 Datum
406 pg_stat_get_activity(PG_FUNCTION_ARGS)
407 {
408         FuncCallContext *funcctx;
409
410         if (SRF_IS_FIRSTCALL())
411         {
412                 MemoryContext oldcontext;
413                 TupleDesc       tupdesc;
414
415                 funcctx = SRF_FIRSTCALL_INIT();
416
417                 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
418
419                 tupdesc = CreateTemplateTupleDesc(11, false);
420                 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid", OIDOID, -1, 0);
421                 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "procpid", INT4OID, -1, 0);
422                 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "usesysid", OIDOID, -1, 0);
423                 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "application_name", TEXTOID, -1, 0);
424                 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "current_query", TEXTOID, -1, 0);
425                 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "waiting", BOOLOID, -1, 0);
426                 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "act_start", TIMESTAMPTZOID, -1, 0);
427                 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "query_start", TIMESTAMPTZOID, -1, 0);
428                 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "backend_start", TIMESTAMPTZOID, -1, 0);
429                 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "client_addr", INETOID, -1, 0);
430                 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "client_port", INT4OID, -1, 0);
431
432                 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
433
434                 funcctx->user_fctx = palloc0(sizeof(int));
435                 if (PG_ARGISNULL(0))
436                 {
437                         /* Get all backends */
438                         funcctx->max_calls = pgstat_fetch_stat_numbackends();
439                 }
440                 else
441                 {
442                         /*
443                          * Get one backend - locate by pid.
444                          *
445                          * We lookup the backend early, so we can return zero rows if it
446                          * doesn't exist, instead of returning a single row full of NULLs.
447                          */
448                         int                     pid = PG_GETARG_INT32(0);
449                         int                     i;
450                         int                     n = pgstat_fetch_stat_numbackends();
451
452                         for (i = 1; i <= n; i++)
453                         {
454                                 PgBackendStatus *be = pgstat_fetch_stat_beentry(i);
455
456                                 if (be)
457                                 {
458                                         if (be->st_procpid == pid)
459                                         {
460                                                 *(int *) (funcctx->user_fctx) = i;
461                                                 break;
462                                         }
463                                 }
464                         }
465
466                         if (*(int *) (funcctx->user_fctx) == 0)
467                                 /* Pid not found, return zero rows */
468                                 funcctx->max_calls = 0;
469                         else
470                                 funcctx->max_calls = 1;
471                 }
472
473                 MemoryContextSwitchTo(oldcontext);
474         }
475
476         /* stuff done on every call of the function */
477         funcctx = SRF_PERCALL_SETUP();
478
479         if (funcctx->call_cntr < funcctx->max_calls)
480         {
481                 /* for each row */
482                 Datum           values[11];
483                 bool            nulls[11];
484                 HeapTuple       tuple;
485                 PgBackendStatus *beentry;
486                 SockAddr        zero_clientaddr;
487
488                 MemSet(values, 0, sizeof(values));
489                 MemSet(nulls, 0, sizeof(nulls));
490
491                 if (*(int *) (funcctx->user_fctx) > 0)
492                 {
493                         /* Get specific pid slot */
494                         beentry = pgstat_fetch_stat_beentry(*(int *) (funcctx->user_fctx));
495                 }
496                 else
497                 {
498                         /* Get the next one in the list */
499                         beentry = pgstat_fetch_stat_beentry(funcctx->call_cntr + 1);            /* 1-based index */
500                 }
501                 if (!beentry)
502                 {
503                         int                     i;
504
505                         for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++)
506                                 nulls[i] = true;
507
508                         nulls[4] = false;
509                         values[4] = CStringGetTextDatum("<backend information not available>");
510
511                         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
512                         SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
513                 }
514
515                 /* Values available to all callers */
516                 values[0] = ObjectIdGetDatum(beentry->st_databaseid);
517                 values[1] = Int32GetDatum(beentry->st_procpid);
518                 values[2] = ObjectIdGetDatum(beentry->st_userid);
519                 if (beentry->st_appname)
520                         values[3] = CStringGetTextDatum(beentry->st_appname);
521                 else
522                         nulls[3] = true;
523
524                 /* Values only available to same user or superuser */
525                 if (superuser() || beentry->st_userid == GetUserId())
526                 {
527                         if (*(beentry->st_activity) == '\0')
528                         {
529                                 values[4] = CStringGetTextDatum("<command string not enabled>");
530                         }
531                         else
532                         {
533                                 values[4] = CStringGetTextDatum(beentry->st_activity);
534                         }
535
536                         values[5] = BoolGetDatum(beentry->st_waiting);
537
538                         if (beentry->st_xact_start_timestamp != 0)
539                                 values[6] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
540                         else
541                                 nulls[6] = true;
542
543                         if (beentry->st_activity_start_timestamp != 0)
544                                 values[7] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
545                         else
546                                 nulls[7] = true;
547
548                         if (beentry->st_proc_start_timestamp != 0)
549                                 values[8] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
550                         else
551                                 nulls[8] = true;
552
553                         /* A zeroed client addr means we don't know */
554                         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
555                         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
556                                            sizeof(zero_clientaddr) == 0))
557                         {
558                                 nulls[9] = true;
559                                 nulls[10] = true;
560                         }
561                         else
562                         {
563                                 if (beentry->st_clientaddr.addr.ss_family == AF_INET
564 #ifdef HAVE_IPV6
565                                         || beentry->st_clientaddr.addr.ss_family == AF_INET6
566 #endif
567                                         )
568                                 {
569                                         char            remote_host[NI_MAXHOST];
570                                         char            remote_port[NI_MAXSERV];
571                                         int                     ret;
572
573                                         remote_host[0] = '\0';
574                                         remote_port[0] = '\0';
575                                         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
576                                                                                          beentry->st_clientaddr.salen,
577                                                                                          remote_host, sizeof(remote_host),
578                                                                                          remote_port, sizeof(remote_port),
579                                                                                          NI_NUMERICHOST | NI_NUMERICSERV);
580                                         if (ret)
581                                         {
582                                                 nulls[9] = true;
583                                                 nulls[10] = true;
584                                         }
585                                         else
586                                         {
587                                                 clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
588                                                 values[9] = DirectFunctionCall1(inet_in,
589                                                                                            CStringGetDatum(remote_host));
590                                                 values[10] = Int32GetDatum(atoi(remote_port));
591                                         }
592                                 }
593                                 else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
594                                 {
595                                         /*
596                                          * Unix sockets always reports NULL for host and -1 for
597                                          * port, so it's possible to tell the difference to
598                                          * connections we have no permissions to view, or with
599                                          * errors.
600                                          */
601                                         nulls[9] = true;
602                                         values[10] = DatumGetInt32(-1);
603                                 }
604                                 else
605                                 {
606                                         /* Unknown address type, should never happen */
607                                         nulls[9] = true;
608                                         nulls[10] = true;
609                                 }
610                         }
611                 }
612                 else
613                 {
614                         /* No permissions to view data about this session */
615                         values[4] = CStringGetTextDatum("<insufficient privilege>");
616                         nulls[5] = true;
617                         nulls[6] = true;
618                         nulls[7] = true;
619                         nulls[8] = true;
620                         nulls[9] = true;
621                         nulls[10] = true;
622                 }
623
624                 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
625
626                 SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
627         }
628         else
629         {
630                 /* nothing left */
631                 SRF_RETURN_DONE(funcctx);
632         }
633 }
634
635
636 Datum
637 pg_backend_pid(PG_FUNCTION_ARGS)
638 {
639         PG_RETURN_INT32(MyProcPid);
640 }
641
642
643 Datum
644 pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
645 {
646         int32           beid = PG_GETARG_INT32(0);
647         PgBackendStatus *beentry;
648
649         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
650                 PG_RETURN_NULL();
651
652         PG_RETURN_INT32(beentry->st_procpid);
653 }
654
655
656 Datum
657 pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
658 {
659         int32           beid = PG_GETARG_INT32(0);
660         PgBackendStatus *beentry;
661
662         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
663                 PG_RETURN_NULL();
664
665         PG_RETURN_OID(beentry->st_databaseid);
666 }
667
668
669 Datum
670 pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
671 {
672         int32           beid = PG_GETARG_INT32(0);
673         PgBackendStatus *beentry;
674
675         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
676                 PG_RETURN_NULL();
677
678         PG_RETURN_OID(beentry->st_userid);
679 }
680
681
682 Datum
683 pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
684 {
685         int32           beid = PG_GETARG_INT32(0);
686         PgBackendStatus *beentry;
687         const char *activity;
688
689         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
690                 activity = "<backend information not available>";
691         else if (!superuser() && beentry->st_userid != GetUserId())
692                 activity = "<insufficient privilege>";
693         else if (*(beentry->st_activity) == '\0')
694                 activity = "<command string not enabled>";
695         else
696                 activity = beentry->st_activity;
697
698         PG_RETURN_TEXT_P(cstring_to_text(activity));
699 }
700
701
702 Datum
703 pg_stat_get_backend_waiting(PG_FUNCTION_ARGS)
704 {
705         int32           beid = PG_GETARG_INT32(0);
706         bool            result;
707         PgBackendStatus *beentry;
708
709         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
710                 PG_RETURN_NULL();
711
712         if (!superuser() && beentry->st_userid != GetUserId())
713                 PG_RETURN_NULL();
714
715         result = beentry->st_waiting;
716
717         PG_RETURN_BOOL(result);
718 }
719
720
721 Datum
722 pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
723 {
724         int32           beid = PG_GETARG_INT32(0);
725         TimestampTz result;
726         PgBackendStatus *beentry;
727
728         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
729                 PG_RETURN_NULL();
730
731         if (!superuser() && beentry->st_userid != GetUserId())
732                 PG_RETURN_NULL();
733
734         result = beentry->st_activity_start_timestamp;
735
736         /*
737          * No time recorded for start of current query -- this is the case if the
738          * user hasn't enabled query-level stats collection.
739          */
740         if (result == 0)
741                 PG_RETURN_NULL();
742
743         PG_RETURN_TIMESTAMPTZ(result);
744 }
745
746
747 Datum
748 pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)
749 {
750         int32           beid = PG_GETARG_INT32(0);
751         TimestampTz result;
752         PgBackendStatus *beentry;
753
754         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
755                 PG_RETURN_NULL();
756
757         if (!superuser() && beentry->st_userid != GetUserId())
758                 PG_RETURN_NULL();
759
760         result = beentry->st_xact_start_timestamp;
761
762         if (result == 0)                        /* not in a transaction */
763                 PG_RETURN_NULL();
764
765         PG_RETURN_TIMESTAMPTZ(result);
766 }
767
768
769 Datum
770 pg_stat_get_backend_start(PG_FUNCTION_ARGS)
771 {
772         int32           beid = PG_GETARG_INT32(0);
773         TimestampTz result;
774         PgBackendStatus *beentry;
775
776         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
777                 PG_RETURN_NULL();
778
779         if (!superuser() && beentry->st_userid != GetUserId())
780                 PG_RETURN_NULL();
781
782         result = beentry->st_proc_start_timestamp;
783
784         if (result == 0)                        /* probably can't happen? */
785                 PG_RETURN_NULL();
786
787         PG_RETURN_TIMESTAMPTZ(result);
788 }
789
790
791 Datum
792 pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
793 {
794         int32           beid = PG_GETARG_INT32(0);
795         PgBackendStatus *beentry;
796         SockAddr        zero_clientaddr;
797         char            remote_host[NI_MAXHOST];
798         int                     ret;
799
800         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
801                 PG_RETURN_NULL();
802
803         if (!superuser() && beentry->st_userid != GetUserId())
804                 PG_RETURN_NULL();
805
806         /* A zeroed client addr means we don't know */
807         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
808         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
809                            sizeof(zero_clientaddr) == 0))
810                 PG_RETURN_NULL();
811
812         switch (beentry->st_clientaddr.addr.ss_family)
813         {
814                 case AF_INET:
815 #ifdef HAVE_IPV6
816                 case AF_INET6:
817 #endif
818                         break;
819                 default:
820                         PG_RETURN_NULL();
821         }
822
823         remote_host[0] = '\0';
824         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
825                                                          beentry->st_clientaddr.salen,
826                                                          remote_host, sizeof(remote_host),
827                                                          NULL, 0,
828                                                          NI_NUMERICHOST | NI_NUMERICSERV);
829         if (ret)
830                 PG_RETURN_NULL();
831
832         clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
833
834         PG_RETURN_INET_P(DirectFunctionCall1(inet_in,
835                                                                                  CStringGetDatum(remote_host)));
836 }
837
838 Datum
839 pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
840 {
841         int32           beid = PG_GETARG_INT32(0);
842         PgBackendStatus *beentry;
843         SockAddr        zero_clientaddr;
844         char            remote_port[NI_MAXSERV];
845         int                     ret;
846
847         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
848                 PG_RETURN_NULL();
849
850         if (!superuser() && beentry->st_userid != GetUserId())
851                 PG_RETURN_NULL();
852
853         /* A zeroed client addr means we don't know */
854         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
855         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
856                            sizeof(zero_clientaddr) == 0))
857                 PG_RETURN_NULL();
858
859         switch (beentry->st_clientaddr.addr.ss_family)
860         {
861                 case AF_INET:
862 #ifdef HAVE_IPV6
863                 case AF_INET6:
864 #endif
865                         break;
866                 case AF_UNIX:
867                         PG_RETURN_INT32(-1);
868                 default:
869                         PG_RETURN_NULL();
870         }
871
872         remote_port[0] = '\0';
873         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
874                                                          beentry->st_clientaddr.salen,
875                                                          NULL, 0,
876                                                          remote_port, sizeof(remote_port),
877                                                          NI_NUMERICHOST | NI_NUMERICSERV);
878         if (ret)
879                 PG_RETURN_NULL();
880
881         PG_RETURN_DATUM(DirectFunctionCall1(int4in,
882                                                                                 CStringGetDatum(remote_port)));
883 }
884
885
886 Datum
887 pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
888 {
889         Oid                     dbid = PG_GETARG_OID(0);
890         int32           result;
891         int                     tot_backends = pgstat_fetch_stat_numbackends();
892         int                     beid;
893
894         result = 0;
895         for (beid = 1; beid <= tot_backends; beid++)
896         {
897                 PgBackendStatus *beentry = pgstat_fetch_stat_beentry(beid);
898
899                 if (beentry && beentry->st_databaseid == dbid)
900                         result++;
901         }
902
903         PG_RETURN_INT32(result);
904 }
905
906
907 Datum
908 pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS)
909 {
910         Oid                     dbid = PG_GETARG_OID(0);
911         int64           result;
912         PgStat_StatDBEntry *dbentry;
913
914         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
915                 result = 0;
916         else
917                 result = (int64) (dbentry->n_xact_commit);
918
919         PG_RETURN_INT64(result);
920 }
921
922
923 Datum
924 pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)
925 {
926         Oid                     dbid = PG_GETARG_OID(0);
927         int64           result;
928         PgStat_StatDBEntry *dbentry;
929
930         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
931                 result = 0;
932         else
933                 result = (int64) (dbentry->n_xact_rollback);
934
935         PG_RETURN_INT64(result);
936 }
937
938
939 Datum
940 pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)
941 {
942         Oid                     dbid = PG_GETARG_OID(0);
943         int64           result;
944         PgStat_StatDBEntry *dbentry;
945
946         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
947                 result = 0;
948         else
949                 result = (int64) (dbentry->n_blocks_fetched);
950
951         PG_RETURN_INT64(result);
952 }
953
954
955 Datum
956 pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)
957 {
958         Oid                     dbid = PG_GETARG_OID(0);
959         int64           result;
960         PgStat_StatDBEntry *dbentry;
961
962         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
963                 result = 0;
964         else
965                 result = (int64) (dbentry->n_blocks_hit);
966
967         PG_RETURN_INT64(result);
968 }
969
970
971 Datum
972 pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS)
973 {
974         Oid                     dbid = PG_GETARG_OID(0);
975         int64           result;
976         PgStat_StatDBEntry *dbentry;
977
978         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
979                 result = 0;
980         else
981                 result = (int64) (dbentry->n_tuples_returned);
982
983         PG_RETURN_INT64(result);
984 }
985
986
987 Datum
988 pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS)
989 {
990         Oid                     dbid = PG_GETARG_OID(0);
991         int64           result;
992         PgStat_StatDBEntry *dbentry;
993
994         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
995                 result = 0;
996         else
997                 result = (int64) (dbentry->n_tuples_fetched);
998
999         PG_RETURN_INT64(result);
1000 }
1001
1002
1003 Datum
1004 pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS)
1005 {
1006         Oid                     dbid = PG_GETARG_OID(0);
1007         int64           result;
1008         PgStat_StatDBEntry *dbentry;
1009
1010         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1011                 result = 0;
1012         else
1013                 result = (int64) (dbentry->n_tuples_inserted);
1014
1015         PG_RETURN_INT64(result);
1016 }
1017
1018
1019 Datum
1020 pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS)
1021 {
1022         Oid                     dbid = PG_GETARG_OID(0);
1023         int64           result;
1024         PgStat_StatDBEntry *dbentry;
1025
1026         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1027                 result = 0;
1028         else
1029                 result = (int64) (dbentry->n_tuples_updated);
1030
1031         PG_RETURN_INT64(result);
1032 }
1033
1034
1035 Datum
1036 pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS)
1037 {
1038         Oid                     dbid = PG_GETARG_OID(0);
1039         int64           result;
1040         PgStat_StatDBEntry *dbentry;
1041
1042         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1043                 result = 0;
1044         else
1045                 result = (int64) (dbentry->n_tuples_deleted);
1046
1047         PG_RETURN_INT64(result);
1048 }
1049
1050 Datum
1051 pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
1052 {
1053         PG_RETURN_INT64(pgstat_fetch_global()->timed_checkpoints);
1054 }
1055
1056 Datum
1057 pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
1058 {
1059         PG_RETURN_INT64(pgstat_fetch_global()->requested_checkpoints);
1060 }
1061
1062 Datum
1063 pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
1064 {
1065         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_checkpoints);
1066 }
1067
1068 Datum
1069 pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)
1070 {
1071         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_clean);
1072 }
1073
1074 Datum
1075 pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
1076 {
1077         PG_RETURN_INT64(pgstat_fetch_global()->maxwritten_clean);
1078 }
1079
1080 Datum
1081 pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
1082 {
1083         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_backend);
1084 }
1085
1086 Datum
1087 pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
1088 {
1089         PG_RETURN_INT64(pgstat_fetch_global()->buf_alloc);
1090 }
1091
1092
1093 /* Discard the active statistics snapshot */
1094 Datum
1095 pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
1096 {
1097         pgstat_clear_snapshot();
1098
1099         PG_RETURN_VOID();
1100 }
1101
1102
1103 /* Reset all counters for the current database */
1104 Datum
1105 pg_stat_reset(PG_FUNCTION_ARGS)
1106 {
1107         pgstat_reset_counters();
1108
1109         PG_RETURN_VOID();
1110 }