]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/pgstatfuncs.c
Update copyright for 2015
[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-2015, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/utils/adt/pgstatfuncs.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/htup_details.h"
18 #include "catalog/pg_type.h"
19 #include "funcapi.h"
20 #include "libpq/ip.h"
21 #include "miscadmin.h"
22 #include "pgstat.h"
23 #include "utils/builtins.h"
24 #include "utils/inet.h"
25 #include "utils/timestamp.h"
26
27 /* bogus ... these externs should be in a header file */
28 extern Datum pg_stat_get_numscans(PG_FUNCTION_ARGS);
29 extern Datum pg_stat_get_tuples_returned(PG_FUNCTION_ARGS);
30 extern Datum pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS);
31 extern Datum pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS);
32 extern Datum pg_stat_get_tuples_updated(PG_FUNCTION_ARGS);
33 extern Datum pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS);
34 extern Datum pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS);
35 extern Datum pg_stat_get_live_tuples(PG_FUNCTION_ARGS);
36 extern Datum pg_stat_get_dead_tuples(PG_FUNCTION_ARGS);
37 extern Datum pg_stat_get_mod_since_analyze(PG_FUNCTION_ARGS);
38 extern Datum pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS);
39 extern Datum pg_stat_get_blocks_hit(PG_FUNCTION_ARGS);
40 extern Datum pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS);
41 extern Datum pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS);
42 extern Datum pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS);
43 extern Datum pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS);
44 extern Datum pg_stat_get_vacuum_count(PG_FUNCTION_ARGS);
45 extern Datum pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS);
46 extern Datum pg_stat_get_analyze_count(PG_FUNCTION_ARGS);
47 extern Datum pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS);
48
49 extern Datum pg_stat_get_function_calls(PG_FUNCTION_ARGS);
50 extern Datum pg_stat_get_function_total_time(PG_FUNCTION_ARGS);
51 extern Datum pg_stat_get_function_self_time(PG_FUNCTION_ARGS);
52
53 extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS);
54 extern Datum pg_stat_get_activity(PG_FUNCTION_ARGS);
55 extern Datum pg_backend_pid(PG_FUNCTION_ARGS);
56 extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS);
57 extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS);
58 extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS);
59 extern Datum pg_stat_get_backend_activity(PG_FUNCTION_ARGS);
60 extern Datum pg_stat_get_backend_waiting(PG_FUNCTION_ARGS);
61 extern Datum pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS);
62 extern Datum pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS);
63 extern Datum pg_stat_get_backend_start(PG_FUNCTION_ARGS);
64 extern Datum pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS);
65 extern Datum pg_stat_get_backend_client_port(PG_FUNCTION_ARGS);
66
67 extern Datum pg_stat_get_db_numbackends(PG_FUNCTION_ARGS);
68 extern Datum pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS);
69 extern Datum pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS);
70 extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS);
71 extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS);
72 extern Datum pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS);
73 extern Datum pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS);
74 extern Datum pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS);
75 extern Datum pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS);
76 extern Datum pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS);
77 extern Datum pg_stat_get_db_conflict_tablespace(PG_FUNCTION_ARGS);
78 extern Datum pg_stat_get_db_conflict_lock(PG_FUNCTION_ARGS);
79 extern Datum pg_stat_get_db_conflict_snapshot(PG_FUNCTION_ARGS);
80 extern Datum pg_stat_get_db_conflict_bufferpin(PG_FUNCTION_ARGS);
81 extern Datum pg_stat_get_db_conflict_startup_deadlock(PG_FUNCTION_ARGS);
82 extern Datum pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS);
83 extern Datum pg_stat_get_db_deadlocks(PG_FUNCTION_ARGS);
84 extern Datum pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS);
85 extern Datum pg_stat_get_db_temp_files(PG_FUNCTION_ARGS);
86 extern Datum pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS);
87 extern Datum pg_stat_get_db_blk_read_time(PG_FUNCTION_ARGS);
88 extern Datum pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS);
89
90 extern Datum pg_stat_get_archiver(PG_FUNCTION_ARGS);
91
92 extern Datum pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS);
93 extern Datum pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS);
94 extern Datum pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS);
95 extern Datum pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS);
96 extern Datum pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS);
97 extern Datum pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS);
98 extern Datum pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS);
99 extern Datum pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS);
100 extern Datum pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS);
101 extern Datum pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS);
102 extern Datum pg_stat_get_buf_alloc(PG_FUNCTION_ARGS);
103
104 extern Datum pg_stat_get_xact_numscans(PG_FUNCTION_ARGS);
105 extern Datum pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS);
106 extern Datum pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS);
107 extern Datum pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS);
108 extern Datum pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS);
109 extern Datum pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS);
110 extern Datum pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS);
111 extern Datum pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS);
112 extern Datum pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS);
113
114 extern Datum pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS);
115 extern Datum pg_stat_get_xact_function_total_time(PG_FUNCTION_ARGS);
116 extern Datum pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS);
117
118 extern Datum pg_stat_clear_snapshot(PG_FUNCTION_ARGS);
119 extern Datum pg_stat_reset(PG_FUNCTION_ARGS);
120 extern Datum pg_stat_reset_shared(PG_FUNCTION_ARGS);
121 extern Datum pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS);
122 extern Datum pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS);
123
124 /* Global bgwriter statistics, from bgwriter.c */
125 extern PgStat_MsgBgWriter bgwriterStats;
126
127 Datum
128 pg_stat_get_numscans(PG_FUNCTION_ARGS)
129 {
130         Oid                     relid = PG_GETARG_OID(0);
131         int64           result;
132         PgStat_StatTabEntry *tabentry;
133
134         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
135                 result = 0;
136         else
137                 result = (int64) (tabentry->numscans);
138
139         PG_RETURN_INT64(result);
140 }
141
142
143 Datum
144 pg_stat_get_tuples_returned(PG_FUNCTION_ARGS)
145 {
146         Oid                     relid = PG_GETARG_OID(0);
147         int64           result;
148         PgStat_StatTabEntry *tabentry;
149
150         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
151                 result = 0;
152         else
153                 result = (int64) (tabentry->tuples_returned);
154
155         PG_RETURN_INT64(result);
156 }
157
158
159 Datum
160 pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS)
161 {
162         Oid                     relid = PG_GETARG_OID(0);
163         int64           result;
164         PgStat_StatTabEntry *tabentry;
165
166         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
167                 result = 0;
168         else
169                 result = (int64) (tabentry->tuples_fetched);
170
171         PG_RETURN_INT64(result);
172 }
173
174
175 Datum
176 pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS)
177 {
178         Oid                     relid = PG_GETARG_OID(0);
179         int64           result;
180         PgStat_StatTabEntry *tabentry;
181
182         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
183                 result = 0;
184         else
185                 result = (int64) (tabentry->tuples_inserted);
186
187         PG_RETURN_INT64(result);
188 }
189
190
191 Datum
192 pg_stat_get_tuples_updated(PG_FUNCTION_ARGS)
193 {
194         Oid                     relid = PG_GETARG_OID(0);
195         int64           result;
196         PgStat_StatTabEntry *tabentry;
197
198         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
199                 result = 0;
200         else
201                 result = (int64) (tabentry->tuples_updated);
202
203         PG_RETURN_INT64(result);
204 }
205
206
207 Datum
208 pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS)
209 {
210         Oid                     relid = PG_GETARG_OID(0);
211         int64           result;
212         PgStat_StatTabEntry *tabentry;
213
214         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
215                 result = 0;
216         else
217                 result = (int64) (tabentry->tuples_deleted);
218
219         PG_RETURN_INT64(result);
220 }
221
222
223 Datum
224 pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS)
225 {
226         Oid                     relid = PG_GETARG_OID(0);
227         int64           result;
228         PgStat_StatTabEntry *tabentry;
229
230         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
231                 result = 0;
232         else
233                 result = (int64) (tabentry->tuples_hot_updated);
234
235         PG_RETURN_INT64(result);
236 }
237
238
239 Datum
240 pg_stat_get_live_tuples(PG_FUNCTION_ARGS)
241 {
242         Oid                     relid = PG_GETARG_OID(0);
243         int64           result;
244         PgStat_StatTabEntry *tabentry;
245
246         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
247                 result = 0;
248         else
249                 result = (int64) (tabentry->n_live_tuples);
250
251         PG_RETURN_INT64(result);
252 }
253
254
255 Datum
256 pg_stat_get_dead_tuples(PG_FUNCTION_ARGS)
257 {
258         Oid                     relid = PG_GETARG_OID(0);
259         int64           result;
260         PgStat_StatTabEntry *tabentry;
261
262         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
263                 result = 0;
264         else
265                 result = (int64) (tabentry->n_dead_tuples);
266
267         PG_RETURN_INT64(result);
268 }
269
270
271 Datum
272 pg_stat_get_mod_since_analyze(PG_FUNCTION_ARGS)
273 {
274         Oid                     relid = PG_GETARG_OID(0);
275         int64           result;
276         PgStat_StatTabEntry *tabentry;
277
278         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
279                 result = 0;
280         else
281                 result = (int64) (tabentry->changes_since_analyze);
282
283         PG_RETURN_INT64(result);
284 }
285
286
287 Datum
288 pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS)
289 {
290         Oid                     relid = PG_GETARG_OID(0);
291         int64           result;
292         PgStat_StatTabEntry *tabentry;
293
294         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
295                 result = 0;
296         else
297                 result = (int64) (tabentry->blocks_fetched);
298
299         PG_RETURN_INT64(result);
300 }
301
302
303 Datum
304 pg_stat_get_blocks_hit(PG_FUNCTION_ARGS)
305 {
306         Oid                     relid = PG_GETARG_OID(0);
307         int64           result;
308         PgStat_StatTabEntry *tabentry;
309
310         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
311                 result = 0;
312         else
313                 result = (int64) (tabentry->blocks_hit);
314
315         PG_RETURN_INT64(result);
316 }
317
318 Datum
319 pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS)
320 {
321         Oid                     relid = PG_GETARG_OID(0);
322         TimestampTz result;
323         PgStat_StatTabEntry *tabentry;
324
325         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
326                 result = 0;
327         else
328                 result = tabentry->vacuum_timestamp;
329
330         if (result == 0)
331                 PG_RETURN_NULL();
332         else
333                 PG_RETURN_TIMESTAMPTZ(result);
334 }
335
336 Datum
337 pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS)
338 {
339         Oid                     relid = PG_GETARG_OID(0);
340         TimestampTz result;
341         PgStat_StatTabEntry *tabentry;
342
343         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
344                 result = 0;
345         else
346                 result = tabentry->autovac_vacuum_timestamp;
347
348         if (result == 0)
349                 PG_RETURN_NULL();
350         else
351                 PG_RETURN_TIMESTAMPTZ(result);
352 }
353
354 Datum
355 pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS)
356 {
357         Oid                     relid = PG_GETARG_OID(0);
358         TimestampTz result;
359         PgStat_StatTabEntry *tabentry;
360
361         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
362                 result = 0;
363         else
364                 result = tabentry->analyze_timestamp;
365
366         if (result == 0)
367                 PG_RETURN_NULL();
368         else
369                 PG_RETURN_TIMESTAMPTZ(result);
370 }
371
372 Datum
373 pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS)
374 {
375         Oid                     relid = PG_GETARG_OID(0);
376         TimestampTz result;
377         PgStat_StatTabEntry *tabentry;
378
379         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
380                 result = 0;
381         else
382                 result = tabentry->autovac_analyze_timestamp;
383
384         if (result == 0)
385                 PG_RETURN_NULL();
386         else
387                 PG_RETURN_TIMESTAMPTZ(result);
388 }
389
390 Datum
391 pg_stat_get_vacuum_count(PG_FUNCTION_ARGS)
392 {
393         Oid                     relid = PG_GETARG_OID(0);
394         int64           result;
395         PgStat_StatTabEntry *tabentry;
396
397         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
398                 result = 0;
399         else
400                 result = (int64) (tabentry->vacuum_count);
401
402         PG_RETURN_INT64(result);
403 }
404
405 Datum
406 pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS)
407 {
408         Oid                     relid = PG_GETARG_OID(0);
409         int64           result;
410         PgStat_StatTabEntry *tabentry;
411
412         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
413                 result = 0;
414         else
415                 result = (int64) (tabentry->autovac_vacuum_count);
416
417         PG_RETURN_INT64(result);
418 }
419
420 Datum
421 pg_stat_get_analyze_count(PG_FUNCTION_ARGS)
422 {
423         Oid                     relid = PG_GETARG_OID(0);
424         int64           result;
425         PgStat_StatTabEntry *tabentry;
426
427         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
428                 result = 0;
429         else
430                 result = (int64) (tabentry->analyze_count);
431
432         PG_RETURN_INT64(result);
433 }
434
435 Datum
436 pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS)
437 {
438         Oid                     relid = PG_GETARG_OID(0);
439         int64           result;
440         PgStat_StatTabEntry *tabentry;
441
442         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
443                 result = 0;
444         else
445                 result = (int64) (tabentry->autovac_analyze_count);
446
447         PG_RETURN_INT64(result);
448 }
449
450 Datum
451 pg_stat_get_function_calls(PG_FUNCTION_ARGS)
452 {
453         Oid                     funcid = PG_GETARG_OID(0);
454         PgStat_StatFuncEntry *funcentry;
455
456         if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
457                 PG_RETURN_NULL();
458         PG_RETURN_INT64(funcentry->f_numcalls);
459 }
460
461 Datum
462 pg_stat_get_function_total_time(PG_FUNCTION_ARGS)
463 {
464         Oid                     funcid = PG_GETARG_OID(0);
465         PgStat_StatFuncEntry *funcentry;
466
467         if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
468                 PG_RETURN_NULL();
469         /* convert counter from microsec to millisec for display */
470         PG_RETURN_FLOAT8(((double) funcentry->f_total_time) / 1000.0);
471 }
472
473 Datum
474 pg_stat_get_function_self_time(PG_FUNCTION_ARGS)
475 {
476         Oid                     funcid = PG_GETARG_OID(0);
477         PgStat_StatFuncEntry *funcentry;
478
479         if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
480                 PG_RETURN_NULL();
481         /* convert counter from microsec to millisec for display */
482         PG_RETURN_FLOAT8(((double) funcentry->f_self_time) / 1000.0);
483 }
484
485 Datum
486 pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
487 {
488         FuncCallContext *funcctx;
489         int                *fctx;
490         int32           result;
491
492         /* stuff done only on the first call of the function */
493         if (SRF_IS_FIRSTCALL())
494         {
495                 /* create a function context for cross-call persistence */
496                 funcctx = SRF_FIRSTCALL_INIT();
497
498                 fctx = MemoryContextAlloc(funcctx->multi_call_memory_ctx,
499                                                                   2 * sizeof(int));
500                 funcctx->user_fctx = fctx;
501
502                 fctx[0] = 0;
503                 fctx[1] = pgstat_fetch_stat_numbackends();
504         }
505
506         /* stuff done on every call of the function */
507         funcctx = SRF_PERCALL_SETUP();
508         fctx = funcctx->user_fctx;
509
510         fctx[0] += 1;
511         result = fctx[0];
512
513         if (result <= fctx[1])
514         {
515                 /* do when there is more left to send */
516                 SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
517         }
518         else
519         {
520                 /* do when there is no more left */
521                 SRF_RETURN_DONE(funcctx);
522         }
523 }
524
525 Datum
526 pg_stat_get_activity(PG_FUNCTION_ARGS)
527 {
528         FuncCallContext *funcctx;
529
530         if (SRF_IS_FIRSTCALL())
531         {
532                 MemoryContext oldcontext;
533                 TupleDesc       tupdesc;
534
535                 funcctx = SRF_FIRSTCALL_INIT();
536
537                 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
538
539                 tupdesc = CreateTemplateTupleDesc(16, false);
540                 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid",
541                                                    OIDOID, -1, 0);
542                 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "pid",
543                                                    INT4OID, -1, 0);
544                 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "usesysid",
545                                                    OIDOID, -1, 0);
546                 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "application_name",
547                                                    TEXTOID, -1, 0);
548                 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "state",
549                                                    TEXTOID, -1, 0);
550                 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "query",
551                                                    TEXTOID, -1, 0);
552                 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "waiting",
553                                                    BOOLOID, -1, 0);
554                 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "act_start",
555                                                    TIMESTAMPTZOID, -1, 0);
556                 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "query_start",
557                                                    TIMESTAMPTZOID, -1, 0);
558                 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "backend_start",
559                                                    TIMESTAMPTZOID, -1, 0);
560                 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "state_change",
561                                                    TIMESTAMPTZOID, -1, 0);
562                 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "client_addr",
563                                                    INETOID, -1, 0);
564                 TupleDescInitEntry(tupdesc, (AttrNumber) 13, "client_hostname",
565                                                    TEXTOID, -1, 0);
566                 TupleDescInitEntry(tupdesc, (AttrNumber) 14, "client_port",
567                                                    INT4OID, -1, 0);
568                 TupleDescInitEntry(tupdesc, (AttrNumber) 15, "backend_xid",
569                                                    XIDOID, -1, 0);
570                 TupleDescInitEntry(tupdesc, (AttrNumber) 16, "backend_xmin",
571                                                    XIDOID, -1, 0);
572
573                 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
574
575                 funcctx->user_fctx = palloc0(sizeof(int));
576                 if (PG_ARGISNULL(0))
577                 {
578                         /* Get all backends */
579                         funcctx->max_calls = pgstat_fetch_stat_numbackends();
580                 }
581                 else
582                 {
583                         /*
584                          * Get one backend - locate by pid.
585                          *
586                          * We lookup the backend early, so we can return zero rows if it
587                          * doesn't exist, instead of returning a single row full of NULLs.
588                          */
589                         int                     pid = PG_GETARG_INT32(0);
590                         int                     i;
591                         int                     n = pgstat_fetch_stat_numbackends();
592
593                         for (i = 1; i <= n; i++)
594                         {
595                                 PgBackendStatus *be = pgstat_fetch_stat_beentry(i);
596
597                                 if (be)
598                                 {
599                                         if (be->st_procpid == pid)
600                                         {
601                                                 *(int *) (funcctx->user_fctx) = i;
602                                                 break;
603                                         }
604                                 }
605                         }
606
607                         if (*(int *) (funcctx->user_fctx) == 0)
608                                 /* Pid not found, return zero rows */
609                                 funcctx->max_calls = 0;
610                         else
611                                 funcctx->max_calls = 1;
612                 }
613
614                 MemoryContextSwitchTo(oldcontext);
615         }
616
617         /* stuff done on every call of the function */
618         funcctx = SRF_PERCALL_SETUP();
619
620         if (funcctx->call_cntr < funcctx->max_calls)
621         {
622                 /* for each row */
623                 Datum           values[16];
624                 bool            nulls[16];
625                 HeapTuple       tuple;
626                 LocalPgBackendStatus *local_beentry;
627                 PgBackendStatus *beentry;
628
629                 MemSet(values, 0, sizeof(values));
630                 MemSet(nulls, 0, sizeof(nulls));
631
632                 if (*(int *) (funcctx->user_fctx) > 0)
633                 {
634                         /* Get specific pid slot */
635                         local_beentry = pgstat_fetch_stat_local_beentry(*(int *) (funcctx->user_fctx));
636                         beentry = &local_beentry->backendStatus;
637                 }
638                 else
639                 {
640                         /* Get the next one in the list */
641                         local_beentry = pgstat_fetch_stat_local_beentry(funcctx->call_cntr + 1);        /* 1-based index */
642                         beentry = &local_beentry->backendStatus;
643                 }
644                 if (!beentry)
645                 {
646                         int                     i;
647
648                         for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++)
649                                 nulls[i] = true;
650
651                         nulls[5] = false;
652                         values[5] = CStringGetTextDatum("<backend information not available>");
653
654                         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
655                         SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
656                 }
657
658                 /* Values available to all callers */
659                 values[0] = ObjectIdGetDatum(beentry->st_databaseid);
660                 values[1] = Int32GetDatum(beentry->st_procpid);
661                 values[2] = ObjectIdGetDatum(beentry->st_userid);
662                 if (beentry->st_appname)
663                         values[3] = CStringGetTextDatum(beentry->st_appname);
664                 else
665                         nulls[3] = true;
666
667                 if (TransactionIdIsValid(local_beentry->backend_xid))
668                         values[14] = TransactionIdGetDatum(local_beentry->backend_xid);
669                 else
670                         nulls[14] = true;
671
672                 if (TransactionIdIsValid(local_beentry->backend_xmin))
673                         values[15] = TransactionIdGetDatum(local_beentry->backend_xmin);
674                 else
675                         nulls[15] = true;
676
677                 /* Values only available to same user or superuser */
678                 if (superuser() || beentry->st_userid == GetUserId())
679                 {
680                         SockAddr        zero_clientaddr;
681
682                         switch (beentry->st_state)
683                         {
684                                 case STATE_IDLE:
685                                         values[4] = CStringGetTextDatum("idle");
686                                         break;
687                                 case STATE_RUNNING:
688                                         values[4] = CStringGetTextDatum("active");
689                                         break;
690                                 case STATE_IDLEINTRANSACTION:
691                                         values[4] = CStringGetTextDatum("idle in transaction");
692                                         break;
693                                 case STATE_FASTPATH:
694                                         values[4] = CStringGetTextDatum("fastpath function call");
695                                         break;
696                                 case STATE_IDLEINTRANSACTION_ABORTED:
697                                         values[4] = CStringGetTextDatum("idle in transaction (aborted)");
698                                         break;
699                                 case STATE_DISABLED:
700                                         values[4] = CStringGetTextDatum("disabled");
701                                         break;
702                                 case STATE_UNDEFINED:
703                                         nulls[4] = true;
704                                         break;
705                         }
706
707                         values[5] = CStringGetTextDatum(beentry->st_activity);
708                         values[6] = BoolGetDatum(beentry->st_waiting);
709
710                         if (beentry->st_xact_start_timestamp != 0)
711                                 values[7] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
712                         else
713                                 nulls[7] = true;
714
715                         if (beentry->st_activity_start_timestamp != 0)
716                                 values[8] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
717                         else
718                                 nulls[8] = true;
719
720                         if (beentry->st_proc_start_timestamp != 0)
721                                 values[9] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
722                         else
723                                 nulls[9] = true;
724
725                         if (beentry->st_state_start_timestamp != 0)
726                                 values[10] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
727                         else
728                                 nulls[10] = true;
729
730                         /* A zeroed client addr means we don't know */
731                         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
732                         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
733                                            sizeof(zero_clientaddr)) == 0)
734                         {
735                                 nulls[11] = true;
736                                 nulls[12] = true;
737                                 nulls[13] = true;
738                         }
739                         else
740                         {
741                                 if (beentry->st_clientaddr.addr.ss_family == AF_INET
742 #ifdef HAVE_IPV6
743                                         || beentry->st_clientaddr.addr.ss_family == AF_INET6
744 #endif
745                                         )
746                                 {
747                                         char            remote_host[NI_MAXHOST];
748                                         char            remote_port[NI_MAXSERV];
749                                         int                     ret;
750
751                                         remote_host[0] = '\0';
752                                         remote_port[0] = '\0';
753                                         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
754                                                                                          beentry->st_clientaddr.salen,
755                                                                                          remote_host, sizeof(remote_host),
756                                                                                          remote_port, sizeof(remote_port),
757                                                                                          NI_NUMERICHOST | NI_NUMERICSERV);
758                                         if (ret == 0)
759                                         {
760                                                 clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
761                                                 values[11] = DirectFunctionCall1(inet_in,
762                                                                                            CStringGetDatum(remote_host));
763                                                 if (beentry->st_clienthostname &&
764                                                         beentry->st_clienthostname[0])
765                                                         values[12] = CStringGetTextDatum(beentry->st_clienthostname);
766                                                 else
767                                                         nulls[12] = true;
768                                                 values[13] = Int32GetDatum(atoi(remote_port));
769                                         }
770                                         else
771                                         {
772                                                 nulls[11] = true;
773                                                 nulls[12] = true;
774                                                 nulls[13] = true;
775                                         }
776                                 }
777                                 else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
778                                 {
779                                         /*
780                                          * Unix sockets always reports NULL for host and -1 for
781                                          * port, so it's possible to tell the difference to
782                                          * connections we have no permissions to view, or with
783                                          * errors.
784                                          */
785                                         nulls[11] = true;
786                                         nulls[12] = true;
787                                         values[13] = DatumGetInt32(-1);
788                                 }
789                                 else
790                                 {
791                                         /* Unknown address type, should never happen */
792                                         nulls[11] = true;
793                                         nulls[12] = true;
794                                         nulls[13] = true;
795                                 }
796                         }
797                 }
798                 else
799                 {
800                         /* No permissions to view data about this session */
801                         values[5] = CStringGetTextDatum("<insufficient privilege>");
802                         nulls[4] = true;
803                         nulls[6] = true;
804                         nulls[7] = true;
805                         nulls[8] = true;
806                         nulls[9] = true;
807                         nulls[10] = true;
808                         nulls[11] = true;
809                         nulls[12] = true;
810                         nulls[13] = true;
811                 }
812
813                 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
814
815                 SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
816         }
817         else
818         {
819                 /* nothing left */
820                 SRF_RETURN_DONE(funcctx);
821         }
822 }
823
824
825 Datum
826 pg_backend_pid(PG_FUNCTION_ARGS)
827 {
828         PG_RETURN_INT32(MyProcPid);
829 }
830
831
832 Datum
833 pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
834 {
835         int32           beid = PG_GETARG_INT32(0);
836         PgBackendStatus *beentry;
837
838         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
839                 PG_RETURN_NULL();
840
841         PG_RETURN_INT32(beentry->st_procpid);
842 }
843
844
845 Datum
846 pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
847 {
848         int32           beid = PG_GETARG_INT32(0);
849         PgBackendStatus *beentry;
850
851         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
852                 PG_RETURN_NULL();
853
854         PG_RETURN_OID(beentry->st_databaseid);
855 }
856
857
858 Datum
859 pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
860 {
861         int32           beid = PG_GETARG_INT32(0);
862         PgBackendStatus *beentry;
863
864         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
865                 PG_RETURN_NULL();
866
867         PG_RETURN_OID(beentry->st_userid);
868 }
869
870
871 Datum
872 pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
873 {
874         int32           beid = PG_GETARG_INT32(0);
875         PgBackendStatus *beentry;
876         const char *activity;
877
878         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
879                 activity = "<backend information not available>";
880         else if (!superuser() && beentry->st_userid != GetUserId())
881                 activity = "<insufficient privilege>";
882         else if (*(beentry->st_activity) == '\0')
883                 activity = "<command string not enabled>";
884         else
885                 activity = beentry->st_activity;
886
887         PG_RETURN_TEXT_P(cstring_to_text(activity));
888 }
889
890
891 Datum
892 pg_stat_get_backend_waiting(PG_FUNCTION_ARGS)
893 {
894         int32           beid = PG_GETARG_INT32(0);
895         bool            result;
896         PgBackendStatus *beentry;
897
898         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
899                 PG_RETURN_NULL();
900
901         if (!superuser() && beentry->st_userid != GetUserId())
902                 PG_RETURN_NULL();
903
904         result = beentry->st_waiting;
905
906         PG_RETURN_BOOL(result);
907 }
908
909
910 Datum
911 pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
912 {
913         int32           beid = PG_GETARG_INT32(0);
914         TimestampTz result;
915         PgBackendStatus *beentry;
916
917         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
918                 PG_RETURN_NULL();
919
920         if (!superuser() && beentry->st_userid != GetUserId())
921                 PG_RETURN_NULL();
922
923         result = beentry->st_activity_start_timestamp;
924
925         /*
926          * No time recorded for start of current query -- this is the case if the
927          * user hasn't enabled query-level stats collection.
928          */
929         if (result == 0)
930                 PG_RETURN_NULL();
931
932         PG_RETURN_TIMESTAMPTZ(result);
933 }
934
935
936 Datum
937 pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)
938 {
939         int32           beid = PG_GETARG_INT32(0);
940         TimestampTz result;
941         PgBackendStatus *beentry;
942
943         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
944                 PG_RETURN_NULL();
945
946         if (!superuser() && beentry->st_userid != GetUserId())
947                 PG_RETURN_NULL();
948
949         result = beentry->st_xact_start_timestamp;
950
951         if (result == 0)                        /* not in a transaction */
952                 PG_RETURN_NULL();
953
954         PG_RETURN_TIMESTAMPTZ(result);
955 }
956
957
958 Datum
959 pg_stat_get_backend_start(PG_FUNCTION_ARGS)
960 {
961         int32           beid = PG_GETARG_INT32(0);
962         TimestampTz result;
963         PgBackendStatus *beentry;
964
965         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
966                 PG_RETURN_NULL();
967
968         if (!superuser() && beentry->st_userid != GetUserId())
969                 PG_RETURN_NULL();
970
971         result = beentry->st_proc_start_timestamp;
972
973         if (result == 0)                        /* probably can't happen? */
974                 PG_RETURN_NULL();
975
976         PG_RETURN_TIMESTAMPTZ(result);
977 }
978
979
980 Datum
981 pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
982 {
983         int32           beid = PG_GETARG_INT32(0);
984         PgBackendStatus *beentry;
985         SockAddr        zero_clientaddr;
986         char            remote_host[NI_MAXHOST];
987         int                     ret;
988
989         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
990                 PG_RETURN_NULL();
991
992         if (!superuser() && beentry->st_userid != GetUserId())
993                 PG_RETURN_NULL();
994
995         /* A zeroed client addr means we don't know */
996         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
997         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
998                            sizeof(zero_clientaddr)) == 0)
999                 PG_RETURN_NULL();
1000
1001         switch (beentry->st_clientaddr.addr.ss_family)
1002         {
1003                 case AF_INET:
1004 #ifdef HAVE_IPV6
1005                 case AF_INET6:
1006 #endif
1007                         break;
1008                 default:
1009                         PG_RETURN_NULL();
1010         }
1011
1012         remote_host[0] = '\0';
1013         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
1014                                                          beentry->st_clientaddr.salen,
1015                                                          remote_host, sizeof(remote_host),
1016                                                          NULL, 0,
1017                                                          NI_NUMERICHOST | NI_NUMERICSERV);
1018         if (ret != 0)
1019                 PG_RETURN_NULL();
1020
1021         clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
1022
1023         PG_RETURN_INET_P(DirectFunctionCall1(inet_in,
1024                                                                                  CStringGetDatum(remote_host)));
1025 }
1026
1027 Datum
1028 pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
1029 {
1030         int32           beid = PG_GETARG_INT32(0);
1031         PgBackendStatus *beentry;
1032         SockAddr        zero_clientaddr;
1033         char            remote_port[NI_MAXSERV];
1034         int                     ret;
1035
1036         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
1037                 PG_RETURN_NULL();
1038
1039         if (!superuser() && beentry->st_userid != GetUserId())
1040                 PG_RETURN_NULL();
1041
1042         /* A zeroed client addr means we don't know */
1043         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
1044         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
1045                            sizeof(zero_clientaddr)) == 0)
1046                 PG_RETURN_NULL();
1047
1048         switch (beentry->st_clientaddr.addr.ss_family)
1049         {
1050                 case AF_INET:
1051 #ifdef HAVE_IPV6
1052                 case AF_INET6:
1053 #endif
1054                         break;
1055                 case AF_UNIX:
1056                         PG_RETURN_INT32(-1);
1057                 default:
1058                         PG_RETURN_NULL();
1059         }
1060
1061         remote_port[0] = '\0';
1062         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
1063                                                          beentry->st_clientaddr.salen,
1064                                                          NULL, 0,
1065                                                          remote_port, sizeof(remote_port),
1066                                                          NI_NUMERICHOST | NI_NUMERICSERV);
1067         if (ret != 0)
1068                 PG_RETURN_NULL();
1069
1070         PG_RETURN_DATUM(DirectFunctionCall1(int4in,
1071                                                                                 CStringGetDatum(remote_port)));
1072 }
1073
1074
1075 Datum
1076 pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
1077 {
1078         Oid                     dbid = PG_GETARG_OID(0);
1079         int32           result;
1080         int                     tot_backends = pgstat_fetch_stat_numbackends();
1081         int                     beid;
1082
1083         result = 0;
1084         for (beid = 1; beid <= tot_backends; beid++)
1085         {
1086                 PgBackendStatus *beentry = pgstat_fetch_stat_beentry(beid);
1087
1088                 if (beentry && beentry->st_databaseid == dbid)
1089                         result++;
1090         }
1091
1092         PG_RETURN_INT32(result);
1093 }
1094
1095
1096 Datum
1097 pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS)
1098 {
1099         Oid                     dbid = PG_GETARG_OID(0);
1100         int64           result;
1101         PgStat_StatDBEntry *dbentry;
1102
1103         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1104                 result = 0;
1105         else
1106                 result = (int64) (dbentry->n_xact_commit);
1107
1108         PG_RETURN_INT64(result);
1109 }
1110
1111
1112 Datum
1113 pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)
1114 {
1115         Oid                     dbid = PG_GETARG_OID(0);
1116         int64           result;
1117         PgStat_StatDBEntry *dbentry;
1118
1119         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1120                 result = 0;
1121         else
1122                 result = (int64) (dbentry->n_xact_rollback);
1123
1124         PG_RETURN_INT64(result);
1125 }
1126
1127
1128 Datum
1129 pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)
1130 {
1131         Oid                     dbid = PG_GETARG_OID(0);
1132         int64           result;
1133         PgStat_StatDBEntry *dbentry;
1134
1135         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1136                 result = 0;
1137         else
1138                 result = (int64) (dbentry->n_blocks_fetched);
1139
1140         PG_RETURN_INT64(result);
1141 }
1142
1143
1144 Datum
1145 pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)
1146 {
1147         Oid                     dbid = PG_GETARG_OID(0);
1148         int64           result;
1149         PgStat_StatDBEntry *dbentry;
1150
1151         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1152                 result = 0;
1153         else
1154                 result = (int64) (dbentry->n_blocks_hit);
1155
1156         PG_RETURN_INT64(result);
1157 }
1158
1159
1160 Datum
1161 pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS)
1162 {
1163         Oid                     dbid = PG_GETARG_OID(0);
1164         int64           result;
1165         PgStat_StatDBEntry *dbentry;
1166
1167         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1168                 result = 0;
1169         else
1170                 result = (int64) (dbentry->n_tuples_returned);
1171
1172         PG_RETURN_INT64(result);
1173 }
1174
1175
1176 Datum
1177 pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS)
1178 {
1179         Oid                     dbid = PG_GETARG_OID(0);
1180         int64           result;
1181         PgStat_StatDBEntry *dbentry;
1182
1183         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1184                 result = 0;
1185         else
1186                 result = (int64) (dbentry->n_tuples_fetched);
1187
1188         PG_RETURN_INT64(result);
1189 }
1190
1191
1192 Datum
1193 pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS)
1194 {
1195         Oid                     dbid = PG_GETARG_OID(0);
1196         int64           result;
1197         PgStat_StatDBEntry *dbentry;
1198
1199         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1200                 result = 0;
1201         else
1202                 result = (int64) (dbentry->n_tuples_inserted);
1203
1204         PG_RETURN_INT64(result);
1205 }
1206
1207
1208 Datum
1209 pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS)
1210 {
1211         Oid                     dbid = PG_GETARG_OID(0);
1212         int64           result;
1213         PgStat_StatDBEntry *dbentry;
1214
1215         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1216                 result = 0;
1217         else
1218                 result = (int64) (dbentry->n_tuples_updated);
1219
1220         PG_RETURN_INT64(result);
1221 }
1222
1223
1224 Datum
1225 pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS)
1226 {
1227         Oid                     dbid = PG_GETARG_OID(0);
1228         int64           result;
1229         PgStat_StatDBEntry *dbentry;
1230
1231         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1232                 result = 0;
1233         else
1234                 result = (int64) (dbentry->n_tuples_deleted);
1235
1236         PG_RETURN_INT64(result);
1237 }
1238
1239 Datum
1240 pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)
1241 {
1242         Oid                     dbid = PG_GETARG_OID(0);
1243         TimestampTz result;
1244         PgStat_StatDBEntry *dbentry;
1245
1246         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1247                 result = 0;
1248         else
1249                 result = dbentry->stat_reset_timestamp;
1250
1251         if (result == 0)
1252                 PG_RETURN_NULL();
1253         else
1254                 PG_RETURN_TIMESTAMPTZ(result);
1255 }
1256
1257 Datum
1258 pg_stat_get_db_temp_files(PG_FUNCTION_ARGS)
1259 {
1260         Oid                     dbid = PG_GETARG_OID(0);
1261         int64           result;
1262         PgStat_StatDBEntry *dbentry;
1263
1264         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1265                 result = 0;
1266         else
1267                 result = dbentry->n_temp_files;
1268
1269         PG_RETURN_INT64(result);
1270 }
1271
1272
1273 Datum
1274 pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS)
1275 {
1276         Oid                     dbid = PG_GETARG_OID(0);
1277         int64           result;
1278         PgStat_StatDBEntry *dbentry;
1279
1280         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1281                 result = 0;
1282         else
1283                 result = dbentry->n_temp_bytes;
1284
1285         PG_RETURN_INT64(result);
1286 }
1287
1288 Datum
1289 pg_stat_get_db_conflict_tablespace(PG_FUNCTION_ARGS)
1290 {
1291         Oid                     dbid = PG_GETARG_OID(0);
1292         int64           result;
1293         PgStat_StatDBEntry *dbentry;
1294
1295         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1296                 result = 0;
1297         else
1298                 result = (int64) (dbentry->n_conflict_tablespace);
1299
1300         PG_RETURN_INT64(result);
1301 }
1302
1303 Datum
1304 pg_stat_get_db_conflict_lock(PG_FUNCTION_ARGS)
1305 {
1306         Oid                     dbid = PG_GETARG_OID(0);
1307         int64           result;
1308         PgStat_StatDBEntry *dbentry;
1309
1310         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1311                 result = 0;
1312         else
1313                 result = (int64) (dbentry->n_conflict_lock);
1314
1315         PG_RETURN_INT64(result);
1316 }
1317
1318 Datum
1319 pg_stat_get_db_conflict_snapshot(PG_FUNCTION_ARGS)
1320 {
1321         Oid                     dbid = PG_GETARG_OID(0);
1322         int64           result;
1323         PgStat_StatDBEntry *dbentry;
1324
1325         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1326                 result = 0;
1327         else
1328                 result = (int64) (dbentry->n_conflict_snapshot);
1329
1330         PG_RETURN_INT64(result);
1331 }
1332
1333 Datum
1334 pg_stat_get_db_conflict_bufferpin(PG_FUNCTION_ARGS)
1335 {
1336         Oid                     dbid = PG_GETARG_OID(0);
1337         int64           result;
1338         PgStat_StatDBEntry *dbentry;
1339
1340         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1341                 result = 0;
1342         else
1343                 result = (int64) (dbentry->n_conflict_bufferpin);
1344
1345         PG_RETURN_INT64(result);
1346 }
1347
1348 Datum
1349 pg_stat_get_db_conflict_startup_deadlock(PG_FUNCTION_ARGS)
1350 {
1351         Oid                     dbid = PG_GETARG_OID(0);
1352         int64           result;
1353         PgStat_StatDBEntry *dbentry;
1354
1355         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1356                 result = 0;
1357         else
1358                 result = (int64) (dbentry->n_conflict_startup_deadlock);
1359
1360         PG_RETURN_INT64(result);
1361 }
1362
1363 Datum
1364 pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS)
1365 {
1366         Oid                     dbid = PG_GETARG_OID(0);
1367         int64           result;
1368         PgStat_StatDBEntry *dbentry;
1369
1370         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1371                 result = 0;
1372         else
1373                 result = (int64) (
1374                                                   dbentry->n_conflict_tablespace +
1375                                                   dbentry->n_conflict_lock +
1376                                                   dbentry->n_conflict_snapshot +
1377                                                   dbentry->n_conflict_bufferpin +
1378                                                   dbentry->n_conflict_startup_deadlock);
1379
1380         PG_RETURN_INT64(result);
1381 }
1382
1383 Datum
1384 pg_stat_get_db_deadlocks(PG_FUNCTION_ARGS)
1385 {
1386         Oid                     dbid = PG_GETARG_OID(0);
1387         int64           result;
1388         PgStat_StatDBEntry *dbentry;
1389
1390         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1391                 result = 0;
1392         else
1393                 result = (int64) (dbentry->n_deadlocks);
1394
1395         PG_RETURN_INT64(result);
1396 }
1397
1398 Datum
1399 pg_stat_get_db_blk_read_time(PG_FUNCTION_ARGS)
1400 {
1401         Oid                     dbid = PG_GETARG_OID(0);
1402         double          result;
1403         PgStat_StatDBEntry *dbentry;
1404
1405         /* convert counter from microsec to millisec for display */
1406         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1407                 result = 0;
1408         else
1409                 result = ((double) dbentry->n_block_read_time) / 1000.0;
1410
1411         PG_RETURN_FLOAT8(result);
1412 }
1413
1414 Datum
1415 pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS)
1416 {
1417         Oid                     dbid = PG_GETARG_OID(0);
1418         double          result;
1419         PgStat_StatDBEntry *dbentry;
1420
1421         /* convert counter from microsec to millisec for display */
1422         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1423                 result = 0;
1424         else
1425                 result = ((double) dbentry->n_block_write_time) / 1000.0;
1426
1427         PG_RETURN_FLOAT8(result);
1428 }
1429
1430 Datum
1431 pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
1432 {
1433         PG_RETURN_INT64(pgstat_fetch_global()->timed_checkpoints);
1434 }
1435
1436 Datum
1437 pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
1438 {
1439         PG_RETURN_INT64(pgstat_fetch_global()->requested_checkpoints);
1440 }
1441
1442 Datum
1443 pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
1444 {
1445         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_checkpoints);
1446 }
1447
1448 Datum
1449 pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)
1450 {
1451         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_clean);
1452 }
1453
1454 Datum
1455 pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
1456 {
1457         PG_RETURN_INT64(pgstat_fetch_global()->maxwritten_clean);
1458 }
1459
1460 Datum
1461 pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS)
1462 {
1463         /* time is already in msec, just convert to double for presentation */
1464         PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_write_time);
1465 }
1466
1467 Datum
1468 pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
1469 {
1470         /* time is already in msec, just convert to double for presentation */
1471         PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_sync_time);
1472 }
1473
1474 Datum
1475 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
1476 {
1477         PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stat_reset_timestamp);
1478 }
1479
1480 Datum
1481 pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
1482 {
1483         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_backend);
1484 }
1485
1486 Datum
1487 pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)
1488 {
1489         PG_RETURN_INT64(pgstat_fetch_global()->buf_fsync_backend);
1490 }
1491
1492 Datum
1493 pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
1494 {
1495         PG_RETURN_INT64(pgstat_fetch_global()->buf_alloc);
1496 }
1497
1498 Datum
1499 pg_stat_get_xact_numscans(PG_FUNCTION_ARGS)
1500 {
1501         Oid                     relid = PG_GETARG_OID(0);
1502         int64           result;
1503         PgStat_TableStatus *tabentry;
1504
1505         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1506                 result = 0;
1507         else
1508                 result = (int64) (tabentry->t_counts.t_numscans);
1509
1510         PG_RETURN_INT64(result);
1511 }
1512
1513 Datum
1514 pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS)
1515 {
1516         Oid                     relid = PG_GETARG_OID(0);
1517         int64           result;
1518         PgStat_TableStatus *tabentry;
1519
1520         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1521                 result = 0;
1522         else
1523                 result = (int64) (tabentry->t_counts.t_tuples_returned);
1524
1525         PG_RETURN_INT64(result);
1526 }
1527
1528 Datum
1529 pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS)
1530 {
1531         Oid                     relid = PG_GETARG_OID(0);
1532         int64           result;
1533         PgStat_TableStatus *tabentry;
1534
1535         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1536                 result = 0;
1537         else
1538                 result = (int64) (tabentry->t_counts.t_tuples_fetched);
1539
1540         PG_RETURN_INT64(result);
1541 }
1542
1543 Datum
1544 pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS)
1545 {
1546         Oid                     relid = PG_GETARG_OID(0);
1547         int64           result;
1548         PgStat_TableStatus *tabentry;
1549         PgStat_TableXactStatus *trans;
1550
1551         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1552                 result = 0;
1553         else
1554         {
1555                 result = tabentry->t_counts.t_tuples_inserted;
1556                 /* live subtransactions' counts aren't in t_tuples_inserted yet */
1557                 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1558                         result += trans->tuples_inserted;
1559         }
1560
1561         PG_RETURN_INT64(result);
1562 }
1563
1564 Datum
1565 pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS)
1566 {
1567         Oid                     relid = PG_GETARG_OID(0);
1568         int64           result;
1569         PgStat_TableStatus *tabentry;
1570         PgStat_TableXactStatus *trans;
1571
1572         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1573                 result = 0;
1574         else
1575         {
1576                 result = tabentry->t_counts.t_tuples_updated;
1577                 /* live subtransactions' counts aren't in t_tuples_updated yet */
1578                 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1579                         result += trans->tuples_updated;
1580         }
1581
1582         PG_RETURN_INT64(result);
1583 }
1584
1585 Datum
1586 pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS)
1587 {
1588         Oid                     relid = PG_GETARG_OID(0);
1589         int64           result;
1590         PgStat_TableStatus *tabentry;
1591         PgStat_TableXactStatus *trans;
1592
1593         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1594                 result = 0;
1595         else
1596         {
1597                 result = tabentry->t_counts.t_tuples_deleted;
1598                 /* live subtransactions' counts aren't in t_tuples_deleted yet */
1599                 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1600                         result += trans->tuples_deleted;
1601         }
1602
1603         PG_RETURN_INT64(result);
1604 }
1605
1606 Datum
1607 pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS)
1608 {
1609         Oid                     relid = PG_GETARG_OID(0);
1610         int64           result;
1611         PgStat_TableStatus *tabentry;
1612
1613         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1614                 result = 0;
1615         else
1616                 result = (int64) (tabentry->t_counts.t_tuples_hot_updated);
1617
1618         PG_RETURN_INT64(result);
1619 }
1620
1621 Datum
1622 pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS)
1623 {
1624         Oid                     relid = PG_GETARG_OID(0);
1625         int64           result;
1626         PgStat_TableStatus *tabentry;
1627
1628         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1629                 result = 0;
1630         else
1631                 result = (int64) (tabentry->t_counts.t_blocks_fetched);
1632
1633         PG_RETURN_INT64(result);
1634 }
1635
1636 Datum
1637 pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS)
1638 {
1639         Oid                     relid = PG_GETARG_OID(0);
1640         int64           result;
1641         PgStat_TableStatus *tabentry;
1642
1643         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1644                 result = 0;
1645         else
1646                 result = (int64) (tabentry->t_counts.t_blocks_hit);
1647
1648         PG_RETURN_INT64(result);
1649 }
1650
1651 Datum
1652 pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
1653 {
1654         Oid                     funcid = PG_GETARG_OID(0);
1655         PgStat_BackendFunctionEntry *funcentry;
1656
1657         if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1658                 PG_RETURN_NULL();
1659         PG_RETURN_INT64(funcentry->f_counts.f_numcalls);
1660 }
1661
1662 Datum
1663 pg_stat_get_xact_function_total_time(PG_FUNCTION_ARGS)
1664 {
1665         Oid                     funcid = PG_GETARG_OID(0);
1666         PgStat_BackendFunctionEntry *funcentry;
1667
1668         if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1669                 PG_RETURN_NULL();
1670         PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_total_time));
1671 }
1672
1673 Datum
1674 pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS)
1675 {
1676         Oid                     funcid = PG_GETARG_OID(0);
1677         PgStat_BackendFunctionEntry *funcentry;
1678
1679         if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1680                 PG_RETURN_NULL();
1681         PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_self_time));
1682 }
1683
1684
1685 /* Discard the active statistics snapshot */
1686 Datum
1687 pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
1688 {
1689         pgstat_clear_snapshot();
1690
1691         PG_RETURN_VOID();
1692 }
1693
1694
1695 /* Reset all counters for the current database */
1696 Datum
1697 pg_stat_reset(PG_FUNCTION_ARGS)
1698 {
1699         pgstat_reset_counters();
1700
1701         PG_RETURN_VOID();
1702 }
1703
1704 /* Reset some shared cluster-wide counters */
1705 Datum
1706 pg_stat_reset_shared(PG_FUNCTION_ARGS)
1707 {
1708         char       *target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1709
1710         pgstat_reset_shared_counters(target);
1711
1712         PG_RETURN_VOID();
1713 }
1714
1715 /* Reset a single counter in the current database */
1716 Datum
1717 pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
1718 {
1719         Oid                     taboid = PG_GETARG_OID(0);
1720
1721         pgstat_reset_single_counter(taboid, RESET_TABLE);
1722
1723         PG_RETURN_VOID();
1724 }
1725
1726 Datum
1727 pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
1728 {
1729         Oid                     funcoid = PG_GETARG_OID(0);
1730
1731         pgstat_reset_single_counter(funcoid, RESET_FUNCTION);
1732
1733         PG_RETURN_VOID();
1734 }
1735
1736 Datum
1737 pg_stat_get_archiver(PG_FUNCTION_ARGS)
1738 {
1739         TupleDesc       tupdesc;
1740         Datum           values[7];
1741         bool            nulls[7];
1742         PgStat_ArchiverStats *archiver_stats;
1743
1744         /* Initialise values and NULL flags arrays */
1745         MemSet(values, 0, sizeof(values));
1746         MemSet(nulls, 0, sizeof(nulls));
1747
1748         /* Initialise attributes information in the tuple descriptor */
1749         tupdesc = CreateTemplateTupleDesc(7, false);
1750         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count",
1751                                            INT8OID, -1, 0);
1752         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
1753                                            TEXTOID, -1, 0);
1754         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time",
1755                                            TIMESTAMPTZOID, -1, 0);
1756         TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count",
1757                                            INT8OID, -1, 0);
1758         TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
1759                                            TEXTOID, -1, 0);
1760         TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time",
1761                                            TIMESTAMPTZOID, -1, 0);
1762         TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset",
1763                                            TIMESTAMPTZOID, -1, 0);
1764
1765         BlessTupleDesc(tupdesc);
1766
1767         /* Get statistics about the archiver process */
1768         archiver_stats = pgstat_fetch_stat_archiver();
1769
1770         /* Fill values and NULLs */
1771         values[0] = Int64GetDatum(archiver_stats->archived_count);
1772         if (*(archiver_stats->last_archived_wal) == '\0')
1773                 nulls[1] = true;
1774         else
1775                 values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
1776
1777         if (archiver_stats->last_archived_timestamp == 0)
1778                 nulls[2] = true;
1779         else
1780                 values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp);
1781
1782         values[3] = Int64GetDatum(archiver_stats->failed_count);
1783         if (*(archiver_stats->last_failed_wal) == '\0')
1784                 nulls[4] = true;
1785         else
1786                 values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
1787
1788         if (archiver_stats->last_failed_timestamp == 0)
1789                 nulls[5] = true;
1790         else
1791                 values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp);
1792
1793         if (archiver_stats->stat_reset_timestamp == 0)
1794                 nulls[6] = true;
1795         else
1796                 values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
1797
1798         /* Returns the record as Datum */
1799         PG_RETURN_DATUM(HeapTupleGetDatum(
1800                                                                    heap_form_tuple(tupdesc, values, nulls)));
1801 }