]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/pgstatfuncs.c
Add pg_stat_archiver statistics view.
[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-2014, 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(14, 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
569                 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
570
571                 funcctx->user_fctx = palloc0(sizeof(int));
572                 if (PG_ARGISNULL(0))
573                 {
574                         /* Get all backends */
575                         funcctx->max_calls = pgstat_fetch_stat_numbackends();
576                 }
577                 else
578                 {
579                         /*
580                          * Get one backend - locate by pid.
581                          *
582                          * We lookup the backend early, so we can return zero rows if it
583                          * doesn't exist, instead of returning a single row full of NULLs.
584                          */
585                         int                     pid = PG_GETARG_INT32(0);
586                         int                     i;
587                         int                     n = pgstat_fetch_stat_numbackends();
588
589                         for (i = 1; i <= n; i++)
590                         {
591                                 PgBackendStatus *be = pgstat_fetch_stat_beentry(i);
592
593                                 if (be)
594                                 {
595                                         if (be->st_procpid == pid)
596                                         {
597                                                 *(int *) (funcctx->user_fctx) = i;
598                                                 break;
599                                         }
600                                 }
601                         }
602
603                         if (*(int *) (funcctx->user_fctx) == 0)
604                                 /* Pid not found, return zero rows */
605                                 funcctx->max_calls = 0;
606                         else
607                                 funcctx->max_calls = 1;
608                 }
609
610                 MemoryContextSwitchTo(oldcontext);
611         }
612
613         /* stuff done on every call of the function */
614         funcctx = SRF_PERCALL_SETUP();
615
616         if (funcctx->call_cntr < funcctx->max_calls)
617         {
618                 /* for each row */
619                 Datum           values[14];
620                 bool            nulls[14];
621                 HeapTuple       tuple;
622                 PgBackendStatus *beentry;
623
624                 MemSet(values, 0, sizeof(values));
625                 MemSet(nulls, 0, sizeof(nulls));
626
627                 if (*(int *) (funcctx->user_fctx) > 0)
628                 {
629                         /* Get specific pid slot */
630                         beentry = pgstat_fetch_stat_beentry(*(int *) (funcctx->user_fctx));
631                 }
632                 else
633                 {
634                         /* Get the next one in the list */
635                         beentry = pgstat_fetch_stat_beentry(funcctx->call_cntr + 1);            /* 1-based index */
636                 }
637                 if (!beentry)
638                 {
639                         int                     i;
640
641                         for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++)
642                                 nulls[i] = true;
643
644                         nulls[5] = false;
645                         values[5] = CStringGetTextDatum("<backend information not available>");
646
647                         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
648                         SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
649                 }
650
651                 /* Values available to all callers */
652                 values[0] = ObjectIdGetDatum(beentry->st_databaseid);
653                 values[1] = Int32GetDatum(beentry->st_procpid);
654                 values[2] = ObjectIdGetDatum(beentry->st_userid);
655                 if (beentry->st_appname)
656                         values[3] = CStringGetTextDatum(beentry->st_appname);
657                 else
658                         nulls[3] = true;
659
660                 /* Values only available to same user or superuser */
661                 if (superuser() || beentry->st_userid == GetUserId())
662                 {
663                         SockAddr        zero_clientaddr;
664
665                         switch (beentry->st_state)
666                         {
667                                 case STATE_IDLE:
668                                         values[4] = CStringGetTextDatum("idle");
669                                         break;
670                                 case STATE_RUNNING:
671                                         values[4] = CStringGetTextDatum("active");
672                                         break;
673                                 case STATE_IDLEINTRANSACTION:
674                                         values[4] = CStringGetTextDatum("idle in transaction");
675                                         break;
676                                 case STATE_FASTPATH:
677                                         values[4] = CStringGetTextDatum("fastpath function call");
678                                         break;
679                                 case STATE_IDLEINTRANSACTION_ABORTED:
680                                         values[4] = CStringGetTextDatum("idle in transaction (aborted)");
681                                         break;
682                                 case STATE_DISABLED:
683                                         values[4] = CStringGetTextDatum("disabled");
684                                         break;
685                                 case STATE_UNDEFINED:
686                                         nulls[4] = true;
687                                         break;
688                         }
689
690                         values[5] = CStringGetTextDatum(beentry->st_activity);
691                         values[6] = BoolGetDatum(beentry->st_waiting);
692
693                         if (beentry->st_xact_start_timestamp != 0)
694                                 values[7] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
695                         else
696                                 nulls[7] = true;
697
698                         if (beentry->st_activity_start_timestamp != 0)
699                                 values[8] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
700                         else
701                                 nulls[8] = true;
702
703                         if (beentry->st_proc_start_timestamp != 0)
704                                 values[9] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
705                         else
706                                 nulls[9] = true;
707
708                         if (beentry->st_state_start_timestamp != 0)
709                                 values[10] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
710                         else
711                                 nulls[10] = true;
712
713                         /* A zeroed client addr means we don't know */
714                         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
715                         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
716                                            sizeof(zero_clientaddr)) == 0)
717                         {
718                                 nulls[11] = true;
719                                 nulls[12] = true;
720                                 nulls[13] = true;
721                         }
722                         else
723                         {
724                                 if (beentry->st_clientaddr.addr.ss_family == AF_INET
725 #ifdef HAVE_IPV6
726                                         || beentry->st_clientaddr.addr.ss_family == AF_INET6
727 #endif
728                                         )
729                                 {
730                                         char            remote_host[NI_MAXHOST];
731                                         char            remote_port[NI_MAXSERV];
732                                         int                     ret;
733
734                                         remote_host[0] = '\0';
735                                         remote_port[0] = '\0';
736                                         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
737                                                                                          beentry->st_clientaddr.salen,
738                                                                                          remote_host, sizeof(remote_host),
739                                                                                          remote_port, sizeof(remote_port),
740                                                                                          NI_NUMERICHOST | NI_NUMERICSERV);
741                                         if (ret == 0)
742                                         {
743                                                 clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
744                                                 values[11] = DirectFunctionCall1(inet_in,
745                                                                                            CStringGetDatum(remote_host));
746                                                 if (beentry->st_clienthostname)
747                                                         values[12] = CStringGetTextDatum(beentry->st_clienthostname);
748                                                 else
749                                                         nulls[12] = true;
750                                                 values[13] = Int32GetDatum(atoi(remote_port));
751                                         }
752                                         else
753                                         {
754                                                 nulls[11] = true;
755                                                 nulls[12] = true;
756                                                 nulls[13] = true;
757                                         }
758                                 }
759                                 else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
760                                 {
761                                         /*
762                                          * Unix sockets always reports NULL for host and -1 for
763                                          * port, so it's possible to tell the difference to
764                                          * connections we have no permissions to view, or with
765                                          * errors.
766                                          */
767                                         nulls[11] = true;
768                                         nulls[12] = true;
769                                         values[13] = DatumGetInt32(-1);
770                                 }
771                                 else
772                                 {
773                                         /* Unknown address type, should never happen */
774                                         nulls[11] = true;
775                                         nulls[12] = true;
776                                         nulls[13] = true;
777                                 }
778                         }
779                 }
780                 else
781                 {
782                         /* No permissions to view data about this session */
783                         values[5] = CStringGetTextDatum("<insufficient privilege>");
784                         nulls[4] = true;
785                         nulls[6] = true;
786                         nulls[7] = true;
787                         nulls[8] = true;
788                         nulls[9] = true;
789                         nulls[10] = true;
790                         nulls[11] = true;
791                         nulls[12] = true;
792                         nulls[13] = true;
793                 }
794
795                 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
796
797                 SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
798         }
799         else
800         {
801                 /* nothing left */
802                 SRF_RETURN_DONE(funcctx);
803         }
804 }
805
806
807 Datum
808 pg_backend_pid(PG_FUNCTION_ARGS)
809 {
810         PG_RETURN_INT32(MyProcPid);
811 }
812
813
814 Datum
815 pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
816 {
817         int32           beid = PG_GETARG_INT32(0);
818         PgBackendStatus *beentry;
819
820         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
821                 PG_RETURN_NULL();
822
823         PG_RETURN_INT32(beentry->st_procpid);
824 }
825
826
827 Datum
828 pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
829 {
830         int32           beid = PG_GETARG_INT32(0);
831         PgBackendStatus *beentry;
832
833         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
834                 PG_RETURN_NULL();
835
836         PG_RETURN_OID(beentry->st_databaseid);
837 }
838
839
840 Datum
841 pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
842 {
843         int32           beid = PG_GETARG_INT32(0);
844         PgBackendStatus *beentry;
845
846         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
847                 PG_RETURN_NULL();
848
849         PG_RETURN_OID(beentry->st_userid);
850 }
851
852
853 Datum
854 pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
855 {
856         int32           beid = PG_GETARG_INT32(0);
857         PgBackendStatus *beentry;
858         const char *activity;
859
860         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
861                 activity = "<backend information not available>";
862         else if (!superuser() && beentry->st_userid != GetUserId())
863                 activity = "<insufficient privilege>";
864         else if (*(beentry->st_activity) == '\0')
865                 activity = "<command string not enabled>";
866         else
867                 activity = beentry->st_activity;
868
869         PG_RETURN_TEXT_P(cstring_to_text(activity));
870 }
871
872
873 Datum
874 pg_stat_get_backend_waiting(PG_FUNCTION_ARGS)
875 {
876         int32           beid = PG_GETARG_INT32(0);
877         bool            result;
878         PgBackendStatus *beentry;
879
880         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
881                 PG_RETURN_NULL();
882
883         if (!superuser() && beentry->st_userid != GetUserId())
884                 PG_RETURN_NULL();
885
886         result = beentry->st_waiting;
887
888         PG_RETURN_BOOL(result);
889 }
890
891
892 Datum
893 pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
894 {
895         int32           beid = PG_GETARG_INT32(0);
896         TimestampTz result;
897         PgBackendStatus *beentry;
898
899         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
900                 PG_RETURN_NULL();
901
902         if (!superuser() && beentry->st_userid != GetUserId())
903                 PG_RETURN_NULL();
904
905         result = beentry->st_activity_start_timestamp;
906
907         /*
908          * No time recorded for start of current query -- this is the case if the
909          * user hasn't enabled query-level stats collection.
910          */
911         if (result == 0)
912                 PG_RETURN_NULL();
913
914         PG_RETURN_TIMESTAMPTZ(result);
915 }
916
917
918 Datum
919 pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)
920 {
921         int32           beid = PG_GETARG_INT32(0);
922         TimestampTz result;
923         PgBackendStatus *beentry;
924
925         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
926                 PG_RETURN_NULL();
927
928         if (!superuser() && beentry->st_userid != GetUserId())
929                 PG_RETURN_NULL();
930
931         result = beentry->st_xact_start_timestamp;
932
933         if (result == 0)                        /* not in a transaction */
934                 PG_RETURN_NULL();
935
936         PG_RETURN_TIMESTAMPTZ(result);
937 }
938
939
940 Datum
941 pg_stat_get_backend_start(PG_FUNCTION_ARGS)
942 {
943         int32           beid = PG_GETARG_INT32(0);
944         TimestampTz result;
945         PgBackendStatus *beentry;
946
947         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
948                 PG_RETURN_NULL();
949
950         if (!superuser() && beentry->st_userid != GetUserId())
951                 PG_RETURN_NULL();
952
953         result = beentry->st_proc_start_timestamp;
954
955         if (result == 0)                        /* probably can't happen? */
956                 PG_RETURN_NULL();
957
958         PG_RETURN_TIMESTAMPTZ(result);
959 }
960
961
962 Datum
963 pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
964 {
965         int32           beid = PG_GETARG_INT32(0);
966         PgBackendStatus *beentry;
967         SockAddr        zero_clientaddr;
968         char            remote_host[NI_MAXHOST];
969         int                     ret;
970
971         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
972                 PG_RETURN_NULL();
973
974         if (!superuser() && beentry->st_userid != GetUserId())
975                 PG_RETURN_NULL();
976
977         /* A zeroed client addr means we don't know */
978         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
979         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
980                            sizeof(zero_clientaddr)) == 0)
981                 PG_RETURN_NULL();
982
983         switch (beentry->st_clientaddr.addr.ss_family)
984         {
985                 case AF_INET:
986 #ifdef HAVE_IPV6
987                 case AF_INET6:
988 #endif
989                         break;
990                 default:
991                         PG_RETURN_NULL();
992         }
993
994         remote_host[0] = '\0';
995         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
996                                                          beentry->st_clientaddr.salen,
997                                                          remote_host, sizeof(remote_host),
998                                                          NULL, 0,
999                                                          NI_NUMERICHOST | NI_NUMERICSERV);
1000         if (ret != 0)
1001                 PG_RETURN_NULL();
1002
1003         clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
1004
1005         PG_RETURN_INET_P(DirectFunctionCall1(inet_in,
1006                                                                                  CStringGetDatum(remote_host)));
1007 }
1008
1009 Datum
1010 pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
1011 {
1012         int32           beid = PG_GETARG_INT32(0);
1013         PgBackendStatus *beentry;
1014         SockAddr        zero_clientaddr;
1015         char            remote_port[NI_MAXSERV];
1016         int                     ret;
1017
1018         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
1019                 PG_RETURN_NULL();
1020
1021         if (!superuser() && beentry->st_userid != GetUserId())
1022                 PG_RETURN_NULL();
1023
1024         /* A zeroed client addr means we don't know */
1025         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
1026         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
1027                            sizeof(zero_clientaddr)) == 0)
1028                 PG_RETURN_NULL();
1029
1030         switch (beentry->st_clientaddr.addr.ss_family)
1031         {
1032                 case AF_INET:
1033 #ifdef HAVE_IPV6
1034                 case AF_INET6:
1035 #endif
1036                         break;
1037                 case AF_UNIX:
1038                         PG_RETURN_INT32(-1);
1039                 default:
1040                         PG_RETURN_NULL();
1041         }
1042
1043         remote_port[0] = '\0';
1044         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
1045                                                          beentry->st_clientaddr.salen,
1046                                                          NULL, 0,
1047                                                          remote_port, sizeof(remote_port),
1048                                                          NI_NUMERICHOST | NI_NUMERICSERV);
1049         if (ret != 0)
1050                 PG_RETURN_NULL();
1051
1052         PG_RETURN_DATUM(DirectFunctionCall1(int4in,
1053                                                                                 CStringGetDatum(remote_port)));
1054 }
1055
1056
1057 Datum
1058 pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
1059 {
1060         Oid                     dbid = PG_GETARG_OID(0);
1061         int32           result;
1062         int                     tot_backends = pgstat_fetch_stat_numbackends();
1063         int                     beid;
1064
1065         result = 0;
1066         for (beid = 1; beid <= tot_backends; beid++)
1067         {
1068                 PgBackendStatus *beentry = pgstat_fetch_stat_beentry(beid);
1069
1070                 if (beentry && beentry->st_databaseid == dbid)
1071                         result++;
1072         }
1073
1074         PG_RETURN_INT32(result);
1075 }
1076
1077
1078 Datum
1079 pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS)
1080 {
1081         Oid                     dbid = PG_GETARG_OID(0);
1082         int64           result;
1083         PgStat_StatDBEntry *dbentry;
1084
1085         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1086                 result = 0;
1087         else
1088                 result = (int64) (dbentry->n_xact_commit);
1089
1090         PG_RETURN_INT64(result);
1091 }
1092
1093
1094 Datum
1095 pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)
1096 {
1097         Oid                     dbid = PG_GETARG_OID(0);
1098         int64           result;
1099         PgStat_StatDBEntry *dbentry;
1100
1101         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1102                 result = 0;
1103         else
1104                 result = (int64) (dbentry->n_xact_rollback);
1105
1106         PG_RETURN_INT64(result);
1107 }
1108
1109
1110 Datum
1111 pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)
1112 {
1113         Oid                     dbid = PG_GETARG_OID(0);
1114         int64           result;
1115         PgStat_StatDBEntry *dbentry;
1116
1117         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1118                 result = 0;
1119         else
1120                 result = (int64) (dbentry->n_blocks_fetched);
1121
1122         PG_RETURN_INT64(result);
1123 }
1124
1125
1126 Datum
1127 pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)
1128 {
1129         Oid                     dbid = PG_GETARG_OID(0);
1130         int64           result;
1131         PgStat_StatDBEntry *dbentry;
1132
1133         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1134                 result = 0;
1135         else
1136                 result = (int64) (dbentry->n_blocks_hit);
1137
1138         PG_RETURN_INT64(result);
1139 }
1140
1141
1142 Datum
1143 pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS)
1144 {
1145         Oid                     dbid = PG_GETARG_OID(0);
1146         int64           result;
1147         PgStat_StatDBEntry *dbentry;
1148
1149         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1150                 result = 0;
1151         else
1152                 result = (int64) (dbentry->n_tuples_returned);
1153
1154         PG_RETURN_INT64(result);
1155 }
1156
1157
1158 Datum
1159 pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS)
1160 {
1161         Oid                     dbid = PG_GETARG_OID(0);
1162         int64           result;
1163         PgStat_StatDBEntry *dbentry;
1164
1165         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1166                 result = 0;
1167         else
1168                 result = (int64) (dbentry->n_tuples_fetched);
1169
1170         PG_RETURN_INT64(result);
1171 }
1172
1173
1174 Datum
1175 pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS)
1176 {
1177         Oid                     dbid = PG_GETARG_OID(0);
1178         int64           result;
1179         PgStat_StatDBEntry *dbentry;
1180
1181         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1182                 result = 0;
1183         else
1184                 result = (int64) (dbentry->n_tuples_inserted);
1185
1186         PG_RETURN_INT64(result);
1187 }
1188
1189
1190 Datum
1191 pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS)
1192 {
1193         Oid                     dbid = PG_GETARG_OID(0);
1194         int64           result;
1195         PgStat_StatDBEntry *dbentry;
1196
1197         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1198                 result = 0;
1199         else
1200                 result = (int64) (dbentry->n_tuples_updated);
1201
1202         PG_RETURN_INT64(result);
1203 }
1204
1205
1206 Datum
1207 pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS)
1208 {
1209         Oid                     dbid = PG_GETARG_OID(0);
1210         int64           result;
1211         PgStat_StatDBEntry *dbentry;
1212
1213         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1214                 result = 0;
1215         else
1216                 result = (int64) (dbentry->n_tuples_deleted);
1217
1218         PG_RETURN_INT64(result);
1219 }
1220
1221 Datum
1222 pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)
1223 {
1224         Oid                     dbid = PG_GETARG_OID(0);
1225         TimestampTz result;
1226         PgStat_StatDBEntry *dbentry;
1227
1228         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1229                 result = 0;
1230         else
1231                 result = dbentry->stat_reset_timestamp;
1232
1233         if (result == 0)
1234                 PG_RETURN_NULL();
1235         else
1236                 PG_RETURN_TIMESTAMPTZ(result);
1237 }
1238
1239 Datum
1240 pg_stat_get_db_temp_files(PG_FUNCTION_ARGS)
1241 {
1242         Oid                     dbid = PG_GETARG_OID(0);
1243         int64           result;
1244         PgStat_StatDBEntry *dbentry;
1245
1246         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1247                 result = 0;
1248         else
1249                 result = dbentry->n_temp_files;
1250
1251         PG_RETURN_INT64(result);
1252 }
1253
1254
1255 Datum
1256 pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS)
1257 {
1258         Oid                     dbid = PG_GETARG_OID(0);
1259         int64           result;
1260         PgStat_StatDBEntry *dbentry;
1261
1262         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1263                 result = 0;
1264         else
1265                 result = dbentry->n_temp_bytes;
1266
1267         PG_RETURN_INT64(result);
1268 }
1269
1270 Datum
1271 pg_stat_get_db_conflict_tablespace(PG_FUNCTION_ARGS)
1272 {
1273         Oid                     dbid = PG_GETARG_OID(0);
1274         int64           result;
1275         PgStat_StatDBEntry *dbentry;
1276
1277         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1278                 result = 0;
1279         else
1280                 result = (int64) (dbentry->n_conflict_tablespace);
1281
1282         PG_RETURN_INT64(result);
1283 }
1284
1285 Datum
1286 pg_stat_get_db_conflict_lock(PG_FUNCTION_ARGS)
1287 {
1288         Oid                     dbid = PG_GETARG_OID(0);
1289         int64           result;
1290         PgStat_StatDBEntry *dbentry;
1291
1292         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1293                 result = 0;
1294         else
1295                 result = (int64) (dbentry->n_conflict_lock);
1296
1297         PG_RETURN_INT64(result);
1298 }
1299
1300 Datum
1301 pg_stat_get_db_conflict_snapshot(PG_FUNCTION_ARGS)
1302 {
1303         Oid                     dbid = PG_GETARG_OID(0);
1304         int64           result;
1305         PgStat_StatDBEntry *dbentry;
1306
1307         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1308                 result = 0;
1309         else
1310                 result = (int64) (dbentry->n_conflict_snapshot);
1311
1312         PG_RETURN_INT64(result);
1313 }
1314
1315 Datum
1316 pg_stat_get_db_conflict_bufferpin(PG_FUNCTION_ARGS)
1317 {
1318         Oid                     dbid = PG_GETARG_OID(0);
1319         int64           result;
1320         PgStat_StatDBEntry *dbentry;
1321
1322         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1323                 result = 0;
1324         else
1325                 result = (int64) (dbentry->n_conflict_bufferpin);
1326
1327         PG_RETURN_INT64(result);
1328 }
1329
1330 Datum
1331 pg_stat_get_db_conflict_startup_deadlock(PG_FUNCTION_ARGS)
1332 {
1333         Oid                     dbid = PG_GETARG_OID(0);
1334         int64           result;
1335         PgStat_StatDBEntry *dbentry;
1336
1337         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1338                 result = 0;
1339         else
1340                 result = (int64) (dbentry->n_conflict_startup_deadlock);
1341
1342         PG_RETURN_INT64(result);
1343 }
1344
1345 Datum
1346 pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS)
1347 {
1348         Oid                     dbid = PG_GETARG_OID(0);
1349         int64           result;
1350         PgStat_StatDBEntry *dbentry;
1351
1352         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1353                 result = 0;
1354         else
1355                 result = (int64) (
1356                                                   dbentry->n_conflict_tablespace +
1357                                                   dbentry->n_conflict_lock +
1358                                                   dbentry->n_conflict_snapshot +
1359                                                   dbentry->n_conflict_bufferpin +
1360                                                   dbentry->n_conflict_startup_deadlock);
1361
1362         PG_RETURN_INT64(result);
1363 }
1364
1365 Datum
1366 pg_stat_get_db_deadlocks(PG_FUNCTION_ARGS)
1367 {
1368         Oid                     dbid = PG_GETARG_OID(0);
1369         int64           result;
1370         PgStat_StatDBEntry *dbentry;
1371
1372         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1373                 result = 0;
1374         else
1375                 result = (int64) (dbentry->n_deadlocks);
1376
1377         PG_RETURN_INT64(result);
1378 }
1379
1380 Datum
1381 pg_stat_get_db_blk_read_time(PG_FUNCTION_ARGS)
1382 {
1383         Oid                     dbid = PG_GETARG_OID(0);
1384         double          result;
1385         PgStat_StatDBEntry *dbentry;
1386
1387         /* convert counter from microsec to millisec for display */
1388         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1389                 result = 0;
1390         else
1391                 result = ((double) dbentry->n_block_read_time) / 1000.0;
1392
1393         PG_RETURN_FLOAT8(result);
1394 }
1395
1396 Datum
1397 pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS)
1398 {
1399         Oid                     dbid = PG_GETARG_OID(0);
1400         double          result;
1401         PgStat_StatDBEntry *dbentry;
1402
1403         /* convert counter from microsec to millisec for display */
1404         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
1405                 result = 0;
1406         else
1407                 result = ((double) dbentry->n_block_write_time) / 1000.0;
1408
1409         PG_RETURN_FLOAT8(result);
1410 }
1411
1412 Datum
1413 pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
1414 {
1415         PG_RETURN_INT64(pgstat_fetch_global()->timed_checkpoints);
1416 }
1417
1418 Datum
1419 pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
1420 {
1421         PG_RETURN_INT64(pgstat_fetch_global()->requested_checkpoints);
1422 }
1423
1424 Datum
1425 pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
1426 {
1427         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_checkpoints);
1428 }
1429
1430 Datum
1431 pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)
1432 {
1433         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_clean);
1434 }
1435
1436 Datum
1437 pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
1438 {
1439         PG_RETURN_INT64(pgstat_fetch_global()->maxwritten_clean);
1440 }
1441
1442 Datum
1443 pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS)
1444 {
1445         /* time is already in msec, just convert to double for presentation */
1446         PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_write_time);
1447 }
1448
1449 Datum
1450 pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
1451 {
1452         /* time is already in msec, just convert to double for presentation */
1453         PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_sync_time);
1454 }
1455
1456 Datum
1457 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
1458 {
1459         PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stat_reset_timestamp);
1460 }
1461
1462 Datum
1463 pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
1464 {
1465         PG_RETURN_INT64(pgstat_fetch_global()->buf_written_backend);
1466 }
1467
1468 Datum
1469 pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)
1470 {
1471         PG_RETURN_INT64(pgstat_fetch_global()->buf_fsync_backend);
1472 }
1473
1474 Datum
1475 pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
1476 {
1477         PG_RETURN_INT64(pgstat_fetch_global()->buf_alloc);
1478 }
1479
1480 Datum
1481 pg_stat_get_xact_numscans(PG_FUNCTION_ARGS)
1482 {
1483         Oid                     relid = PG_GETARG_OID(0);
1484         int64           result;
1485         PgStat_TableStatus *tabentry;
1486
1487         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1488                 result = 0;
1489         else
1490                 result = (int64) (tabentry->t_counts.t_numscans);
1491
1492         PG_RETURN_INT64(result);
1493 }
1494
1495 Datum
1496 pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS)
1497 {
1498         Oid                     relid = PG_GETARG_OID(0);
1499         int64           result;
1500         PgStat_TableStatus *tabentry;
1501
1502         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1503                 result = 0;
1504         else
1505                 result = (int64) (tabentry->t_counts.t_tuples_returned);
1506
1507         PG_RETURN_INT64(result);
1508 }
1509
1510 Datum
1511 pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS)
1512 {
1513         Oid                     relid = PG_GETARG_OID(0);
1514         int64           result;
1515         PgStat_TableStatus *tabentry;
1516
1517         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1518                 result = 0;
1519         else
1520                 result = (int64) (tabentry->t_counts.t_tuples_fetched);
1521
1522         PG_RETURN_INT64(result);
1523 }
1524
1525 Datum
1526 pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS)
1527 {
1528         Oid                     relid = PG_GETARG_OID(0);
1529         int64           result;
1530         PgStat_TableStatus *tabentry;
1531         PgStat_TableXactStatus *trans;
1532
1533         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1534                 result = 0;
1535         else
1536         {
1537                 result = tabentry->t_counts.t_tuples_inserted;
1538                 /* live subtransactions' counts aren't in t_tuples_inserted yet */
1539                 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1540                         result += trans->tuples_inserted;
1541         }
1542
1543         PG_RETURN_INT64(result);
1544 }
1545
1546 Datum
1547 pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS)
1548 {
1549         Oid                     relid = PG_GETARG_OID(0);
1550         int64           result;
1551         PgStat_TableStatus *tabentry;
1552         PgStat_TableXactStatus *trans;
1553
1554         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1555                 result = 0;
1556         else
1557         {
1558                 result = tabentry->t_counts.t_tuples_updated;
1559                 /* live subtransactions' counts aren't in t_tuples_updated yet */
1560                 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1561                         result += trans->tuples_updated;
1562         }
1563
1564         PG_RETURN_INT64(result);
1565 }
1566
1567 Datum
1568 pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS)
1569 {
1570         Oid                     relid = PG_GETARG_OID(0);
1571         int64           result;
1572         PgStat_TableStatus *tabentry;
1573         PgStat_TableXactStatus *trans;
1574
1575         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1576                 result = 0;
1577         else
1578         {
1579                 result = tabentry->t_counts.t_tuples_deleted;
1580                 /* live subtransactions' counts aren't in t_tuples_deleted yet */
1581                 for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
1582                         result += trans->tuples_deleted;
1583         }
1584
1585         PG_RETURN_INT64(result);
1586 }
1587
1588 Datum
1589 pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS)
1590 {
1591         Oid                     relid = PG_GETARG_OID(0);
1592         int64           result;
1593         PgStat_TableStatus *tabentry;
1594
1595         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1596                 result = 0;
1597         else
1598                 result = (int64) (tabentry->t_counts.t_tuples_hot_updated);
1599
1600         PG_RETURN_INT64(result);
1601 }
1602
1603 Datum
1604 pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS)
1605 {
1606         Oid                     relid = PG_GETARG_OID(0);
1607         int64           result;
1608         PgStat_TableStatus *tabentry;
1609
1610         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1611                 result = 0;
1612         else
1613                 result = (int64) (tabentry->t_counts.t_blocks_fetched);
1614
1615         PG_RETURN_INT64(result);
1616 }
1617
1618 Datum
1619 pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS)
1620 {
1621         Oid                     relid = PG_GETARG_OID(0);
1622         int64           result;
1623         PgStat_TableStatus *tabentry;
1624
1625         if ((tabentry = find_tabstat_entry(relid)) == NULL)
1626                 result = 0;
1627         else
1628                 result = (int64) (tabentry->t_counts.t_blocks_hit);
1629
1630         PG_RETURN_INT64(result);
1631 }
1632
1633 Datum
1634 pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
1635 {
1636         Oid                     funcid = PG_GETARG_OID(0);
1637         PgStat_BackendFunctionEntry *funcentry;
1638
1639         if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1640                 PG_RETURN_NULL();
1641         PG_RETURN_INT64(funcentry->f_counts.f_numcalls);
1642 }
1643
1644 Datum
1645 pg_stat_get_xact_function_total_time(PG_FUNCTION_ARGS)
1646 {
1647         Oid                     funcid = PG_GETARG_OID(0);
1648         PgStat_BackendFunctionEntry *funcentry;
1649
1650         if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1651                 PG_RETURN_NULL();
1652         PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_total_time));
1653 }
1654
1655 Datum
1656 pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS)
1657 {
1658         Oid                     funcid = PG_GETARG_OID(0);
1659         PgStat_BackendFunctionEntry *funcentry;
1660
1661         if ((funcentry = find_funcstat_entry(funcid)) == NULL)
1662                 PG_RETURN_NULL();
1663         PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_self_time));
1664 }
1665
1666
1667 /* Discard the active statistics snapshot */
1668 Datum
1669 pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
1670 {
1671         pgstat_clear_snapshot();
1672
1673         PG_RETURN_VOID();
1674 }
1675
1676
1677 /* Reset all counters for the current database */
1678 Datum
1679 pg_stat_reset(PG_FUNCTION_ARGS)
1680 {
1681         pgstat_reset_counters();
1682
1683         PG_RETURN_VOID();
1684 }
1685
1686 /* Reset some shared cluster-wide counters */
1687 Datum
1688 pg_stat_reset_shared(PG_FUNCTION_ARGS)
1689 {
1690         char       *target = text_to_cstring(PG_GETARG_TEXT_PP(0));
1691
1692         pgstat_reset_shared_counters(target);
1693
1694         PG_RETURN_VOID();
1695 }
1696
1697 /* Reset a a single counter in the current database */
1698 Datum
1699 pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
1700 {
1701         Oid                     taboid = PG_GETARG_OID(0);
1702
1703         pgstat_reset_single_counter(taboid, RESET_TABLE);
1704
1705         PG_RETURN_VOID();
1706 }
1707
1708 Datum
1709 pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
1710 {
1711         Oid                     funcoid = PG_GETARG_OID(0);
1712
1713         pgstat_reset_single_counter(funcoid, RESET_FUNCTION);
1714
1715         PG_RETURN_VOID();
1716 }
1717
1718 Datum
1719 pg_stat_get_archiver(PG_FUNCTION_ARGS)
1720 {
1721         TupleDesc       tupdesc;
1722         Datum           values[7];
1723         bool            nulls[7];
1724         PgStat_ArchiverStats *archiver_stats;
1725
1726         /* Initialise values and NULL flags arrays */
1727         MemSet(values, 0, sizeof(values));
1728         MemSet(nulls, 0, sizeof(nulls));
1729
1730         /* Initialise attributes information in the tuple descriptor */
1731         tupdesc = CreateTemplateTupleDesc(7, false);
1732         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count",
1733                                            INT8OID, -1, 0);
1734         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
1735                                            TEXTOID, -1, 0);
1736         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time",
1737                                            TIMESTAMPTZOID, -1, 0);
1738         TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count",
1739                                            INT8OID, -1, 0);
1740         TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
1741                                            TEXTOID, -1, 0);
1742         TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time",
1743                                            TIMESTAMPTZOID, -1, 0);
1744         TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset",
1745                                            TIMESTAMPTZOID, -1, 0);
1746
1747         BlessTupleDesc(tupdesc);
1748
1749         /* Get statistics about the archiver process */
1750         archiver_stats = pgstat_fetch_stat_archiver();
1751
1752         /* Fill values and NULLs */
1753         values[0] = Int64GetDatum(archiver_stats->archived_count);
1754         if (archiver_stats->last_archived_wal == 0)
1755                 nulls[1] = true;
1756         else
1757                 values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
1758
1759         if (archiver_stats->last_archived_timestamp == 0)
1760                 nulls[2] = true;
1761         else
1762                 values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp);
1763
1764         values[3] = Int64GetDatum(archiver_stats->failed_count);
1765         if (archiver_stats->last_failed_wal == 0)
1766                 nulls[4] = true;
1767         else
1768                 values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
1769
1770         if (archiver_stats->last_failed_timestamp == 0)
1771                 nulls[5] = true;
1772         else
1773                 values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp);
1774
1775         if (archiver_stats->stat_reset_timestamp == 0)
1776                 nulls[6] = true;
1777         else
1778                 values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
1779
1780         /* Returns the record as Datum */
1781         PG_RETURN_DATUM(HeapTupleGetDatum(
1782                                                 heap_form_tuple(tupdesc, values, nulls)));
1783 }