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