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