88#include "commands/explain.h"
99#include "storage/ipc.h"
1010#include "storage/proc.h"
11-
11+ #include "tcop/utility.h"
1212#include "trace_parsing.h"
1313#include "uprobe_internal.h"
1414#include "trace_lock_on_buffers.h"
@@ -35,6 +35,7 @@ static volatile Uprobe *lastSetUprobe = NULL;
3535static ExecutorRun_hook_type prev_ExecutorRun_hook = NULL ;
3636static ExecutorStart_hook_type prev_ExecutorStart_hook = NULL ;
3737static ExecutorFinish_hook_type prev_ExecutorFinish_hook = NULL ;
38+ static ProcessUtility_hook_type prev_ProcessUtility_hook = NULL ;
3839
3940bool isExecuteTime = false;
4041
@@ -62,6 +63,14 @@ static void TraceSessionExecutorRun(QueryDesc *queryDesc,
6263 uint64 count ,
6364 bool execute_once );
6465#endif
66+ static void TraceSessionExecutorProcessUtility (PlannedStmt * pstmt ,
67+ const char * queryString ,
68+ bool readOnlyTree ,
69+ ProcessUtilityContext context ,
70+ ParamListInfo params ,
71+ QueryEnvironment * queryEnv ,
72+ DestReceiver * dest ,
73+ QueryCompletion * qc );
6574static void TraceSessionExecutorStart (QueryDesc * queryDesc , int eflags );
6675static void TraceSessionExecutorFinish (QueryDesc * queryDesc );
6776static char * ProcessDescBeforeExec (QueryDesc * queryDesc );
@@ -289,6 +298,8 @@ SessionTraceStart(void)
289298 ExecutorStart_hook = TraceSessionExecutorStart ;
290299 prev_ExecutorFinish_hook = ExecutorFinish_hook ;
291300 ExecutorFinish_hook = TraceSessionExecutorFinish ;
301+ prev_ProcessUtility_hook = ProcessUtility_hook ;
302+ ProcessUtility_hook = TraceSessionExecutorProcessUtility ;
292303 }
293304 PG_CATCH ();
294305 {
@@ -464,6 +475,27 @@ ProcessDescBeforeExec(QueryDesc *queryDesc)
464475 return planCopy ;
465476}
466477
478+ static void
479+ CallOriginalExecutorFinish (PlannedStmt * pstmt ,
480+ const char * queryString ,
481+ bool readOnlyTree ,
482+ ProcessUtilityContext context ,
483+ ParamListInfo params ,
484+ QueryEnvironment * queryEnv ,
485+ DestReceiver * dest ,
486+ QueryCompletion * qc )
487+ {
488+ if (prev_ProcessUtility_hook )
489+ (* prev_ProcessUtility_hook ) (pstmt , queryString , readOnlyTree ,
490+ context , params , queryEnv ,
491+ dest , qc );
492+ else
493+ standard_ProcessUtility (pstmt , queryString , readOnlyTree ,
494+ context , params , queryEnv ,
495+ dest , qc );
496+ }
497+
498+
467499#if PG_MAJORVERSION_NUM >= 18
468500static void
469501TraceSessionExecutorRun (QueryDesc * queryDesc , ScanDirection direction , uint64 count )
@@ -601,6 +633,82 @@ TraceSessionExecutorFinish(QueryDesc *queryDesc)
601633 PG_END_TRY ();
602634}
603635
636+ static void
637+ TraceSessionExecutorProcessUtility (PlannedStmt * pstmt ,
638+ const char * queryString ,
639+ bool readOnlyTree ,
640+ ProcessUtilityContext context ,
641+ ParamListInfo params ,
642+ QueryEnvironment * queryEnv ,
643+ DestReceiver * dest ,
644+ QueryCompletion * qc )
645+ {
646+ char * planCopy ;
647+ struct timespec time ;
648+ uint64 executionStarted ;
649+ FetchStmt * fetch ;
650+ Portal portal ;
651+ QueryDesc * queryDesc ;
652+
653+ if (nodeTag (pstmt -> utilityStmt ) != T_FetchStmt )
654+ {
655+ CallOriginalExecutorFinish (pstmt , queryString , readOnlyTree ,
656+ context , params , queryEnv ,
657+ dest , qc );
658+
659+ return ;
660+ }
661+
662+ fetch = (FetchStmt * ) pstmt -> utilityStmt ;
663+ portal = GetPortalByName (fetch -> portalname );
664+
665+ if (!PortalIsValid (portal ))
666+ {
667+ CallOriginalExecutorFinish (pstmt , queryString , readOnlyTree ,
668+ context , params , queryEnv ,
669+ dest , qc );
670+ return ;
671+ }
672+
673+ queryDesc = portal -> queryDesc ;
674+
675+ if (writeMode == JSON_WRITE_MODE && !isFirstNodeCall )
676+ {
677+ TracePrintf (",\n" );
678+ }
679+
680+ planCopy = BeforeExecution (queryDesc );
681+
682+ clock_gettime (CLOCKTYPE , & time );
683+ executionStarted = time .tv_sec * 1000000000L + time .tv_nsec ;
684+
685+ ExecutorRunNestLevel ++ ;
686+
687+ PG_TRY ();
688+ {
689+ CallOriginalExecutorFinish (pstmt , queryString , readOnlyTree ,
690+ context , params , queryEnv ,
691+ dest , qc );
692+ }
693+ PG_FINALLY ();
694+ {
695+ uint64 timeDiff ;
696+
697+ ExecutorRunNestLevel -- ;
698+
699+ clock_gettime (CLOCKTYPE , & time );
700+ timeDiff = time .tv_sec * 1000000000L + time .tv_nsec - executionStarted ;
701+ if (writeMode == TEXT_WRITE_MODE )
702+ TracePrintf ("TRACE. Execution finished for %lu nanosec\n" , timeDiff );
703+ else
704+ TracePrintf ("\n],\n\"executionTime\": \"%lu nanosec\"\n" , timeDiff );
705+
706+ AfterExecution (queryDesc , planCopy );
707+ isFirstNodeCall = false;
708+ }
709+ PG_END_TRY ();
710+ }
711+
604712
605713/* find the plan field in explain jsonb */
606714static JsonbValue *
0 commit comments