@@ -524,137 +524,75 @@ pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
524524 }
525525}
526526
527+ /*
528+ * Returns activity of PG backends.
529+ */
527530Datum
528531pg_stat_get_activity (PG_FUNCTION_ARGS )
529532{
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 ++ )
635570 {
636571 /* 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 ];
640574 LocalPgBackendStatus * local_beentry ;
641575 PgBackendStatus * beentry ;
642576
643577 MemSet (values , 0 , sizeof (values ));
644578 MemSet (nulls , 0 , sizeof (nulls ));
645579
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 )
653581 {
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+
657588 }
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 ;
658596 if (!beentry )
659597 {
660598 int i ;
@@ -665,8 +603,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
665603 nulls [5 ] = false;
666604 values [5 ] = CStringGetTextDatum ("<backend information not available>" );
667605
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 ;
670608 }
671609
672610 /* Values available to all callers */
@@ -839,15 +777,17 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
839777 nulls [13 ] = true;
840778 }
841779
842- tuple = heap_form_tuple ( funcctx -> tuple_desc , values , nulls );
780+ tuplestore_putvalues ( tupstore , tupdesc , values , nulls );
843781
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 ;
850785 }
786+
787+ /* clean up and return the tuplestore */
788+ tuplestore_donestoring (tupstore );
789+
790+ return (Datum ) 0 ;
851791}
852792
853793
0 commit comments