]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/pgstatfuncs.c
Add n_live_tuples and n_dead_tuples to pg_stat_all_tables.
[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-2006, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.36 2007/01/02 20:59:31 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "funcapi.h"
18 #include "miscadmin.h"
19 #include "pgstat.h"
20 #include "utils/builtins.h"
21 #include "utils/inet.h"
22 #include "libpq/ip.h"
23
24 /* bogus ... these externs should be in a header file */
25 extern Datum pg_stat_get_numscans(PG_FUNCTION_ARGS);
26 extern Datum pg_stat_get_tuples_returned(PG_FUNCTION_ARGS);
27 extern Datum pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS);
28 extern Datum pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS);
29 extern Datum pg_stat_get_tuples_updated(PG_FUNCTION_ARGS);
30 extern Datum pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS);
31 extern Datum pg_stat_get_live_tuples(PG_FUNCTION_ARGS);
32 extern Datum pg_stat_get_dead_tuples(PG_FUNCTION_ARGS);
33 extern Datum pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS);
34 extern Datum pg_stat_get_blocks_hit(PG_FUNCTION_ARGS);
35 extern Datum pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS);
36 extern Datum pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS);
37 extern Datum pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS);
38 extern Datum pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS);
39
40 extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS);
41 extern Datum pg_backend_pid(PG_FUNCTION_ARGS);
42 extern Datum pg_stat_reset(PG_FUNCTION_ARGS);
43 extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS);
44 extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS);
45 extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS);
46 extern Datum pg_stat_get_backend_activity(PG_FUNCTION_ARGS);
47 extern Datum pg_stat_get_backend_waiting(PG_FUNCTION_ARGS);
48 extern Datum pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS);
49 extern Datum pg_stat_get_backend_txn_start(PG_FUNCTION_ARGS);
50 extern Datum pg_stat_get_backend_start(PG_FUNCTION_ARGS);
51 extern Datum pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS);
52 extern Datum pg_stat_get_backend_client_port(PG_FUNCTION_ARGS);
53
54 extern Datum pg_stat_get_db_numbackends(PG_FUNCTION_ARGS);
55 extern Datum pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS);
56 extern Datum pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS);
57 extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS);
58 extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS);
59
60
61 Datum
62 pg_stat_get_numscans(PG_FUNCTION_ARGS)
63 {
64         Oid                     relid = PG_GETARG_OID(0);
65         int64           result;
66         PgStat_StatTabEntry *tabentry;
67
68         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
69                 result = 0;
70         else
71                 result = (int64) (tabentry->numscans);
72
73         PG_RETURN_INT64(result);
74 }
75
76
77 Datum
78 pg_stat_get_tuples_returned(PG_FUNCTION_ARGS)
79 {
80         Oid                     relid = PG_GETARG_OID(0);
81         int64           result;
82         PgStat_StatTabEntry *tabentry;
83
84         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
85                 result = 0;
86         else
87                 result = (int64) (tabentry->tuples_returned);
88
89         PG_RETURN_INT64(result);
90 }
91
92
93 Datum
94 pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS)
95 {
96         Oid                     relid = PG_GETARG_OID(0);
97         int64           result;
98         PgStat_StatTabEntry *tabentry;
99
100         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
101                 result = 0;
102         else
103                 result = (int64) (tabentry->tuples_fetched);
104
105         PG_RETURN_INT64(result);
106 }
107
108
109 Datum
110 pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS)
111 {
112         Oid                     relid = PG_GETARG_OID(0);
113         int64           result;
114         PgStat_StatTabEntry *tabentry;
115
116         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
117                 result = 0;
118         else
119                 result = (int64) (tabentry->tuples_inserted);
120
121         PG_RETURN_INT64(result);
122 }
123
124
125 Datum
126 pg_stat_get_tuples_updated(PG_FUNCTION_ARGS)
127 {
128         Oid                     relid = PG_GETARG_OID(0);
129         int64           result;
130         PgStat_StatTabEntry *tabentry;
131
132         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
133                 result = 0;
134         else
135                 result = (int64) (tabentry->tuples_updated);
136
137         PG_RETURN_INT64(result);
138 }
139
140
141 Datum
142 pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS)
143 {
144         Oid                     relid = PG_GETARG_OID(0);
145         int64           result;
146         PgStat_StatTabEntry *tabentry;
147
148         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
149                 result = 0;
150         else
151                 result = (int64) (tabentry->tuples_deleted);
152
153         PG_RETURN_INT64(result);
154 }
155
156
157 Datum
158 pg_stat_get_live_tuples(PG_FUNCTION_ARGS)
159
160         Oid             relid = PG_GETARG_OID(0);
161         int64   result;
162         PgStat_StatTabEntry     *tabentry;
163  
164         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
165                 result = 0;
166         else
167                 result = (int64) (tabentry->n_live_tuples);
168         
169         PG_RETURN_INT64(result);
170 }
171
172         
173 Datum
174 pg_stat_get_dead_tuples(PG_FUNCTION_ARGS)
175 {
176         Oid             relid = PG_GETARG_OID(0);
177         int64   result;
178         PgStat_StatTabEntry     *tabentry;
179
180         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
181                 result = 0;
182         else
183                 result = (int64) (tabentry->n_dead_tuples);
184         
185         PG_RETURN_INT64(result);
186 }
187
188
189 Datum
190 pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS)
191 {
192         Oid                     relid = PG_GETARG_OID(0);
193         int64           result;
194         PgStat_StatTabEntry *tabentry;
195
196         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
197                 result = 0;
198         else
199                 result = (int64) (tabentry->blocks_fetched);
200
201         PG_RETURN_INT64(result);
202 }
203
204
205 Datum
206 pg_stat_get_blocks_hit(PG_FUNCTION_ARGS)
207 {
208         Oid                     relid = PG_GETARG_OID(0);
209         int64           result;
210         PgStat_StatTabEntry *tabentry;
211
212         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
213                 result = 0;
214         else
215                 result = (int64) (tabentry->blocks_hit);
216
217         PG_RETURN_INT64(result);
218 }
219
220 Datum
221 pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS)
222 {
223         Oid                     relid = PG_GETARG_OID(0);
224         TimestampTz result;
225         PgStat_StatTabEntry *tabentry;
226
227         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
228                 result = 0;
229         else
230                 result = tabentry->vacuum_timestamp;
231
232         if (result == 0)
233                 PG_RETURN_NULL();
234         else
235                 PG_RETURN_TIMESTAMPTZ(result);
236 }
237
238 Datum
239 pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS)
240 {
241         Oid                     relid = PG_GETARG_OID(0);
242         TimestampTz result;
243         PgStat_StatTabEntry *tabentry;
244
245         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
246                 result = 0;
247         else
248                 result = tabentry->autovac_vacuum_timestamp;
249
250         if (result == 0)
251                 PG_RETURN_NULL();
252         else
253                 PG_RETURN_TIMESTAMPTZ(result);
254 }
255
256 Datum
257 pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS)
258 {
259         Oid                     relid = PG_GETARG_OID(0);
260         TimestampTz result;
261         PgStat_StatTabEntry *tabentry;
262
263         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
264                 result = 0;
265         else
266                 result = tabentry->analyze_timestamp;
267
268         if (result == 0)
269                 PG_RETURN_NULL();
270         else
271                 PG_RETURN_TIMESTAMPTZ(result);
272 }
273
274 Datum
275 pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS)
276 {
277         Oid                     relid = PG_GETARG_OID(0);
278         TimestampTz result;
279         PgStat_StatTabEntry *tabentry;
280
281         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
282                 result = 0;
283         else
284                 result = tabentry->autovac_analyze_timestamp;
285
286         if (result == 0)
287                 PG_RETURN_NULL();
288         else
289                 PG_RETURN_TIMESTAMPTZ(result);
290 }
291
292 Datum
293 pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
294 {
295         FuncCallContext *funcctx;
296         int                *fctx;
297         int32           result;
298
299         /* stuff done only on the first call of the function */
300         if (SRF_IS_FIRSTCALL())
301         {
302                 /* create a function context for cross-call persistence */
303                 funcctx = SRF_FIRSTCALL_INIT();
304
305                 fctx = MemoryContextAlloc(funcctx->multi_call_memory_ctx,
306                                                                   2 * sizeof(int));
307                 funcctx->user_fctx = fctx;
308
309                 fctx[0] = 0;
310                 fctx[1] = pgstat_fetch_stat_numbackends();
311         }
312
313         /* stuff done on every call of the function */
314         funcctx = SRF_PERCALL_SETUP();
315         fctx = funcctx->user_fctx;
316
317         fctx[0] += 1;
318         result = fctx[0];
319
320         if (result <= fctx[1])
321         {
322                 /* do when there is more left to send */
323                 SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
324         }
325         else
326         {
327                 /* do when there is no more left */
328                 SRF_RETURN_DONE(funcctx);
329         }
330 }
331
332
333 Datum
334 pg_backend_pid(PG_FUNCTION_ARGS)
335 {
336         PG_RETURN_INT32(MyProcPid);
337 }
338
339 /*
340  * Built-in function for resetting the counters
341  */
342 Datum
343 pg_stat_reset(PG_FUNCTION_ARGS)
344 {
345         pgstat_reset_counters();
346
347         PG_RETURN_BOOL(true);
348 }
349
350 Datum
351 pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
352 {
353         int32           beid = PG_GETARG_INT32(0);
354         PgBackendStatus *beentry;
355
356         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
357                 PG_RETURN_NULL();
358
359         PG_RETURN_INT32(beentry->st_procpid);
360 }
361
362
363 Datum
364 pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
365 {
366         int32           beid = PG_GETARG_INT32(0);
367         PgBackendStatus *beentry;
368
369         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
370                 PG_RETURN_NULL();
371
372         PG_RETURN_OID(beentry->st_databaseid);
373 }
374
375
376 Datum
377 pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
378 {
379         int32           beid = PG_GETARG_INT32(0);
380         PgBackendStatus *beentry;
381
382         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
383                 PG_RETURN_NULL();
384
385         PG_RETURN_OID(beentry->st_userid);
386 }
387
388
389 Datum
390 pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
391 {
392         int32           beid = PG_GETARG_INT32(0);
393         text       *result;
394         PgBackendStatus *beentry;
395         int                     len;
396         const char *activity;
397
398         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
399                 activity = "<backend information not available>";
400         else if (!superuser() && beentry->st_userid != GetUserId())
401                 activity = "<insufficient privilege>";
402         else if (*(beentry->st_activity) == '\0')
403                 activity = "<command string not enabled>";
404         else
405                 activity = beentry->st_activity;
406
407         len = strlen(activity);
408         result = palloc(VARHDRSZ + len);
409         VARATT_SIZEP(result) = VARHDRSZ + len;
410         memcpy(VARDATA(result), activity, len);
411
412         PG_RETURN_TEXT_P(result);
413 }
414
415
416 Datum
417 pg_stat_get_backend_waiting(PG_FUNCTION_ARGS)
418 {
419         int32           beid = PG_GETARG_INT32(0);
420         bool            result;
421         PgBackendStatus *beentry;
422
423         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
424                 PG_RETURN_NULL();
425
426         if (!superuser() && beentry->st_userid != GetUserId())
427                 PG_RETURN_NULL();
428
429         result = beentry->st_waiting;
430
431         PG_RETURN_BOOL(result);
432 }
433
434
435 Datum
436 pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
437 {
438         int32           beid = PG_GETARG_INT32(0);
439         TimestampTz result;
440         PgBackendStatus *beentry;
441
442         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
443                 PG_RETURN_NULL();
444
445         if (!superuser() && beentry->st_userid != GetUserId())
446                 PG_RETURN_NULL();
447
448         result = beentry->st_activity_start_timestamp;
449
450         /*
451          * No time recorded for start of current query -- this is the case if the
452          * user hasn't enabled query-level stats collection.
453          */
454         if (result == 0)
455                 PG_RETURN_NULL();
456
457         PG_RETURN_TIMESTAMPTZ(result);
458 }
459
460
461 Datum
462 pg_stat_get_backend_txn_start(PG_FUNCTION_ARGS)
463 {
464         int32           beid = PG_GETARG_INT32(0);
465         TimestampTz result;
466         PgBackendStatus *beentry;
467
468         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
469                 PG_RETURN_NULL();
470
471         if (!superuser() && beentry->st_userid != GetUserId())
472                 PG_RETURN_NULL();
473
474         result = beentry->st_txn_start_timestamp;
475
476         if (result == 0)                        /* not in a transaction */
477                 PG_RETURN_NULL();
478
479         PG_RETURN_TIMESTAMPTZ(result);
480 }
481
482
483 Datum
484 pg_stat_get_backend_start(PG_FUNCTION_ARGS)
485 {
486         int32           beid = PG_GETARG_INT32(0);
487         TimestampTz result;
488         PgBackendStatus *beentry;
489
490         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
491                 PG_RETURN_NULL();
492
493         if (!superuser() && beentry->st_userid != GetUserId())
494                 PG_RETURN_NULL();
495
496         result = beentry->st_proc_start_timestamp;
497
498         if (result == 0)                        /* probably can't happen? */
499                 PG_RETURN_NULL();
500
501         PG_RETURN_TIMESTAMPTZ(result);
502 }
503
504
505 Datum
506 pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
507 {
508         int32           beid = PG_GETARG_INT32(0);
509         PgBackendStatus *beentry;
510         SockAddr        zero_clientaddr;
511         char            remote_host[NI_MAXHOST];
512         int                     ret;
513
514         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
515                 PG_RETURN_NULL();
516
517         if (!superuser() && beentry->st_userid != GetUserId())
518                 PG_RETURN_NULL();
519
520         /* A zeroed client addr means we don't know */
521         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
522         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
523                            sizeof(zero_clientaddr) == 0))
524                 PG_RETURN_NULL();
525
526         switch (beentry->st_clientaddr.addr.ss_family)
527         {
528                 case AF_INET:
529 #ifdef HAVE_IPV6
530                 case AF_INET6:
531 #endif
532                         break;
533                 default:
534                         PG_RETURN_NULL();
535         }
536
537         remote_host[0] = '\0';
538         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
539                                                          beentry->st_clientaddr.salen,
540                                                          remote_host, sizeof(remote_host),
541                                                          NULL, 0,
542                                                          NI_NUMERICHOST | NI_NUMERICSERV);
543         if (ret)
544                 PG_RETURN_NULL();
545
546         PG_RETURN_INET_P(DirectFunctionCall1(inet_in,
547                                                                                  CStringGetDatum(remote_host)));
548 }
549
550 Datum
551 pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
552 {
553         int32           beid = PG_GETARG_INT32(0);
554         PgBackendStatus *beentry;
555         SockAddr        zero_clientaddr;
556         char            remote_port[NI_MAXSERV];
557         int                     ret;
558
559         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
560                 PG_RETURN_NULL();
561
562         if (!superuser() && beentry->st_userid != GetUserId())
563                 PG_RETURN_NULL();
564
565         /* A zeroed client addr means we don't know */
566         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
567         if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
568                            sizeof(zero_clientaddr) == 0))
569                 PG_RETURN_NULL();
570
571         switch (beentry->st_clientaddr.addr.ss_family)
572         {
573                 case AF_INET:
574 #ifdef HAVE_IPV6
575                 case AF_INET6:
576 #endif
577                         break;
578                 case AF_UNIX:
579                         PG_RETURN_INT32(-1);
580                 default:
581                         PG_RETURN_NULL();
582         }
583
584         remote_port[0] = '\0';
585         ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
586                                                          beentry->st_clientaddr.salen,
587                                                          NULL, 0,
588                                                          remote_port, sizeof(remote_port),
589                                                          NI_NUMERICHOST | NI_NUMERICSERV);
590         if (ret)
591                 PG_RETURN_NULL();
592
593         PG_RETURN_DATUM(DirectFunctionCall1(int4in,
594                                                                                 CStringGetDatum(remote_port)));
595 }
596
597
598 Datum
599 pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
600 {
601         Oid                     dbid = PG_GETARG_OID(0);
602         int32           result;
603         int                     tot_backends = pgstat_fetch_stat_numbackends();
604         int                     beid;
605
606         result = 0;
607         for (beid = 1; beid <= tot_backends; beid++)
608         {
609                 PgBackendStatus *beentry = pgstat_fetch_stat_beentry(beid);
610
611                 if (beentry && beentry->st_databaseid == dbid)
612                         result++;
613         }
614
615         PG_RETURN_INT32(result);
616 }
617
618
619 Datum
620 pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS)
621 {
622         Oid                     dbid = PG_GETARG_OID(0);
623         int64           result;
624         PgStat_StatDBEntry *dbentry;
625
626         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
627                 result = 0;
628         else
629                 result = (int64) (dbentry->n_xact_commit);
630
631         PG_RETURN_INT64(result);
632 }
633
634
635 Datum
636 pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)
637 {
638         Oid                     dbid = PG_GETARG_OID(0);
639         int64           result;
640         PgStat_StatDBEntry *dbentry;
641
642         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
643                 result = 0;
644         else
645                 result = (int64) (dbentry->n_xact_rollback);
646
647         PG_RETURN_INT64(result);
648 }
649
650
651 Datum
652 pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)
653 {
654         Oid                     dbid = PG_GETARG_OID(0);
655         int64           result;
656         PgStat_StatDBEntry *dbentry;
657
658         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
659                 result = 0;
660         else
661                 result = (int64) (dbentry->n_blocks_fetched);
662
663         PG_RETURN_INT64(result);
664 }
665
666
667 Datum
668 pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)
669 {
670         Oid                     dbid = PG_GETARG_OID(0);
671         int64           result;
672         PgStat_StatDBEntry *dbentry;
673
674         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
675                 result = 0;
676         else
677                 result = (int64) (dbentry->n_blocks_hit);
678
679         PG_RETURN_INT64(result);
680 }