@@ -524,137 +524,75 @@ pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
524
524
}
525
525
}
526
526
527
+ /*
528
+ * Returns activity of PG backends.
529
+ */
527
530
Datum
528
531
pg_stat_get_activity (PG_FUNCTION_ARGS )
529
532
{
530
- FuncCallContext * funcctx ;
531
-
532
- if (SRF_IS_FIRSTCALL ())
533
- {
534
- MemoryContext oldcontext ;
535
- TupleDesc tupdesc ;
536
-
537
- funcctx = SRF_FIRSTCALL_INIT ();
538
-
539
- oldcontext = MemoryContextSwitchTo (funcctx -> multi_call_memory_ctx );
540
-
541
- tupdesc = CreateTemplateTupleDesc (22 , false);
542
- TupleDescInitEntry (tupdesc , (AttrNumber )1 ,"datid" ,
543
- OIDOID ,-1 ,0 );
544
- TupleDescInitEntry (tupdesc , (AttrNumber )2 ,"pid" ,
545
- INT4OID ,-1 ,0 );
546
- TupleDescInitEntry (tupdesc , (AttrNumber )3 ,"usesysid" ,
547
- OIDOID ,-1 ,0 );
548
- TupleDescInitEntry (tupdesc , (AttrNumber )4 ,"application_name" ,
549
- TEXTOID ,-1 ,0 );
550
- TupleDescInitEntry (tupdesc , (AttrNumber )5 ,"state" ,
551
- TEXTOID ,-1 ,0 );
552
- TupleDescInitEntry (tupdesc , (AttrNumber )6 ,"query" ,
553
- TEXTOID ,-1 ,0 );
554
- TupleDescInitEntry (tupdesc , (AttrNumber )7 ,"waiting" ,
555
- BOOLOID ,-1 ,0 );
556
- TupleDescInitEntry (tupdesc , (AttrNumber )8 ,"act_start" ,
557
- TIMESTAMPTZOID ,-1 ,0 );
558
- TupleDescInitEntry (tupdesc , (AttrNumber )9 ,"query_start" ,
559
- TIMESTAMPTZOID ,-1 ,0 );
560
- TupleDescInitEntry (tupdesc , (AttrNumber )10 ,"backend_start" ,
561
- TIMESTAMPTZOID ,-1 ,0 );
562
- TupleDescInitEntry (tupdesc , (AttrNumber )11 ,"state_change" ,
563
- TIMESTAMPTZOID ,-1 ,0 );
564
- TupleDescInitEntry (tupdesc , (AttrNumber )12 ,"client_addr" ,
565
- INETOID ,-1 ,0 );
566
- TupleDescInitEntry (tupdesc , (AttrNumber )13 ,"client_hostname" ,
567
- TEXTOID ,-1 ,0 );
568
- TupleDescInitEntry (tupdesc , (AttrNumber )14 ,"client_port" ,
569
- INT4OID ,-1 ,0 );
570
- TupleDescInitEntry (tupdesc , (AttrNumber )15 ,"backend_xid" ,
571
- XIDOID ,-1 ,0 );
572
- TupleDescInitEntry (tupdesc , (AttrNumber )16 ,"backend_xmin" ,
573
- XIDOID ,-1 ,0 );
574
- TupleDescInitEntry (tupdesc , (AttrNumber )17 ,"ssl" ,
575
- BOOLOID ,-1 ,0 );
576
- TupleDescInitEntry (tupdesc , (AttrNumber )18 ,"sslversion" ,
577
- TEXTOID ,-1 ,0 );
578
- TupleDescInitEntry (tupdesc , (AttrNumber )19 ,"sslcipher" ,
579
- TEXTOID ,-1 ,0 );
580
- TupleDescInitEntry (tupdesc , (AttrNumber )20 ,"sslbits" ,
581
- INT4OID ,-1 ,0 );
582
- TupleDescInitEntry (tupdesc , (AttrNumber )21 ,"sslcompression" ,
583
- BOOLOID ,-1 ,0 );
584
- TupleDescInitEntry (tupdesc , (AttrNumber )22 ,"sslclientdn" ,
585
- TEXTOID ,-1 ,0 );
586
-
587
- funcctx -> tuple_desc = BlessTupleDesc (tupdesc );
588
-
589
- funcctx -> user_fctx = palloc0 (sizeof (int ));
590
- if (PG_ARGISNULL (0 ))
591
- {
592
- /* Get all backends */
593
- funcctx -> max_calls = pgstat_fetch_stat_numbackends ();
594
- }
595
- else
596
- {
597
- /*
598
- * Get one backend - locate by pid.
599
- *
600
- * We lookup the backend early, so we can return zero rows if it
601
- * doesn't exist, instead of returning a single row full of NULLs.
602
- */
603
- int pid = PG_GETARG_INT32 (0 );
604
- int i ;
605
- int n = pgstat_fetch_stat_numbackends ();
606
-
607
- for (i = 1 ;i <=n ;i ++ )
608
- {
609
- PgBackendStatus * be = pgstat_fetch_stat_beentry (i );
610
-
611
- if (be )
612
- {
613
- if (be -> st_procpid == pid )
614
- {
615
- * (int * ) (funcctx -> user_fctx )= i ;
616
- break ;
617
- }
618
- }
619
- }
620
-
621
- if (* (int * ) (funcctx -> user_fctx )== 0 )
622
- /* Pid not found, return zero rows */
623
- funcctx -> max_calls = 0 ;
624
- else
625
- funcctx -> max_calls = 1 ;
626
- }
627
-
628
- MemoryContextSwitchTo (oldcontext );
629
- }
630
-
631
- /* stuff done on every call of the function */
632
- funcctx = SRF_PERCALL_SETUP ();
633
-
634
- if (funcctx -> call_cntr < funcctx -> max_calls )
533
+ #define PG_STAT_GET_ACTIVITY_COLS 22
534
+ int num_backends = pgstat_fetch_stat_numbackends ();
535
+ int curr_backend ;
536
+ int pid = PG_ARGISNULL (0 ) ?-1 :PG_GETARG_INT32 (0 );
537
+ ReturnSetInfo * rsinfo = (ReturnSetInfo * )fcinfo -> resultinfo ;
538
+ TupleDesc tupdesc ;
539
+ Tuplestorestate * tupstore ;
540
+ MemoryContext per_query_ctx ;
541
+ MemoryContext oldcontext ;
542
+
543
+ /* check to see if caller supports us returning a tuplestore */
544
+ if (rsinfo == NULL || !IsA (rsinfo ,ReturnSetInfo ))
545
+ ereport (ERROR ,
546
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
547
+ errmsg ("set-valued function called in context that cannot accept a set" )));
548
+ if (!(rsinfo -> allowedModes & SFRM_Materialize ))
549
+ ereport (ERROR ,
550
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
551
+ errmsg ("materialize mode required, but it is not " \
552
+ "allowed in this context" )));
553
+
554
+ /* Build a tuple descriptor for our result type */
555
+ if (get_call_result_type (fcinfo ,NULL ,& tupdesc )!= TYPEFUNC_COMPOSITE )
556
+ elog (ERROR ,"return type must be a row type" );
557
+
558
+ per_query_ctx = rsinfo -> econtext -> ecxt_per_query_memory ;
559
+ oldcontext = MemoryContextSwitchTo (per_query_ctx );
560
+
561
+ tupstore = tuplestore_begin_heap (true, false,work_mem );
562
+ rsinfo -> returnMode = SFRM_Materialize ;
563
+ rsinfo -> setResult = tupstore ;
564
+ rsinfo -> setDesc = tupdesc ;
565
+
566
+ MemoryContextSwitchTo (oldcontext );
567
+
568
+ /* 1-based index */
569
+ for (curr_backend = 1 ;curr_backend <=num_backends ;curr_backend ++ )
635
570
{
636
571
/* for each row */
637
- Datum values [22 ];
638
- bool nulls [22 ];
639
- HeapTuple tuple ;
572
+ Datum values [PG_STAT_GET_ACTIVITY_COLS ];
573
+ bool nulls [PG_STAT_GET_ACTIVITY_COLS ];
640
574
LocalPgBackendStatus * local_beentry ;
641
575
PgBackendStatus * beentry ;
642
576
643
577
MemSet (values ,0 ,sizeof (values ));
644
578
MemSet (nulls ,0 ,sizeof (nulls ));
645
579
646
- if (* (int * ) (funcctx -> user_fctx )> 0 )
647
- {
648
- /* Get specific pid slot */
649
- local_beentry = pgstat_fetch_stat_local_beentry (* (int * ) (funcctx -> user_fctx ));
650
- beentry = & local_beentry -> backendStatus ;
651
- }
652
- else
580
+ if (pid != -1 )
653
581
{
654
- /* Get the next one in the list */
655
- local_beentry = pgstat_fetch_stat_local_beentry (funcctx -> call_cntr + 1 );/* 1-based index */
656
- beentry = & local_beentry -> backendStatus ;
582
+ /* Skip any which are not the one we're looking for. */
583
+ PgBackendStatus * be = pgstat_fetch_stat_beentry (curr_backend );
584
+
585
+ if (!be || be -> st_procpid != pid )
586
+ continue ;
587
+
657
588
}
589
+
590
+ /* Get the next one in the list */
591
+ local_beentry = pgstat_fetch_stat_local_beentry (curr_backend );
592
+ if (!local_beentry )
593
+ continue ;
594
+
595
+ beentry = & local_beentry -> backendStatus ;
658
596
if (!beentry )
659
597
{
660
598
int i ;
@@ -665,8 +603,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
665
603
nulls [5 ]= false;
666
604
values [5 ]= CStringGetTextDatum ("<backend information not available>" );
667
605
668
- tuple = heap_form_tuple ( funcctx -> tuple_desc ,values ,nulls );
669
- SRF_RETURN_NEXT ( funcctx , HeapTupleGetDatum ( tuple )) ;
606
+ tuplestore_putvalues ( tupstore , tupdesc ,values ,nulls );
607
+ continue ;
670
608
}
671
609
672
610
/* Values available to all callers */
@@ -839,15 +777,17 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
839
777
nulls [13 ]= true;
840
778
}
841
779
842
- tuple = heap_form_tuple ( funcctx -> tuple_desc ,values ,nulls );
780
+ tuplestore_putvalues ( tupstore , tupdesc ,values ,nulls );
843
781
844
- SRF_RETURN_NEXT (funcctx ,HeapTupleGetDatum (tuple ));
845
- }
846
- else
847
- {
848
- /* nothing left */
849
- SRF_RETURN_DONE (funcctx );
782
+ /* If only a single backend was requested, and we found it, break. */
783
+ if (pid != -1 )
784
+ break ;
850
785
}
786
+
787
+ /* clean up and return the tuplestore */
788
+ tuplestore_donestoring (tupstore );
789
+
790
+ return (Datum )0 ;
851
791
}
852
792
853
793