]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/pgstatfuncs.c
Add vacuum and analyze counters to pg_stat_*_tables views.
[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.62 2010/08/21 10:59:17 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 "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 extern Datum pg_stat_get_vacuum_count(PG_FUNCTION_ARGS);
42 extern Datum pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS);
43 extern Datum pg_stat_get_analyze_count(PG_FUNCTION_ARGS);
44 extern Datum pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS);
45
46 extern Datum pg_stat_get_function_calls(PG_FUNCTION_ARGS);
47 extern Datum pg_stat_get_function_time(PG_FUNCTION_ARGS);
48 extern Datum pg_stat_get_function_self_time(PG_FUNCTION_ARGS);
49
50 extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS);
51 extern Datum pg_stat_get_activity(PG_FUNCTION_ARGS);
52 extern Datum pg_backend_pid(PG_FUNCTION_ARGS);
53 extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS);
54 extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS);
55 extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS);
56 extern Datum pg_stat_get_backend_activity(PG_FUNCTION_ARGS);
57 extern Datum pg_stat_get_backend_waiting(PG_FUNCTION_ARGS);
58 extern Datum pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS);
59 extern Datum pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS);
60 extern Datum pg_stat_get_backend_start(PG_FUNCTION_ARGS);
61 extern Datum pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS);
62 extern Datum pg_stat_get_backend_client_port(PG_FUNCTION_ARGS);
63
64 extern Datum pg_stat_get_db_numbackends(PG_FUNCTION_ARGS);
65 extern Datum pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS);
66 extern Datum pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS);
67 extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS);
68 extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS);
69 extern Datum pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS);
70 extern Datum pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS);
71 extern Datum pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS);
72 extern Datum pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS);
73 extern Datum pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS);
74
75 extern Datum pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS);
76 extern Datum pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS);
77 extern Datum pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS);
78 extern Datum pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS);
79 extern Datum pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS);
80 extern Datum pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS);
81 extern Datum pg_stat_get_buf_alloc(PG_FUNCTION_ARGS);
82
83 extern Datum pg_stat_get_xact_numscans(PG_FUNCTION_ARGS);
84 extern Datum pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS);
85 extern Datum pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS);
86 extern Datum pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS);
87 extern Datum pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS);
88 extern Datum pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS);
89 extern Datum pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS);
90 extern Datum pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS);
91 extern Datum pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS);
92
93 extern Datum pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS);
94 extern Datum pg_stat_get_xact_function_time(PG_FUNCTION_ARGS);
95 extern Datum pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS);
96
97 extern Datum pg_stat_clear_snapshot(PG_FUNCTION_ARGS);
98 extern Datum pg_stat_reset(PG_FUNCTION_ARGS);
99 extern Datum pg_stat_reset_shared(PG_FUNCTION_ARGS);
100 extern Datum pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS);
101 extern Datum pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS);
102
103 /* Global bgwriter statistics, from bgwriter.c */
104 extern PgStat_MsgBgWriter bgwriterStats;
105
106 Datum
107 pg_stat_get_numscans(PG_FUNCTION_ARGS)
108 {
109         Oid                     relid = PG_GETARG_OID(0);
110         int64           result;
111         PgStat_StatTabEntry *tabentry;
112
113         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
114                 result = 0;
115         else
116                 result = (int64) (tabentry->numscans);
117
118         PG_RETURN_INT64(result);
119 }
120
121
122 Datum
123 pg_stat_get_tuples_returned(PG_FUNCTION_ARGS)
124 {
125         Oid                     relid = PG_GETARG_OID(0);
126         int64           result;
127         PgStat_StatTabEntry *tabentry;
128
129         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
130                 result = 0;
131         else
132                 result = (int64) (tabentry->tuples_returned);
133
134         PG_RETURN_INT64(result);
135 }
136
137
138 Datum
139 pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS)
140 {
141         Oid                     relid = PG_GETARG_OID(0);
142         int64           result;
143         PgStat_StatTabEntry *tabentry;
144
145         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
146                 result = 0;
147         else
148                 result = (int64) (tabentry->tuples_fetched);
149
150         PG_RETURN_INT64(result);
151 }
152
153
154 Datum
155 pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS)
156 {
157         Oid                     relid = PG_GETARG_OID(0);
158         int64           result;
159         PgStat_StatTabEntry *tabentry;
160
161         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
162                 result = 0;
163         else
164                 result = (int64) (tabentry->tuples_inserted);
165
166         PG_RETURN_INT64(result);
167 }
168
169
170 Datum
171 pg_stat_get_tuples_updated(PG_FUNCTION_ARGS)
172 {
173         Oid                     relid = PG_GETARG_OID(0);
174         int64           result;
175         PgStat_StatTabEntry *tabentry;
176
177         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
178                 result = 0;
179         else
180                 result = (int64) (tabentry->tuples_updated);
181
182         PG_RETURN_INT64(result);
183 }
184
185
186 Datum
187 pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS)
188 {
189         Oid                     relid = PG_GETARG_OID(0);
190         int64           result;
191         PgStat_StatTabEntry *tabentry;
192
193         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
194                 result = 0;
195         else
196                 result = (int64) (tabentry->tuples_deleted);
197
198         PG_RETURN_INT64(result);
199 }
200
201
202 Datum
203 pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS)
204 {
205         Oid                     relid = PG_GETARG_OID(0);
206         int64           result;
207         PgStat_StatTabEntry *tabentry;
208
209         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
210                 result = 0;
211         else
212                 result = (int64) (tabentry->tuples_hot_updated);
213
214         PG_RETURN_INT64(result);
215 }
216
217
218 Datum
219 pg_stat_get_live_tuples(PG_FUNCTION_ARGS)
220 {
221         Oid                     relid = PG_GETARG_OID(0);
222         int64           result;
223         PgStat_StatTabEntry *tabentry;
224
225         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
226                 result = 0;
227         else
228                 result = (int64) (tabentry->n_live_tuples);
229
230         PG_RETURN_INT64(result);
231 }
232
233
234 Datum
235 pg_stat_get_dead_tuples(PG_FUNCTION_ARGS)
236 {
237         Oid                     relid = PG_GETARG_OID(0);
238         int64           result;
239         PgStat_StatTabEntry *tabentry;
240
241         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
242                 result = 0;
243         else
244                 result = (int64) (tabentry->n_dead_tuples);
245
246         PG_RETURN_INT64(result);
247 }
248
249
250 Datum
251 pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS)
252 {
253         Oid                     relid = PG_GETARG_OID(0);
254         int64           result;
255         PgStat_StatTabEntry *tabentry;
256
257         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
258                 result = 0;
259         else
260                 result = (int64) (tabentry->blocks_fetched);
261
262         PG_RETURN_INT64(result);
263 }
264
265
266 Datum
267 pg_stat_get_blocks_hit(PG_FUNCTION_ARGS)
268 {
269         Oid                     relid = PG_GETARG_OID(0);
270         int64           result;
271         PgStat_StatTabEntry *tabentry;
272
273         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
274                 result = 0;
275         else
276                 result = (int64) (tabentry->blocks_hit);
277
278         PG_RETURN_INT64(result);
279 }
280
281 Datum
282 pg_stat_get_last_vacuum_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->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_autovacuum_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->autovac_vacuum_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_analyze_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->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_last_autoanalyze_time(PG_FUNCTION_ARGS)
337 {
338         Oid                     relid = PG_GETARG_OID(0);
339         TimestampTz result;
340         PgStat_StatTabEntry *tabentry;
341
342         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
343                 result = 0;
344         else
345                 result = tabentry->autovac_analyze_timestamp;
346
347         if (result == 0)
348                 PG_RETURN_NULL();
349         else
350                 PG_RETURN_TIMESTAMPTZ(result);
351 }
352
353 Datum
354 pg_stat_get_vacuum_count(PG_FUNCTION_ARGS)
355 {
356         Oid                     relid = PG_GETARG_OID(0);
357         int64           result;
358         PgStat_StatTabEntry     *tabentry;
359
360         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
361                 result = 0;
362         else
363                 result = (int64) (tabentry->vacuum_count);
364
365         PG_RETURN_INT64(result);
366 }
367
368 Datum
369 pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS)
370 {
371         Oid                     relid = PG_GETARG_OID(0);
372         int64           result;
373         PgStat_StatTabEntry     *tabentry;
374
375         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
376                 result = 0;
377         else
378                 result = (int64) (tabentry->autovac_vacuum_count);
379
380         PG_RETURN_INT64(result);
381 }
382
383 Datum
384 pg_stat_get_analyze_count(PG_FUNCTION_ARGS)
385 {
386         Oid                     relid = PG_GETARG_OID(0);
387         int64           result;
388         PgStat_StatTabEntry     *tabentry;
389
390         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
391                 result = 0;
392         else
393                 result = (int64) (tabentry->analyze_count);
394
395         PG_RETURN_INT64(result);
396 }
397
398 Datum
399 pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS)
400 {
401         Oid                     relid = PG_GETARG_OID(0);
402         int64           result;
403         PgStat_StatTabEntry     *tabentry;
404
405         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
406                 result = 0;
407         else
408                 result = (int64) (tabentry->autovac_analyze_count);
409
410         PG_RETURN_INT64(result);
411 }
412
413 Datum
414 pg_stat_get_function_calls(PG_FUNCTION_ARGS)
415 {
416         Oid                     funcid = PG_GETARG_OID(0);
417         PgStat_StatFuncEntry *funcentry;
418
419         if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
420                 PG_RETURN_NULL();
421         PG_RETURN_INT64(funcentry->f_numcalls);
422 }
423
424 Datum
425 pg_stat_get_function_time(PG_FUNCTION_ARGS)
426 {
427         Oid                     funcid = PG_GETARG_OID(0);
428         PgStat_StatFuncEntry *funcentry;
429
430         if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
431                 PG_RETURN_NULL();
432         PG_RETURN_INT64(funcentry->f_time);
433 }
434
435 Datum
436 pg_stat_get_function_self_time(PG_FUNCTION_ARGS)
437 {
438         Oid                     funcid = PG_GETARG_OID(0);
439         PgStat_StatFuncEntry *funcentry;
440
441         if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
442                 PG_RETURN_NULL();
443         PG_RETURN_INT64(funcentry->f_time_self);
444 }
445
446 Datum
447 pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
448 {
449         FuncCallContext *funcctx;
450         int                *fctx;
451         int32           result;
452
453         /* stuff done only on the first call of the function */
454         if (SRF_IS_FIRSTCALL())
455         {
456                 /* create a function context for cross-call persistence */
457                 funcctx = SRF_FIRSTCALL_INIT();
458
459                 fctx = MemoryContextAlloc(funcctx->multi_call_memory_ctx,
460                                                                   2 * sizeof(int));
461                 funcctx->user_fctx = fctx;
462
463                 fctx[0] = 0;
464                 fctx[1] = pgstat_fetch_stat_numbackends();
465         }
466
467         /* stuff done on every call of the function */
468         funcctx = SRF_PERCALL_SETUP();
469         fctx = funcctx->user_fctx;
470
471         fctx[0] += 1;
472         result = fctx[0];
473
474         if (result <= fctx[1])
475         {
476                 /* do when there is more left to send */
477                 SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
478         }
479         else
480         {
481                 /* do when there is no more left */
482                 SRF_RETURN_DONE(funcctx);
483         }
484 }
485
486 Datum
487 pg_stat_get_activity(PG_FUNCTION_ARGS)
488 {
489         FuncCallContext *funcctx;
490
491         if (SRF_IS_FIRSTCALL())
492         {
493                 MemoryContext oldcontext;
494                 TupleDesc       tupdesc;
495
496                 funcctx = SRF_FIRSTCALL_INIT();
497
498                 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
499
500                 tupdesc = CreateTemplateTupleDesc(11, false);
501                 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid", OIDOID, -1, 0);
502                 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "procpid", INT4OID, -1, 0);
503                 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "usesysid", OIDOID, -1, 0);
504                 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "application_name", TEXTOID, -1, 0);
505                 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "current_query", TEXTOID, -1, 0);
506                 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "waiting", BOOLOID, -1, 0);
507                 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "act_start", TIMESTAMPTZOID, -1, 0);
508                 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "query_start", TIMESTAMPTZOID, -1, 0);
509                 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "backend_start", TIMESTAMPTZOID, -1, 0);
510                 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "client_addr", INETOID, -1, 0);
511                 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "client_port", INT4OID, -1, 0);
512
513                 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
514
515                 funcctx->user_fctx = palloc0(sizeof(int));
516                 if (PG_ARGISNULL(0))
517                 {
518                         /* Get all backends */
519                         funcctx->max_calls = pgstat_fetch_stat_numbackends();
520                 }
521                 else
522                 {
523                         /*
524                          * Get one backend - locate by pid.
525                          *
526                          * We lookup the backend early, so we can return zero rows if it
527                          * doesn't exist, instead of returning a single row full of NULLs.
528                          */
529                         int                     pid = PG_GETARG_INT32(0);
530                         int                     i;
531                         int                     n = pgstat_fetch_stat_numbackends();
532
533                         for (i = 1; i <= n; i++)
534                         {
535                                 PgBackendStatus *be = pgstat_fetch_stat_beentry(i);
536
537                                 if (be)
538                                 {
539                                         if (be->st_procpid == pid)
540                                         {
541                                                 *(int *) (funcctx->user_fctx) = i;
542                                                 break;
543                                         }
544                                 }
545                         }
546
547                         if (*(int *) (funcctx->user_fctx) == 0)
548                                 /* Pid not found, return zero rows */
549                                 funcctx->max_calls = 0;
550                         else
551                                 funcctx->max_calls = 1;
552                 }
553
554                 MemoryContextSwitchTo(oldcontext);
555         }
556
557         /* stuff done on every call of the function */
558         funcctx = SRF_PERCALL_SETUP();
559
560         if (funcctx->call_cntr < funcctx->max_calls)
561         {
562                 /* for each row */
563                 Datum           values[11];
564                 bool            nulls[11];
565                 HeapTuple       tuple;
566                 PgBackendStatus *beentry;
567                 SockAddr        zero_clientaddr;
568
569                 MemSet(values, 0, sizeof(values));
570                 MemSet(nulls, 0, sizeof(nulls));
571
572                 if (*(int *) (funcctx->user_fctx) > 0)
573                 {
574                         /* Get specific pid slot */
575                         beentry = pgstat_fetch_stat_beentry(*(int *) (funcctx->user_fctx));
576                 }
577                 else
578                 {
579                         /* Get the next one in the list */
580                         beentry = pgstat_fetch_stat_beentry(funcctx->call_cntr + 1);            /* 1-based index */
581                 }
582                 if (!beentry)
583                 {
584                         int                     i;
585
586                         for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++)
587                                 nulls[i] = true;
588
589                         nulls[4] = false;
590                         values[4] = CStringGetTextDatum("<backend information not available>");
591
592                         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
593                         SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
594                 }
595
596                 /* Values available to all callers */
597                 values[0] = ObjectIdGetDatum(beentry->st_databaseid);
598                 values[1] = Int32GetDatum(beentry->st_procpid);
599                 values[2] = ObjectIdGetDatum(beentry->st_userid);
600                 if (beentry->st_appname)
601                         values[3] = CStringGetTextDatum(beentry->st_appname);
602                 else
603                         nulls[3] = true;
604
605                 /* Values only available to same user or superuser */
606                 if (superuser() || beentry->st_userid == GetUserId())
607                 {
608                         if (*(beentry->st_activity) == '\0')
609                         {
610                                 values[4] = CStringGetTextDatum("<command string not enabled>");
611                         }
612                         else
613                         {
614                                 values[4] = CStringGetTextDatum(beentry->st_activity);
615                         }
616
617                         values[5] = BoolGetDatum(beentry->st_waiting);
618
619                         if (beentry->st_xact_start_timestamp != 0)
620                                 values[6] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
621                         else
622                                 nulls[6] = true;
623
624                         if (beentry->st_activity_start_timestamp != 0)
625                                 values[7] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
626                         else
627                                 nulls[7] = true;
628
629                         if (beentry->st_proc_start_timestamp != 0)
630                                 values[8] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
631                         else
632                                 nulls[8] = true;
633
634                         /* A zeroed client addr means we don't know */
635                         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
636                         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
637                                            sizeof(zero_clientaddr) == 0))
638                         {
639                                 nulls[9] = true;
640                                 nulls[10] = true;
641                         }
642                         else
643                         {
644                                 if (beentry->st_clientaddr.addr.ss_family == AF_INET
645 #ifdef HAVE_IPV6
646                                         || beentry->st_clientaddr.addr.ss_family == AF_INET6
647 #endif
648                                         )
649                                 {
650                                         char            remote_host[NI_MAXHOST];
651                                         char            remote_port[NI_MAXSERV];
652                                         int                     ret;
653
654                                         remote_host[0] = '\0';
655                                         remote_port[0] = '\0';
656                                         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
657                                                                                          beentry->st_clientaddr.salen,
658                                                                                          remote_host, sizeof(remote_host),
659                                                                                          remote_port, sizeof(remote_port),
660                                                                                          NI_NUMERICHOST | NI_NUMERICSERV);
661                                         if (ret)
662                                         {
663                                                 nulls[9] = true;
664                                                 nulls[10] = true;
665                                         }
666                                         else
667                                         {
668                                                 clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
669                                                 values[9] = DirectFunctionCall1(inet_in,
670                                                                                            CStringGetDatum(remote_host));
671                                                 values[10] = Int32GetDatum(atoi(remote_port));
672                                         }
673                                 }
674                                 else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
675                                 {
676                                         /*
677                                          * Unix sockets always reports NULL for host and -1 for
678                                          * port, so it's possible to tell the difference to
679                                          * connections we have no permissions to view, or with
680                                          * errors.
681                                          */
682                                         nulls[9] = true;
683                                         values[10] = DatumGetInt32(-1);
684                                 }
685                                 else
686                                 {
687                                         /* Unknown address type, should never happen */
688                                         nulls[9] = true;
689                                         nulls[10] = true;
690                                 }
691                         }
692                 }
693                 else
694                 {
695                         /* No permissions to view data about this session */
696                         values[4] = CStringGetTextDatum("<insufficient privilege>");
697                         nulls[5] = true;
698                         nulls[6] = true;
699                         nulls[7] = true;
700                         nulls[8] = true;
701                         nulls[9] = true;
702                         nulls[10] = true;
703                 }
704
705                 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
706
707                 SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
708         }
709         else
710         {
711                 /* nothing left */
712                 SRF_RETURN_DONE(funcctx);
713         }
714 }
715
716
717 Datum
718 pg_backend_pid(PG_FUNCTION_ARGS)
719 {
720         PG_RETURN_INT32(MyProcPid);
721 }
722
723
724 Datum
725 pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
726 {
727         int32           beid = PG_GETARG_INT32(0);
728         PgBackendStatus *beentry;
729
730         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
731                 PG_RETURN_NULL();
732
733         PG_RETURN_INT32(beentry->st_procpid);
734 }
735
736
737 Datum
738 pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
739 {
740         int32           beid = PG_GETARG_INT32(0);
741         PgBackendStatus *beentry;
742
743         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
744                 PG_RETURN_NULL();
745
746         PG_RETURN_OID(beentry->st_databaseid);
747 }
748
749
750 Datum
751 pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
752 {
753         int32           beid = PG_GETARG_INT32(0);
754         PgBackendStatus *beentry;
755
756         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
757                 PG_RETURN_NULL();
758
759         PG_RETURN_OID(beentry->st_userid);
760 }
761
762
763 Datum
764 pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
765 {
766         int32           beid = PG_GETARG_INT32(0);
767         PgBackendStatus *beentry;
768         const char *activity;
769
770         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
771                 activity = "<backend information not available>";
772         else if (!superuser() && beentry->st_userid != GetUserId())
773                 activity = "<insufficient privilege>";
774         else if (*(beentry->st_activity) == '\0')
775                 activity = "<command string not enabled>";
776         else
777                 activity = beentry->st_activity;
778
779         PG_RETURN_TEXT_P(cstring_to_text(activity));
780 }
781
782
783 Datum
784 pg_stat_get_backend_waiting(PG_FUNCTION_ARGS)
785 {
786         int32           beid = PG_GETARG_INT32(0);
787         bool            result;
788         PgBackendStatus *beentry;
789
790         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
791                 PG_RETURN_NULL();
792
793         if (!superuser() && beentry->st_userid != GetUserId())
794                 PG_RETURN_NULL();
795
796         result = beentry->st_waiting;
797
798         PG_RETURN_BOOL(result);
799 }
800
801
802 Datum
803 pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
804 {
805         int32           beid = PG_GETARG_INT32(0);
806         TimestampTz result;
807         PgBackendStatus *beentry;
808
809         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
810                 PG_RETURN_NULL();
811
812         if (!superuser() && beentry->st_userid != GetUserId())
813                 PG_RETURN_NULL();
814
815         result = beentry->st_activity_start_timestamp;
816
817         /*
818          * No time recorded for start of current query -- this is the case if the
819          * user hasn't enabled query-level stats collection.
820          */
821         if (result == 0)
822                 PG_RETURN_NULL();
823
824         PG_RETURN_TIMESTAMPTZ(result);
825 }
826
827
828 Datum
829 pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)
830 {
831         int32           beid = PG_GETARG_INT32(0);
832         TimestampTz result;
833         PgBackendStatus *beentry;
834
835         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
836                 PG_RETURN_NULL();
837
838         if (!superuser() && beentry->st_userid != GetUserId())
839                 PG_RETURN_NULL();
840
841         result = beentry->st_xact_start_timestamp;
842
843         if (result == 0)                        /* not in a transaction */
844                 PG_RETURN_NULL();
845
846         PG_RETURN_TIMESTAMPTZ(result);
847 }
848
849
850 Datum
851 pg_stat_get_backend_start(PG_FUNCTION_ARGS)
852 {
853         int32           beid = PG_GETARG_INT32(0);
854         TimestampTz result;
855         PgBackendStatus *beentry;
856
857         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
858                 PG_RETURN_NULL();
859
860         if (!superuser() && beentry->st_userid != GetUserId())
861                 PG_RETURN_NULL();
862
863         result = beentry->st_proc_start_timestamp;
864
865         if (result == 0)                        /* probably can't happen? */
866                 PG_RETURN_NULL();
867
868         PG_RETURN_TIMESTAMPTZ(result);
869 }
870
871
872 Datum
873 pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
874 {
875         int32           beid = PG_GETARG_INT32(0);
876         PgBackendStatus *beentry;
877         SockAddr        zero_clientaddr;
878         char            remote_host[NI_MAXHOST];
879         int                     ret;
880
881         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
882                 PG_RETURN_NULL();
883
884         if (!superuser() && beentry->st_userid != GetUserId())
885                 PG_RETURN_NULL();
886
887         /* A zeroed client addr means we don't know */
888         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
889         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
890                            sizeof(zero_clientaddr) == 0))
891                 PG_RETURN_NULL();
892
893         switch (beentry->st_clientaddr.addr.ss_family)
894         {
895                 case AF_INET:
896 #ifdef HAVE_IPV6
897                 case AF_INET6:
898 #endif
899                         break;
900                 default:
901                         PG_RETURN_NULL();
902         }
903
904         remote_host[0] = '\0';
905         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
906                                                          beentry->st_clientaddr.salen,
907                                                          remote_host, sizeof(remote_host),
908                                                          NULL, 0,
909                                                          NI_NUMERICHOST | NI_NUMERICSERV);
910         if (ret)
911                 PG_RETURN_NULL();
912
913         clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
914
915         PG_RETURN_INET_P(DirectFunctionCall1(inet_in,
916                                                                                  CStringGetDatum(remote_host)));
917 }
918
919 Datum
920 pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
921 {
922         int32           beid = PG_GETARG_INT32(0);
923         PgBackendStatus *beentry;
924         SockAddr        zero_clientaddr;
925         char            remote_port[NI_MAXSERV];
926         int                     ret;
927
928         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
929                 PG_RETURN_NULL();
930
931         if (!superuser() && beentry->st_userid != GetUserId())
932                 PG_RETURN_NULL();
933
934         /* A zeroed client addr means we don't know */
935         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
936         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
937                            sizeof(zero_clientaddr) == 0))
938                 PG_RETURN_NULL();
939
940         switch (beentry->st_clientaddr.addr.ss_family)
941         {
942                 case AF_INET:
943 #ifdef HAVE_IPV6
944                 case AF_INET6:
945 #endif
946                         break;
947                 case AF_UNIX:
948                         PG_RETURN_INT32(-1);
949                 default:
950                         PG_RETURN_NULL();
951         }
952
953         remote_port[0] = '\0';
954         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
955                                                          beentry->st_clientaddr.salen,
956                                                          NULL, 0,
957                                                          remote_port, sizeof(remote_port),
958                                                          NI_NUMERICHOST | NI_NUMERICSERV);
959         if (ret)
960                 PG_RETURN_NULL();
961
962         PG_RETURN_DATUM(DirectFunctionCall1(int4in,
963                                                                                 CStringGetDatum(remote_port)));
964 }
965
966
967 Datum
968 pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
969 {
970         Oid                     dbid = PG_GETARG_OID(0);
971         int32           result;
972         int                     tot_backends = pgstat_fetch_stat_numbackends();
973         int                     beid;
974
975         result = 0;
976         for (beid = 1; beid <= tot_backends; beid++)
977         {
978                 PgBackendStatus *beentry = pgstat_fetch_stat_beentry(beid);
979
980                 if (beentry && beentry->st_databaseid == dbid)
981                         result++;
982         }
983
984         PG_RETURN_INT32(result);
985 }
986
987
988 Datum
989 pg_stat_get_db_xact_commit(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_xact_commit);
999
1000         PG_RETURN_INT64(result);
1001 }
1002
1003
1004 Datum
1005 pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)
1006 {
1007         Oid                     dbid = PG_GETARG_OID(0);
1008         int64           result;
1009         PgStat_StatDBEntry *dbentry;
1010
1011         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1012                 result = 0;
1013         else
1014                 result = (int64) (dbentry->n_xact_rollback);
1015
1016         PG_RETURN_INT64(result);
1017 }
1018
1019
1020 Datum
1021 pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)
1022 {
1023         Oid                     dbid = PG_GETARG_OID(0);
1024         int64           result;
1025         PgStat_StatDBEntry *dbentry;
1026
1027         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1028                 result = 0;
1029         else
1030                 result = (int64) (dbentry->n_blocks_fetched);
1031
1032         PG_RETURN_INT64(result);
1033 }
1034
1035
1036 Datum
1037 pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)
1038 {
1039         Oid                     dbid = PG_GETARG_OID(0);
1040         int64           result;
1041         PgStat_StatDBEntry *dbentry;
1042
1043         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1044                 result = 0;
1045         else
1046                 result = (int64) (dbentry->n_blocks_hit);
1047
1048         PG_RETURN_INT64(result);
1049 }
1050
1051
1052 Datum
1053 pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS)
1054 {
1055         Oid                     dbid = PG_GETARG_OID(0);
1056         int64           result;
1057         PgStat_StatDBEntry *dbentry;
1058
1059         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1060                 result = 0;
1061         else
1062                 result = (int64) (dbentry->n_tuples_returned);
1063
1064         PG_RETURN_INT64(result);
1065 }
1066
1067
1068 Datum
1069 pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS)
1070 {
1071         Oid                     dbid = PG_GETARG_OID(0);
1072         int64           result;
1073         PgStat_StatDBEntry *dbentry;
1074
1075         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1076                 result = 0;
1077         else
1078                 result = (int64) (dbentry->n_tuples_fetched);
1079
1080         PG_RETURN_INT64(result);
1081 }
1082
1083
1084 Datum
1085 pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS)
1086 {
1087         Oid                     dbid = PG_GETARG_OID(0);
1088         int64           result;
1089         PgStat_StatDBEntry *dbentry;
1090
1091         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1092                 result = 0;
1093         else
1094                 result = (int64) (dbentry->n_tuples_inserted);
1095
1096         PG_RETURN_INT64(result);
1097 }
1098
1099
1100 Datum
1101 pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS)
1102 {
1103         Oid                     dbid = PG_GETARG_OID(0);
1104         int64           result;
1105         PgStat_StatDBEntry *dbentry;
1106
1107         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1108                 result = 0;
1109         else
1110                 result = (int64) (dbentry->n_tuples_updated);
1111
1112         PG_RETURN_INT64(result);
1113 }
1114
1115
1116 Datum
1117 pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS)
1118 {
1119         Oid                     dbid = PG_GETARG_OID(0);
1120         int64           result;
1121         PgStat_StatDBEntry *dbentry;
1122
1123         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1124                 result = 0;
1125         else
1126                 result = (int64) (dbentry->n_tuples_deleted);
1127
1128         PG_RETURN_INT64(result);
1129 }
1130
1131 Datum
1132 pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
1133 {
1134         PG_RETURN_INT64(pgstat_fetch_global()->timed_checkpoints);
1135 }
1136
1137 Datum
1138 pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
1139 {
1140         PG_RETURN_INT64(pgstat_fetch_global()->requested_checkpoints);
1141 }
1142
1143 Datum
1144 pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
1145 {
1146         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_checkpoints);
1147 }
1148
1149 Datum
1150 pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)
1151 {
1152         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_clean);
1153 }
1154
1155 Datum
1156 pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
1157 {
1158         PG_RETURN_INT64(pgstat_fetch_global()->maxwritten_clean);
1159 }
1160
1161 Datum
1162 pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
1163 {
1164         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_backend);
1165 }
1166
1167 Datum
1168 pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
1169 {
1170         PG_RETURN_INT64(pgstat_fetch_global()->buf_alloc);
1171 }
1172
1173 Datum
1174 pg_stat_get_xact_numscans(PG_FUNCTION_ARGS)
1175 {
1176         Oid                     relid = PG_GETARG_OID(0);
1177         int64           result;
1178         PgStat_TableStatus *tabentry;
1179
1180         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1181                 result = 0;
1182         else
1183                 result = (int64) (tabentry->t_counts.t_numscans);
1184
1185         PG_RETURN_INT64(result);
1186 }
1187
1188 Datum
1189 pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS)
1190 {
1191         Oid                     relid = PG_GETARG_OID(0);
1192         int64           result;
1193         PgStat_TableStatus *tabentry;
1194
1195         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1196                 result = 0;
1197         else
1198                 result = (int64) (tabentry->t_counts.t_tuples_returned);
1199
1200         PG_RETURN_INT64(result);
1201 }
1202
1203 Datum
1204 pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS)
1205 {
1206         Oid                     relid = PG_GETARG_OID(0);
1207         int64           result;
1208         PgStat_TableStatus *tabentry;
1209
1210         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1211                 result = 0;
1212         else
1213                 result = (int64) (tabentry->t_counts.t_tuples_fetched);
1214
1215         PG_RETURN_INT64(result);
1216 }
1217
1218 Datum
1219 pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS)
1220 {
1221         Oid                     relid = PG_GETARG_OID(0);
1222         int64           result;
1223         PgStat_TableStatus *tabentry;
1224         PgStat_TableXactStatus *trans;
1225
1226         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1227                 result = 0;
1228         else
1229         {
1230                 result = tabentry->t_counts.t_tuples_inserted;
1231                 /* live subtransactions' counts aren't in t_tuples_inserted yet */
1232                 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1233                         result += trans->tuples_inserted;
1234         }
1235
1236         PG_RETURN_INT64(result);
1237 }
1238
1239 Datum
1240 pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS)
1241 {
1242         Oid                     relid = PG_GETARG_OID(0);
1243         int64           result;
1244         PgStat_TableStatus *tabentry;
1245         PgStat_TableXactStatus *trans;
1246
1247         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1248                 result = 0;
1249         else
1250         {
1251                 result = tabentry->t_counts.t_tuples_updated;
1252                 /* live subtransactions' counts aren't in t_tuples_updated yet */
1253                 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1254                         result += trans->tuples_updated;
1255         }
1256
1257         PG_RETURN_INT64(result);
1258 }
1259
1260 Datum
1261 pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS)
1262 {
1263         Oid                     relid = PG_GETARG_OID(0);
1264         int64           result;
1265         PgStat_TableStatus *tabentry;
1266         PgStat_TableXactStatus *trans;
1267
1268         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1269                 result = 0;
1270         else
1271         {
1272                 result = tabentry->t_counts.t_tuples_deleted;
1273                 /* live subtransactions' counts aren't in t_tuples_deleted yet */
1274                 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1275                         result += trans->tuples_deleted;
1276         }
1277
1278         PG_RETURN_INT64(result);
1279 }
1280
1281 Datum
1282 pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS)
1283 {
1284         Oid                     relid = PG_GETARG_OID(0);
1285         int64           result;
1286         PgStat_TableStatus *tabentry;
1287
1288         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1289                 result = 0;
1290         else
1291                 result = (int64) (tabentry->t_counts.t_tuples_hot_updated);
1292
1293         PG_RETURN_INT64(result);
1294 }
1295
1296 Datum
1297 pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS)
1298 {
1299         Oid                     relid = PG_GETARG_OID(0);
1300         int64           result;
1301         PgStat_TableStatus *tabentry;
1302
1303         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1304                 result = 0;
1305         else
1306                 result = (int64) (tabentry->t_counts.t_blocks_fetched);
1307
1308         PG_RETURN_INT64(result);
1309 }
1310
1311 Datum
1312 pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS)
1313 {
1314         Oid                     relid = PG_GETARG_OID(0);
1315         int64           result;
1316         PgStat_TableStatus *tabentry;
1317
1318         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1319                 result = 0;
1320         else
1321                 result = (int64) (tabentry->t_counts.t_blocks_hit);
1322
1323         PG_RETURN_INT64(result);
1324 }
1325
1326 Datum
1327 pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
1328 {
1329         Oid                     funcid = PG_GETARG_OID(0);
1330         PgStat_BackendFunctionEntry *funcentry;
1331
1332         if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1333                 PG_RETURN_NULL();
1334         PG_RETURN_INT64(funcentry->f_counts.f_numcalls);
1335 }
1336
1337 Datum
1338 pg_stat_get_xact_function_time(PG_FUNCTION_ARGS)
1339 {
1340         Oid                     funcid = PG_GETARG_OID(0);
1341         PgStat_BackendFunctionEntry *funcentry;
1342
1343         if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1344                 PG_RETURN_NULL();
1345         PG_RETURN_INT64(INSTR_TIME_GET_MICROSEC(funcentry->f_counts.f_time));
1346 }
1347
1348 Datum
1349 pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS)
1350 {
1351         Oid                     funcid = PG_GETARG_OID(0);
1352         PgStat_BackendFunctionEntry *funcentry;
1353
1354         if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1355                 PG_RETURN_NULL();
1356         PG_RETURN_INT64(INSTR_TIME_GET_MICROSEC(funcentry->f_counts.f_time_self));
1357 }
1358
1359
1360 /* Discard the active statistics snapshot */
1361 Datum
1362 pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
1363 {
1364         pgstat_clear_snapshot();
1365
1366         PG_RETURN_VOID();
1367 }
1368
1369
1370 /* Reset all counters for the current database */
1371 Datum
1372 pg_stat_reset(PG_FUNCTION_ARGS)
1373 {
1374         pgstat_reset_counters();
1375
1376         PG_RETURN_VOID();
1377 }
1378
1379 /* Reset some shared cluster-wide counters */
1380 Datum
1381 pg_stat_reset_shared(PG_FUNCTION_ARGS)
1382 {
1383         char       *target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1384
1385         pgstat_reset_shared_counters(target);
1386
1387         PG_RETURN_VOID();
1388 }
1389
1390 /* Reset a a single counter in the current database */
1391 Datum
1392 pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
1393 {
1394         Oid                     taboid = PG_GETARG_OID(0);
1395
1396         pgstat_reset_single_counter(taboid, RESET_TABLE);
1397
1398         PG_RETURN_VOID();
1399 }
1400
1401 Datum
1402 pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
1403 {
1404         Oid                     funcoid = PG_GETARG_OID(0);
1405
1406         pgstat_reset_single_counter(funcoid, RESET_FUNCTION);
1407
1408         PG_RETURN_VOID();
1409 }