@@ -253,6 +253,7 @@ string StatusXcp::as_text() const
253253}
254254
255255
256+ static void activate_request (thread_db* tdbb, Request* request, jrd_tra* transaction);
256257static void execute_looper (thread_db*, Request*, jrd_tra*, const StmtNode*, Request::req_s);
257258static void looper_seh (thread_db*, Request*, const StmtNode*);
258259static void release_blobs (thread_db*, Request*);
@@ -262,6 +263,56 @@ static void stuff_stack_trace(const Request*);
262263const size_t MAX_STACK_TRACE = 2048 ;
263264
264265
266+ namespace
267+ {
268+ void forgetSavepoint (thread_db* tdbb, Request* request, jrd_tra* transaction, SavNumber savNumber);
269+ SavNumber startSavepoint (Request* request, jrd_tra* transaction);
270+
271+ void forgetSavepoint (thread_db* tdbb, Request* request, jrd_tra* transaction, SavNumber savNumber)
272+ {
273+ while (transaction->tra_save_point &&
274+ transaction->tra_save_point ->getNumber () >= savNumber)
275+ {
276+ const auto savepoint = transaction->tra_save_point ;
277+ // Forget about any undo for this verb
278+ fb_assert (!transaction->tra_save_point ->isChanging ());
279+ transaction->releaseSavepoint (tdbb);
280+ // Preserve savepoint for reuse
281+ fb_assert (savepoint == transaction->tra_save_free );
282+ transaction->tra_save_free = savepoint->moveToStack (request->req_savepoints );
283+ fb_assert (savepoint != transaction->tra_save_free );
284+
285+ // Ensure that the priorly existing savepoints are preserved,
286+ // e.g. 10-11-12-(5-6-7) where savNumber == 5. This may happen
287+ // due to looper savepoints being reused in subsequent invokations.
288+ if (savepoint->getNumber () == savNumber)
289+ break ;
290+ }
291+ }
292+
293+ SavNumber startSavepoint (Request* request, jrd_tra* transaction)
294+ {
295+ if (!(request->req_flags & req_proc_fetch) && request->req_transaction )
296+ {
297+ if (transaction && !(transaction->tra_flags & TRA_system))
298+ {
299+ if (request->req_savepoints )
300+ {
301+ request->req_savepoints =
302+ request->req_savepoints ->moveToStack (transaction->tra_save_point );
303+ }
304+ else
305+ transaction->startSavepoint ();
306+
307+ return transaction->tra_save_point ->getNumber ();
308+ }
309+ }
310+
311+ return 0 ;
312+ }
313+ } // anonymous namespace
314+
315+
265316// Perform an assignment.
266317void EXE_assignment (thread_db* tdbb, const AssignmentNode* node)
267318{
@@ -850,7 +901,7 @@ void EXE_send(thread_db* tdbb, Request* request, USHORT msg, ULONG length, const
850901
851902
852903// Mark a request as active.
853- void EXE_activate (thread_db* tdbb, Request* request, jrd_tra* transaction)
904+ static void activate_request (thread_db* tdbb, Request* request, jrd_tra* transaction)
854905{
855906 SET_TDBB (tdbb);
856907
@@ -918,10 +969,151 @@ void EXE_activate(thread_db* tdbb, Request* request, jrd_tra* transaction)
918969}
919970
920971
972+ // Execute function. A shortcut for node-based function but required for external functions.
973+ void EXE_execute_function (thread_db* tdbb, Request* request, jrd_tra* transaction,
974+ ULONG inMsgLength, UCHAR* inMsg, ULONG outMsgLength, UCHAR* outMsg)
975+ {
976+ if (const auto function = request->getStatement ()->function ; function && function->fun_external )
977+ {
978+ activate_request (tdbb, request, transaction);
979+
980+ const auto attachment = tdbb->getAttachment ();
981+
982+ // Ensure the cancellation lock can be triggered
983+ const auto lock = attachment->att_cancel_lock ;
984+ if (lock && lock->lck_logical == LCK_none)
985+ LCK_lock (tdbb, lock, LCK_SR, LCK_WAIT);
986+
987+ const SavNumber savNumber = startSavepoint (request, transaction);
988+
989+ if (!request->req_transaction )
990+ ERR_post (Arg::Gds (isc_req_no_trans));
991+
992+ try
993+ {
994+ // Save the old pool and request to restore on exit
995+ StmtNode::ExeState exeState (tdbb, request, request->req_transaction );
996+ Jrd::ContextPoolHolder context (tdbb, request->req_pool );
997+
998+ fb_assert (!request->req_caller );
999+ request->req_caller = exeState.oldRequest ;
1000+
1001+ tdbb->tdbb_flags &= ~(TDBB_stack_trace_done | TDBB_sys_error);
1002+
1003+ // Execute stuff until we drop
1004+
1005+ const auto profilerManager = attachment->isProfilerActive () && !request->hasInternalStatement () ?
1006+ attachment->getProfilerManager (tdbb) : nullptr ;
1007+ const SINT64 profilerInitialTicks = profilerManager ? profilerManager->queryTicks () : 0 ;
1008+ const SINT64 profilerInitialAccumulatedOverhead = profilerManager ?
1009+ profilerManager->getAccumulatedOverhead () : 0 ;
1010+
1011+ try
1012+ {
1013+ function->fun_external ->execute (tdbb, request, transaction, inMsgLength, inMsg, outMsgLength, outMsg);
1014+
1015+ tdbb->checkCancelState ();
1016+ }
1017+ catch (const Exception& ex)
1018+ {
1019+ ex.stuffException (tdbb->tdbb_status_vector );
1020+
1021+ request->adjustCallerStats ();
1022+
1023+ // Ensure the transaction hasn't disappeared in the meantime
1024+ fb_assert (request->req_transaction );
1025+
1026+ // If the database is already bug-checked, then get out
1027+ if (tdbb->getDatabase ()->dbb_flags & DBB_bugcheck)
1028+ status_exception::raise (tdbb->tdbb_status_vector );
1029+
1030+ exeState.errorPending = true ;
1031+
1032+ if (!(tdbb->tdbb_flags & TDBB_stack_trace_done) && !(tdbb->tdbb_flags & TDBB_sys_error))
1033+ {
1034+ stuff_stack_trace (request);
1035+ tdbb->tdbb_flags |= TDBB_stack_trace_done;
1036+ }
1037+ }
1038+
1039+ if (profilerInitialTicks && attachment->isProfilerActive ())
1040+ {
1041+ const SINT64 currentProfilerTicks = profilerManager->queryTicks ();
1042+ const SINT64 elapsedTicks = profilerManager->getElapsedTicksAndAdjustOverhead (
1043+ currentProfilerTicks, profilerInitialTicks, profilerInitialAccumulatedOverhead);
1044+
1045+ request->req_profiler_ticks += elapsedTicks;
1046+ }
1047+
1048+ request->adjustCallerStats ();
1049+
1050+ if (!exeState.errorPending )
1051+ TRA_release_request_snapshot (tdbb, request);
1052+
1053+ request->req_flags &= ~(req_active | req_reserved);
1054+ request->invalidateTimeStamp ();
1055+
1056+ if (profilerInitialTicks && attachment->isProfilerActive ())
1057+ {
1058+ ProfilerManager::Stats stats (request->req_profiler_ticks );
1059+ profilerManager->onRequestFinish (request, stats);
1060+ }
1061+
1062+ fb_assert (request->req_caller == exeState.oldRequest );
1063+ request->req_caller = nullptr ;
1064+
1065+ // Ensure the transaction hasn't disappeared in the meantime
1066+ fb_assert (request->req_transaction );
1067+
1068+ // In the case of a pending error condition (one which did not
1069+ // result in a exception to the top of looper), we need to
1070+ // release the request snapshot
1071+
1072+ if (exeState.errorPending )
1073+ {
1074+ TRA_release_request_snapshot (tdbb, request);
1075+ ERR_punt ();
1076+ }
1077+
1078+ if (request->req_flags & req_abort)
1079+ ERR_post (Arg::Gds (isc_req_sync));
1080+ }
1081+ catch (const Exception&)
1082+ {
1083+ // In the case of error, undo changes performed under our savepoint
1084+
1085+ if (savNumber)
1086+ transaction->rollbackToSavepoint (tdbb, savNumber);
1087+
1088+ throw ;
1089+ }
1090+
1091+ // If any requested modify/delete/insert ops have completed, forget them
1092+
1093+ if (savNumber)
1094+ {
1095+ // There should be no other savepoint but the one started by ourselves.
1096+ fb_assert (transaction->tra_save_point && transaction->tra_save_point ->getNumber () == savNumber);
1097+
1098+ forgetSavepoint (tdbb, request, transaction, savNumber);
1099+ }
1100+ }
1101+ else
1102+ {
1103+ EXE_start (tdbb, request, transaction);
1104+
1105+ if (inMsgLength != 0 )
1106+ EXE_send (tdbb, request, 0 , inMsgLength, inMsg);
1107+
1108+ EXE_receive (tdbb, request, 1 , outMsgLength, outMsg);
1109+ }
1110+ }
1111+
1112+
9211113// Start and execute a request.
9221114void EXE_start (thread_db* tdbb, Request* request, jrd_tra* transaction)
9231115{
924- EXE_activate (tdbb, request, transaction);
1116+ activate_request (tdbb, request, transaction);
9251117
9261118 execute_looper (tdbb, request, transaction, request->getStatement ()->topNode , Request::req_evaluate);
9271119}
@@ -1043,25 +1235,7 @@ static void execute_looper(thread_db* tdbb,
10431235 if (lock && lock->lck_logical == LCK_none)
10441236 LCK_lock (tdbb, lock, LCK_SR, LCK_WAIT);
10451237
1046- // Start a save point
1047-
1048- SavNumber savNumber = 0 ;
1049-
1050- if (!(request->req_flags & req_proc_fetch) && request->req_transaction )
1051- {
1052- if (transaction && !(transaction->tra_flags & TRA_system))
1053- {
1054- if (request->req_savepoints )
1055- {
1056- request->req_savepoints =
1057- request->req_savepoints ->moveToStack (transaction->tra_save_point );
1058- }
1059- else
1060- transaction->startSavepoint ();
1061-
1062- savNumber = transaction->tra_save_point ->getNumber ();
1063- }
1064- }
1238+ const SavNumber savNumber = startSavepoint (request, transaction);
10651239
10661240 request->req_flags &= ~req_stall;
10671241 request->req_operation = next_state;
@@ -1090,24 +1264,7 @@ static void execute_looper(thread_db* tdbb,
10901264 (transaction->tra_save_point &&
10911265 transaction->tra_save_point ->getNumber () == savNumber));
10921266
1093- while (transaction->tra_save_point &&
1094- transaction->tra_save_point ->getNumber () >= savNumber)
1095- {
1096- const auto savepoint = transaction->tra_save_point ;
1097- // Forget about any undo for this verb
1098- fb_assert (!transaction->tra_save_point ->isChanging ());
1099- transaction->releaseSavepoint (tdbb);
1100- // Preserve savepoint for reuse
1101- fb_assert (savepoint == transaction->tra_save_free );
1102- transaction->tra_save_free = savepoint->moveToStack (request->req_savepoints );
1103- fb_assert (savepoint != transaction->tra_save_free );
1104-
1105- // Ensure that the priorly existing savepoints are preserved,
1106- // e.g. 10-11-12-(5-6-7) where savNumber == 5. This may happen
1107- // due to looper savepoints being reused in subsequent invokations.
1108- if (savepoint->getNumber () == savNumber)
1109- break ;
1110- }
1267+ forgetSavepoint (tdbb, request, transaction, savNumber);
11111268 }
11121269}
11131270
@@ -1357,6 +1514,7 @@ bool EXE_get_stack_trace(const Request* request, string& sTrace)
13571514 return sTrace .hasData ();
13581515}
13591516
1517+
13601518static void stuff_stack_trace (const Request* request)
13611519{
13621520 string sTrace ;
0 commit comments