8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.49 2008/03/25 22:42:44 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.50 2008/05/07 14:41:55 mha Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
17
17
#include "funcapi.h"
18
18
#include "miscadmin.h"
19
19
#include "pgstat.h"
20
+ #include "catalog/pg_type.h"
21
+ #include "access/heapam.h"
20
22
#include "utils/builtins.h"
21
23
#include "utils/inet.h"
22
24
#include "libpq/ip.h"
@@ -39,6 +41,7 @@ extern Datum pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS);
39
41
extern Datum pg_stat_get_last_autoanalyze_time (PG_FUNCTION_ARGS );
40
42
41
43
extern Datum pg_stat_get_backend_idset (PG_FUNCTION_ARGS );
44
+ extern Datum pg_stat_get_activity (PG_FUNCTION_ARGS );
42
45
extern Datum pg_backend_pid (PG_FUNCTION_ARGS );
43
46
extern Datum pg_stat_get_backend_pid (PG_FUNCTION_ARGS );
44
47
extern Datum pg_stat_get_backend_dbid (PG_FUNCTION_ARGS );
@@ -363,6 +366,225 @@ pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
363
366
}
364
367
}
365
368
369
+ Datum
370
+ pg_stat_get_activity (PG_FUNCTION_ARGS )
371
+ {
372
+ FuncCallContext * funcctx ;
373
+
374
+ if (SRF_IS_FIRSTCALL ())
375
+ {
376
+ MemoryContext oldcontext ;
377
+ TupleDesc tupdesc ;
378
+
379
+ funcctx = SRF_FIRSTCALL_INIT ();
380
+
381
+ oldcontext = MemoryContextSwitchTo (funcctx -> multi_call_memory_ctx );
382
+
383
+ tupdesc = CreateTemplateTupleDesc (10 , false);
384
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 1 , "datid" , OIDOID , -1 , 0 );
385
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 2 , "procpid" , INT4OID , -1 , 0 );
386
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 3 , "usesysid" , OIDOID , -1 , 0 );
387
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 4 , "current_query" , TEXTOID , -1 , 0 );
388
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 5 , "waiting" , BOOLOID , -1 , 0 );
389
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 6 , "act_start" , TIMESTAMPTZOID , -1 , 0 );
390
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 7 , "query_start" , TIMESTAMPTZOID , -1 , 0 );
391
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 8 , "backend_start" , TIMESTAMPTZOID , -1 , 0 );
392
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 9 , "client_addr" , INETOID , -1 , 0 );
393
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 10 , "client_port" , INT4OID , -1 , 0 );
394
+
395
+ funcctx -> tuple_desc = BlessTupleDesc (tupdesc );
396
+
397
+ funcctx -> user_fctx = palloc0 (sizeof (int ));
398
+ if (PG_ARGISNULL (0 ))
399
+ {
400
+ /* Get all backends */
401
+ funcctx -> max_calls = pgstat_fetch_stat_numbackends ();
402
+ }
403
+ else
404
+ {
405
+ /*
406
+ * Get one backend - locate by pid.
407
+ *
408
+ * We lookup the backend early, so we can return zero rows if it doesn't
409
+ * exist, instead of returning a single row full of NULLs.
410
+ */
411
+ int pid = PG_GETARG_INT32 (0 );
412
+ int i ;
413
+ int n = pgstat_fetch_stat_numbackends ();
414
+
415
+ for (i = 1 ; i <= n ; i ++ )
416
+ {
417
+ PgBackendStatus * be = pgstat_fetch_stat_beentry (i );
418
+ if (be )
419
+ {
420
+ if (be -> st_procpid == pid )
421
+ {
422
+ * (int * )(funcctx -> user_fctx ) = i ;
423
+ break ;
424
+ }
425
+ }
426
+ }
427
+
428
+ if (* (int * )(funcctx -> user_fctx ) == 0 )
429
+ /* Pid not found, return zero rows */
430
+ funcctx -> max_calls = 0 ;
431
+ else
432
+ funcctx -> max_calls = 1 ;
433
+ }
434
+
435
+ MemoryContextSwitchTo (oldcontext );
436
+ }
437
+
438
+ /* stuff done on every call of the function */
439
+ funcctx = SRF_PERCALL_SETUP ();
440
+
441
+ if (funcctx -> call_cntr < funcctx -> max_calls )
442
+ {
443
+ /* for each row */
444
+ Datum values [10 ];
445
+ bool nulls [10 ];
446
+ HeapTuple tuple ;
447
+ PgBackendStatus * beentry ;
448
+ SockAddr zero_clientaddr ;
449
+
450
+ MemSet (values , 0 , sizeof (values ));
451
+ MemSet (nulls , 0 , sizeof (nulls ));
452
+
453
+ if (* (int * )(funcctx -> user_fctx ) > 0 )
454
+ /* Get specific pid slot */
455
+ beentry = pgstat_fetch_stat_beentry (* (int * )(funcctx -> user_fctx ));
456
+ else
457
+ /* Get the next one in the list */
458
+ beentry = pgstat_fetch_stat_beentry (funcctx -> call_cntr + 1 ); /* 1-based index */
459
+ if (!beentry )
460
+ {
461
+ int i ;
462
+
463
+ for (i = 0 ; i < sizeof (nulls )/sizeof (nulls [0 ]); i ++ )
464
+ nulls [i ] = true;
465
+
466
+ nulls [3 ] = false;
467
+ values [3 ] = CStringGetTextDatum ("<backend information not available>" );
468
+
469
+ tuple = heap_form_tuple (funcctx -> tuple_desc , values , nulls );
470
+ SRF_RETURN_NEXT (funcctx , HeapTupleGetDatum (tuple ));
471
+ }
472
+
473
+ /* Values available to all callers */
474
+ values [0 ] = ObjectIdGetDatum (beentry -> st_databaseid );
475
+ values [1 ] = Int32GetDatum (beentry -> st_procpid );
476
+ values [2 ] = ObjectIdGetDatum (beentry -> st_userid );
477
+
478
+ /* Values only available to same user or superuser */
479
+ if (superuser () || beentry -> st_userid == GetUserId ())
480
+ {
481
+ if (* (beentry -> st_activity ) == '\0' )
482
+ {
483
+ values [3 ] = CStringGetTextDatum ("<command string not enabled>" );
484
+ }
485
+ else
486
+ {
487
+ values [3 ] = CStringGetTextDatum (beentry -> st_activity );
488
+ }
489
+
490
+ values [4 ] = BoolGetDatum (beentry -> st_waiting );
491
+
492
+ if (beentry -> st_xact_start_timestamp != 0 )
493
+ values [5 ] = TimestampTzGetDatum (beentry -> st_xact_start_timestamp );
494
+ else
495
+ nulls [5 ] = true;
496
+
497
+ if (beentry -> st_activity_start_timestamp != 0 )
498
+ values [6 ] = TimestampTzGetDatum (beentry -> st_activity_start_timestamp );
499
+ else
500
+ nulls [6 ] = true;
501
+
502
+ if (beentry -> st_proc_start_timestamp != 0 )
503
+ values [7 ] = TimestampTzGetDatum (beentry -> st_proc_start_timestamp );
504
+ else
505
+ nulls [7 ] = true;
506
+
507
+ /* A zeroed client addr means we don't know */
508
+ memset (& zero_clientaddr , 0 , sizeof (zero_clientaddr ));
509
+ if (memcmp (& (beentry -> st_clientaddr ), & zero_clientaddr ,
510
+ sizeof (zero_clientaddr ) == 0 ))
511
+ {
512
+ nulls [8 ] = true;
513
+ nulls [9 ] = true;
514
+ }
515
+ else
516
+ {
517
+ if (beentry -> st_clientaddr .addr .ss_family == AF_INET
518
+ #ifdef HAVE_IPV6
519
+ || beentry -> st_clientaddr .addr .ss_family == AF_INET6
520
+ #endif
521
+ )
522
+ {
523
+ char remote_host [NI_MAXHOST ];
524
+ char remote_port [NI_MAXSERV ];
525
+ int ret ;
526
+
527
+ remote_host [0 ] = '\0' ;
528
+ remote_port [0 ] = '\0' ;
529
+ ret = pg_getnameinfo_all (& beentry -> st_clientaddr .addr ,
530
+ beentry -> st_clientaddr .salen ,
531
+ remote_host , sizeof (remote_host ),
532
+ remote_port , sizeof (remote_port ),
533
+ NI_NUMERICHOST | NI_NUMERICSERV );
534
+ if (ret )
535
+ {
536
+ nulls [8 ] = true;
537
+ nulls [9 ] = true;
538
+ }
539
+ else
540
+ {
541
+ clean_ipv6_addr (beentry -> st_clientaddr .addr .ss_family , remote_host );
542
+ values [8 ] = DirectFunctionCall1 (inet_in ,
543
+ CStringGetDatum (remote_host ));
544
+ values [9 ] = Int32GetDatum (atoi (remote_port ));
545
+ }
546
+ }
547
+ else if (beentry -> st_clientaddr .addr .ss_family == AF_UNIX )
548
+ {
549
+ /*
550
+ * Unix sockets always reports NULL for host and -1 for port, so it's
551
+ * possible to tell the difference to connections we have no
552
+ * permissions to view, or with errors.
553
+ */
554
+ nulls [8 ] = true;
555
+ values [9 ] = DatumGetInt32 (-1 );
556
+ }
557
+ else
558
+ {
559
+ /* Unknown address type, should never happen */
560
+ nulls [8 ] = true;
561
+ nulls [9 ] = true;
562
+ }
563
+ }
564
+ }
565
+ else
566
+ {
567
+ /* No permissions to view data about this session */
568
+ values [3 ] = CStringGetTextDatum ("<insufficient privilege>" );
569
+ nulls [4 ] = true;
570
+ nulls [5 ] = true;
571
+ nulls [6 ] = true;
572
+ nulls [7 ] = true;
573
+ nulls [8 ] = true;
574
+ nulls [9 ] = true;
575
+ }
576
+
577
+ tuple = heap_form_tuple (funcctx -> tuple_desc , values , nulls );
578
+
579
+ SRF_RETURN_NEXT (funcctx , HeapTupleGetDatum (tuple ));
580
+ }
581
+ else
582
+ {
583
+ /* nothing left */
584
+ SRF_RETURN_DONE (funcctx );
585
+ }
586
+ }
587
+
366
588
367
589
Datum
368
590
pg_backend_pid (PG_FUNCTION_ARGS )
0 commit comments