]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/pgstatfuncs.c
Have autovacuum report its activities to the stat collector.
[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.28 2006/05/19 15:15:37 alvherre Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/xact.h"
18 #include "fmgr.h"
19 #include "funcapi.h"
20 #include "miscadmin.h"
21 #include "nodes/execnodes.h"
22 #include "pgstat.h"
23 #include "utils/hsearch.h"
24 #include "utils/inet.h"
25 #include "utils/builtins.h"
26 #include "libpq/ip.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_blocks_fetched(PG_FUNCTION_ARGS);
36 extern Datum pg_stat_get_blocks_hit(PG_FUNCTION_ARGS);
37
38 extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS);
39 extern Datum pg_backend_pid(PG_FUNCTION_ARGS);
40 extern Datum pg_stat_reset(PG_FUNCTION_ARGS);
41 extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS);
42 extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS);
43 extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS);
44 extern Datum pg_stat_get_backend_activity(PG_FUNCTION_ARGS);
45 extern Datum pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS);
46 extern Datum pg_stat_get_backend_start(PG_FUNCTION_ARGS);
47 extern Datum pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS);
48 extern Datum pg_stat_get_backend_client_port(PG_FUNCTION_ARGS);
49
50 extern Datum pg_stat_get_db_numbackends(PG_FUNCTION_ARGS);
51 extern Datum pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS);
52 extern Datum pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS);
53 extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS);
54 extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS);
55
56
57 Datum
58 pg_stat_get_numscans(PG_FUNCTION_ARGS)
59 {
60         PgStat_StatTabEntry *tabentry;
61         Oid                     relid;
62         int64           result;
63
64         relid = PG_GETARG_OID(0);
65
66         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
67                 result = 0;
68         else
69                 result = (int64) (tabentry->numscans);
70
71         PG_RETURN_INT64(result);
72 }
73
74
75 Datum
76 pg_stat_get_tuples_returned(PG_FUNCTION_ARGS)
77 {
78         PgStat_StatTabEntry *tabentry;
79         Oid                     relid;
80         int64           result;
81
82         relid = PG_GETARG_OID(0);
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         PgStat_StatTabEntry *tabentry;
97         Oid                     relid;
98         int64           result;
99
100         relid = PG_GETARG_OID(0);
101
102         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
103                 result = 0;
104         else
105                 result = (int64) (tabentry->tuples_fetched);
106
107         PG_RETURN_INT64(result);
108 }
109
110
111 Datum
112 pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS)
113 {
114         PgStat_StatTabEntry *tabentry;
115         Oid                     relid;
116         int64           result;
117
118         relid = PG_GETARG_OID(0);
119
120         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
121                 result = 0;
122         else
123                 result = (int64) (tabentry->tuples_inserted);
124
125         PG_RETURN_INT64(result);
126 }
127
128
129 Datum
130 pg_stat_get_tuples_updated(PG_FUNCTION_ARGS)
131 {
132         PgStat_StatTabEntry *tabentry;
133         Oid                     relid;
134         int64           result;
135
136         relid = PG_GETARG_OID(0);
137
138         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
139                 result = 0;
140         else
141                 result = (int64) (tabentry->tuples_updated);
142
143         PG_RETURN_INT64(result);
144 }
145
146
147 Datum
148 pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS)
149 {
150         PgStat_StatTabEntry *tabentry;
151         Oid                     relid;
152         int64           result;
153
154         relid = PG_GETARG_OID(0);
155
156         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
157                 result = 0;
158         else
159                 result = (int64) (tabentry->tuples_deleted);
160
161         PG_RETURN_INT64(result);
162 }
163
164
165 Datum
166 pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS)
167 {
168         PgStat_StatTabEntry *tabentry;
169         Oid                     relid;
170         int64           result;
171
172         relid = PG_GETARG_OID(0);
173
174         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
175                 result = 0;
176         else
177                 result = (int64) (tabentry->blocks_fetched);
178
179         PG_RETURN_INT64(result);
180 }
181
182
183 Datum
184 pg_stat_get_blocks_hit(PG_FUNCTION_ARGS)
185 {
186         PgStat_StatTabEntry *tabentry;
187         Oid                     relid;
188         int64           result;
189
190         relid = PG_GETARG_OID(0);
191
192         if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
193                 result = 0;
194         else
195                 result = (int64) (tabentry->blocks_hit);
196
197         PG_RETURN_INT64(result);
198 }
199
200
201 Datum
202 pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
203 {
204         FuncCallContext *funcctx;
205         int                *fctx;
206         int32           result;
207
208         /* stuff done only on the first call of the function */
209         if (SRF_IS_FIRSTCALL())
210         {
211                 /* create a function context for cross-call persistence */
212                 funcctx = SRF_FIRSTCALL_INIT();
213
214                 fctx = MemoryContextAlloc(funcctx->multi_call_memory_ctx,
215                                                                   2 * sizeof(int));
216                 funcctx->user_fctx = fctx;
217
218                 fctx[0] = 0;
219                 fctx[1] = pgstat_fetch_stat_numbackends();
220         }
221
222         /* stuff done on every call of the function */
223         funcctx = SRF_PERCALL_SETUP();
224         fctx = funcctx->user_fctx;
225
226         fctx[0] += 1;
227         result = fctx[0];
228
229         if (result <= fctx[1])
230         {
231                 /* do when there is more left to send */
232                 SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
233         }
234         else
235         {
236                 /* do when there is no more left */
237                 SRF_RETURN_DONE(funcctx);
238         }
239 }
240
241
242 Datum
243 pg_backend_pid(PG_FUNCTION_ARGS)
244 {
245         PG_RETURN_INT32(MyProcPid);
246 }
247
248 /*
249  * Built-in function for resetting the counters
250  */
251 Datum
252 pg_stat_reset(PG_FUNCTION_ARGS)
253 {
254         pgstat_reset_counters();
255
256         PG_RETURN_BOOL(true);
257 }
258
259 Datum
260 pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
261 {
262         PgStat_StatBeEntry *beentry;
263         int32           beid;
264
265         beid = PG_GETARG_INT32(0);
266
267         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
268                 PG_RETURN_NULL();
269
270         PG_RETURN_INT32(beentry->procpid);
271 }
272
273
274 Datum
275 pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
276 {
277         PgStat_StatBeEntry *beentry;
278         int32           beid;
279
280         beid = PG_GETARG_INT32(0);
281
282         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
283                 PG_RETURN_NULL();
284
285         /* Not initialized yet? */
286         if (!OidIsValid(beentry->databaseid))
287                 PG_RETURN_NULL();
288
289         PG_RETURN_OID(beentry->databaseid);
290 }
291
292
293 Datum
294 pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
295 {
296         PgStat_StatBeEntry *beentry;
297         int32           beid;
298
299         beid = PG_GETARG_INT32(0);
300
301         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
302                 PG_RETURN_NULL();
303
304         /* Not initialized yet? */
305         if (!OidIsValid(beentry->userid))
306                 PG_RETURN_NULL();
307
308         PG_RETURN_OID(beentry->userid);
309 }
310
311
312 Datum
313 pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
314 {
315         PgStat_StatBeEntry *beentry;
316         int32           beid;
317         int                     len;
318         char       *activity;
319         text       *result;
320
321         beid = PG_GETARG_INT32(0);
322
323         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
324                 activity = "<backend information not available>";
325         else if (!superuser() && beentry->userid != GetUserId())
326                 activity = "<insufficient privilege>";
327         else if (*(beentry->activity) == '\0')
328                 activity = "<command string not enabled>";
329         else
330                 activity = beentry->activity;
331
332         len = strlen(activity);
333         result = palloc(VARHDRSZ + len);
334         VARATT_SIZEP(result) = VARHDRSZ + len;
335         memcpy(VARDATA(result), activity, len);
336
337         PG_RETURN_TEXT_P(result);
338 }
339
340
341 Datum
342 pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
343 {
344         int32           beid = PG_GETARG_INT32(0);
345         TimestampTz result;
346         PgStat_StatBeEntry *beentry;
347
348         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
349                 PG_RETURN_NULL();
350
351         if (!superuser() && beentry->userid != GetUserId())
352                 PG_RETURN_NULL();
353
354         result = beentry->activity_start_timestamp;
355
356         /*
357          * No time recorded for start of current query -- this is the case if the
358          * user hasn't enabled query-level stats collection.
359          */
360         if (result == 0)
361                 PG_RETURN_NULL();
362
363         PG_RETURN_TIMESTAMPTZ(result);
364 }
365
366 Datum
367 pg_stat_get_backend_start(PG_FUNCTION_ARGS)
368 {
369         int32           beid = PG_GETARG_INT32(0);
370         TimestampTz result;
371         PgStat_StatBeEntry *beentry;
372
373         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
374                 PG_RETURN_NULL();
375
376         if (!superuser() && beentry->userid != GetUserId())
377                 PG_RETURN_NULL();
378
379         result = beentry->start_timestamp;
380
381         if (result == 0)                        /* probably can't happen? */
382                 PG_RETURN_NULL();
383
384         PG_RETURN_TIMESTAMPTZ(result);
385 }
386
387
388 Datum
389 pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
390 {
391         PgStat_StatBeEntry *beentry;
392         SockAddr        zero_clientaddr;
393         int32           beid;
394         char            remote_host[NI_MAXHOST];
395         int                     ret;
396
397         beid = PG_GETARG_INT32(0);
398
399         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
400                 PG_RETURN_NULL();
401
402         /* Not initialized yet? */
403         if (!OidIsValid(beentry->userid))
404                 PG_RETURN_NULL();
405
406         if (!superuser() && beentry->userid != GetUserId())
407                 PG_RETURN_NULL();
408
409         /* A zeroed client addr means we don't know */
410         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
411         if (memcmp(&(beentry->clientaddr), &zero_clientaddr,
412                            sizeof(zero_clientaddr) == 0))
413                 PG_RETURN_NULL();
414
415         switch (beentry->clientaddr.addr.ss_family)
416         {
417                 case AF_INET:
418 #ifdef HAVE_IPV6
419                 case AF_INET6:
420 #endif
421                         break;
422                 default:
423                         PG_RETURN_NULL();
424         }
425
426         remote_host[0] = '\0';
427         ret = pg_getnameinfo_all(&beentry->clientaddr.addr, beentry->clientaddr.salen,
428                                                          remote_host, sizeof(remote_host),
429                                                          NULL, 0,
430                                                          NI_NUMERICHOST | NI_NUMERICSERV);
431         if (ret)
432                 PG_RETURN_NULL();
433
434         PG_RETURN_INET_P(DirectFunctionCall1(inet_in,
435                                                                                  CStringGetDatum(remote_host)));
436 }
437
438 Datum
439 pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
440 {
441         PgStat_StatBeEntry *beentry;
442         SockAddr        zero_clientaddr;
443         int32           beid;
444         char            remote_port[NI_MAXSERV];
445         int                     ret;
446
447         beid = PG_GETARG_INT32(0);
448
449         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
450                 PG_RETURN_NULL();
451
452         /* Not initialized yet? */
453         if (!OidIsValid(beentry->userid))
454                 PG_RETURN_NULL();
455
456         if (!superuser() && beentry->userid != GetUserId())
457                 PG_RETURN_NULL();
458
459         /* A zeroed client addr means we don't know */
460         memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
461         if (memcmp(&(beentry->clientaddr), &zero_clientaddr,
462                            sizeof(zero_clientaddr) == 0))
463                 PG_RETURN_NULL();
464
465         switch (beentry->clientaddr.addr.ss_family)
466         {
467                 case AF_INET:
468 #ifdef HAVE_IPV6
469                 case AF_INET6:
470 #endif
471                         break;
472                 case AF_UNIX:
473                         PG_RETURN_INT32(-1);
474                 default:
475                         PG_RETURN_NULL();
476         }
477
478         remote_port[0] = '\0';
479         ret = pg_getnameinfo_all(&beentry->clientaddr.addr,
480                                                          beentry->clientaddr.salen,
481                                                          NULL, 0,
482                                                          remote_port, sizeof(remote_port),
483                                                          NI_NUMERICHOST | NI_NUMERICSERV);
484         if (ret)
485                 PG_RETURN_NULL();
486
487         PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(remote_port)));
488 }
489
490
491 Datum
492 pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
493 {
494         PgStat_StatDBEntry *dbentry;
495         Oid                     dbid;
496         int32           result;
497
498         dbid = PG_GETARG_OID(0);
499
500         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
501                 result = 0;
502         else
503                 result = (int32) (dbentry->n_backends);
504
505         PG_RETURN_INT32(result);
506 }
507
508
509 Datum
510 pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS)
511 {
512         PgStat_StatDBEntry *dbentry;
513         Oid                     dbid;
514         int64           result;
515
516         dbid = PG_GETARG_OID(0);
517
518         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
519                 result = 0;
520         else
521                 result = (int64) (dbentry->n_xact_commit);
522
523         PG_RETURN_INT64(result);
524 }
525
526
527 Datum
528 pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)
529 {
530         PgStat_StatDBEntry *dbentry;
531         Oid                     dbid;
532         int64           result;
533
534         dbid = PG_GETARG_OID(0);
535
536         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
537                 result = 0;
538         else
539                 result = (int64) (dbentry->n_xact_rollback);
540
541         PG_RETURN_INT64(result);
542 }
543
544
545 Datum
546 pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)
547 {
548         PgStat_StatDBEntry *dbentry;
549         Oid                     dbid;
550         int64           result;
551
552         dbid = PG_GETARG_OID(0);
553
554         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
555                 result = 0;
556         else
557                 result = (int64) (dbentry->n_blocks_fetched);
558
559         PG_RETURN_INT64(result);
560 }
561
562
563 Datum
564 pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)
565 {
566         PgStat_StatDBEntry *dbentry;
567         Oid                     dbid;
568         int64           result;
569
570         dbid = PG_GETARG_OID(0);
571
572         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
573                 result = 0;
574         else
575                 result = (int64) (dbentry->n_blocks_hit);
576
577         PG_RETURN_INT64(result);
578 }