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