]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/pgstatfuncs.c
Clean up the rather historically encumbered interface to now() and
[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-2005, 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.24 2005/06/29 22:51:56 tgl 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
358          * the 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         int32       beid;
393         char            remote_host[NI_MAXHOST];
394         int                     ret;
395
396         beid = PG_GETARG_INT32(0);
397
398         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
399                 PG_RETURN_NULL();
400
401         /* Not initialized yet? */
402         if (!OidIsValid(beentry->userid))
403                 PG_RETURN_NULL();
404
405         if (!superuser() && beentry->userid != GetUserId())
406                 PG_RETURN_NULL();
407
408         switch (beentry->clientaddr.addr.ss_family)
409         {
410                 case AF_INET:
411 #ifdef HAVE_IPV6
412                 case AF_INET6:
413 #endif
414                         break;
415                 default:
416                         PG_RETURN_NULL();
417         }
418
419         remote_host[0] = '\0';
420         ret = getnameinfo_all(&beentry->clientaddr.addr, beentry->clientaddr.salen,
421                                                   remote_host, sizeof(remote_host),
422                                                   NULL, 0,
423                                                   NI_NUMERICHOST | NI_NUMERICSERV);
424         if (ret)
425                 PG_RETURN_NULL();
426
427         PG_RETURN_INET_P(DirectFunctionCall1(inet_in,
428                                                                                  CStringGetDatum(remote_host)));
429 }
430
431 Datum
432 pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
433 {
434         PgStat_StatBeEntry *beentry;
435         int32       beid;
436         char            remote_port[NI_MAXSERV];
437         int                     ret;
438
439         beid = PG_GETARG_INT32(0);
440
441         if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
442                 PG_RETURN_NULL();
443
444         /* Not initialized yet? */
445         if (!OidIsValid(beentry->userid))
446                 PG_RETURN_NULL();
447
448         if (!superuser() && beentry->userid != GetUserId())
449                 PG_RETURN_NULL();
450
451         switch (beentry->clientaddr.addr.ss_family)
452         {
453                 case AF_INET:
454 #ifdef HAVE_IPV6
455                 case AF_INET6:
456 #endif
457                         break;
458                 case AF_UNIX:
459                         PG_RETURN_INT32(-1);
460                 default:
461                         PG_RETURN_NULL();
462         }
463
464         remote_port[0] = '\0';
465         ret = getnameinfo_all(&beentry->clientaddr.addr,
466                                                   beentry->clientaddr.salen,
467                                                   NULL, 0,
468                                                   remote_port, sizeof(remote_port),
469                                                   NI_NUMERICHOST | NI_NUMERICSERV);
470         if (ret)
471                 PG_RETURN_NULL();
472
473         PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(remote_port)));
474 }
475
476
477 Datum
478 pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
479 {
480         PgStat_StatDBEntry *dbentry;
481         Oid                     dbid;
482         int32           result;
483
484         dbid = PG_GETARG_OID(0);
485
486         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
487                 result = 0;
488         else
489                 result = (int32) (dbentry->n_backends);
490
491         PG_RETURN_INT32(result);
492 }
493
494
495 Datum
496 pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS)
497 {
498         PgStat_StatDBEntry *dbentry;
499         Oid                     dbid;
500         int64           result;
501
502         dbid = PG_GETARG_OID(0);
503
504         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
505                 result = 0;
506         else
507                 result = (int64) (dbentry->n_xact_commit);
508
509         PG_RETURN_INT64(result);
510 }
511
512
513 Datum
514 pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)
515 {
516         PgStat_StatDBEntry *dbentry;
517         Oid                     dbid;
518         int64           result;
519
520         dbid = PG_GETARG_OID(0);
521
522         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
523                 result = 0;
524         else
525                 result = (int64) (dbentry->n_xact_rollback);
526
527         PG_RETURN_INT64(result);
528 }
529
530
531 Datum
532 pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)
533 {
534         PgStat_StatDBEntry *dbentry;
535         Oid                     dbid;
536         int64           result;
537
538         dbid = PG_GETARG_OID(0);
539
540         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
541                 result = 0;
542         else
543                 result = (int64) (dbentry->n_blocks_fetched);
544
545         PG_RETURN_INT64(result);
546 }
547
548
549 Datum
550 pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)
551 {
552         PgStat_StatDBEntry *dbentry;
553         Oid                     dbid;
554         int64           result;
555
556         dbid = PG_GETARG_OID(0);
557
558         if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
559                 result = 0;
560         else
561                 result = (int64) (dbentry->n_blocks_hit);
562
563         PG_RETURN_INT64(result);
564 }