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