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