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