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