66#include "utils/jsonb.h"
77#include "utils/guc.h"
88#include "commands/explain.h"
9- #if PG_MAJORVERSION_NUM >= 18
10- #include "commands/explain_state.h"
11- #include "commands/explain_format.h"
12- #endif
139#include "storage/ipc.h"
1410#include "storage/proc.h"
1511
@@ -33,13 +29,12 @@ static UprobeList *uprobesList = NULL;
3329
3430static MemoryContext traceMemoryContext = NULL ;
3531
32+ /* We need it in case that ListAdd fails and we need to delete this uprobe */
3633static volatile Uprobe * lastSetUprobe = NULL ;
3734
38- /* we need it in case that ListAdd fails and we need to delete this uprobe */
39-
4035static ExecutorRun_hook_type prev_ExecutorRun_hook = NULL ;
41-
4236static ExecutorStart_hook_type prev_ExecutorStart_hook = NULL ;
37+ static ExecutorFinish_hook_type prev_ExecutorFinish_hook = NULL ;
4338
4439bool isExecuteTime = false;
4540
@@ -68,6 +63,7 @@ static void TraceSessionExecutorRun(QueryDesc *queryDesc,
6863 bool execute_once );
6964#endif
7065static void TraceSessionExecutorStart (QueryDesc * queryDesc , int eflags );
66+ static void TraceSessionExecutorFinish (QueryDesc * queryDesc );
7167static char * ProcessDescBeforeExec (QueryDesc * queryDesc );
7268
7369static UprobeList * MakeNodesPlanStringsText (char * startPlanExplain , char * endPlanExplain );
@@ -291,6 +287,8 @@ SessionTraceStart(void)
291287 ExecutorRun_hook = TraceSessionExecutorRun ;
292288 prev_ExecutorStart_hook = ExecutorStart_hook ;
293289 ExecutorStart_hook = TraceSessionExecutorStart ;
290+ prev_ExecutorFinish_hook = ExecutorFinish_hook ;
291+ ExecutorFinish_hook = TraceSessionExecutorFinish ;
294292 }
295293 PG_CATCH ();
296294 {
@@ -548,6 +546,62 @@ TraceSessionExecutorStart(QueryDesc *queryDesc, int eflags)
548546}
549547
550548
549+ static void
550+ TraceSessionExecutorFinish (QueryDesc * queryDesc )
551+ {
552+ char * planCopy ;
553+ struct timespec time ;
554+ uint64 executionStarted ;
555+
556+ /*No Executor nodes will be called, so no need for additional set up*/
557+ if (queryDesc -> estate -> es_auxmodifytables == NULL )
558+ {
559+ if (prev_ExecutorFinish_hook )
560+ (* prev_ExecutorFinish_hook ) (queryDesc );
561+ else
562+ standard_ExecutorFinish (queryDesc );
563+ return ;
564+ }
565+
566+ if (writeMode == JSON_WRITE_MODE && !isFirstNodeCall )
567+ {
568+ TracePrintf (",\n" );
569+ }
570+
571+ planCopy = BeforeExecution (queryDesc );
572+
573+ clock_gettime (CLOCKTYPE , & time );
574+ executionStarted = time .tv_sec * 1000000000L + time .tv_nsec ;
575+
576+ ExecutorRunNestLevel ++ ;
577+
578+ PG_TRY ();
579+ {
580+ if (prev_ExecutorFinish_hook )
581+ (* prev_ExecutorFinish_hook ) (queryDesc );
582+ else
583+ standard_ExecutorFinish (queryDesc );
584+ }
585+ PG_FINALLY ();
586+ {
587+ uint64 timeDiff ;
588+
589+ ExecutorRunNestLevel -- ;
590+
591+ clock_gettime (CLOCKTYPE , & time );
592+ timeDiff = time .tv_sec * 1000000000L + time .tv_nsec - executionStarted ;
593+ if (writeMode == TEXT_WRITE_MODE )
594+ TracePrintf ("TRACE. Execution finished for %lu nanosec\n" , timeDiff );
595+ else
596+ TracePrintf ("\n],\n\"executionTime\": \"%lu nanosec\"\n" , timeDiff );
597+
598+ AfterExecution (queryDesc , planCopy );
599+ isFirstNodeCall = false;
600+ }
601+ PG_END_TRY ();
602+ }
603+
604+
551605/* find the plan field in explain jsonb */
552606static JsonbValue *
553607FindField (JsonbValue * json , char * field , size_t len )
0 commit comments