@@ -253,6 +253,7 @@ string StatusXcp::as_text() const
253
253
}
254
254
255
255
256
+ static void activate_request (thread_db* tdbb, Request* request, jrd_tra* transaction);
256
257
static void execute_looper (thread_db*, Request*, jrd_tra*, const StmtNode*, Request::req_s);
257
258
static void looper_seh (thread_db*, Request*, const StmtNode*);
258
259
static void release_blobs (thread_db*, Request*);
@@ -262,6 +263,56 @@ static void stuff_stack_trace(const Request*);
262
263
const size_t MAX_STACK_TRACE = 2048 ;
263
264
264
265
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
+
265
316
// Perform an assignment.
266
317
void EXE_assignment (thread_db* tdbb, const AssignmentNode* node)
267
318
{
@@ -850,7 +901,7 @@ void EXE_send(thread_db* tdbb, Request* request, USHORT msg, ULONG length, const
850
901
851
902
852
903
// 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)
854
905
{
855
906
SET_TDBB (tdbb);
856
907
@@ -918,10 +969,151 @@ void EXE_activate(thread_db* tdbb, Request* request, jrd_tra* transaction)
918
969
}
919
970
920
971
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
+
921
1113
// Start and execute a request.
922
1114
void EXE_start (thread_db* tdbb, Request* request, jrd_tra* transaction)
923
1115
{
924
- EXE_activate (tdbb, request, transaction);
1116
+ activate_request (tdbb, request, transaction);
925
1117
926
1118
execute_looper (tdbb, request, transaction, request->getStatement ()->topNode , Request::req_evaluate);
927
1119
}
@@ -1043,25 +1235,7 @@ static void execute_looper(thread_db* tdbb,
1043
1235
if (lock && lock->lck_logical == LCK_none)
1044
1236
LCK_lock (tdbb, lock, LCK_SR, LCK_WAIT);
1045
1237
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);
1065
1239
1066
1240
request->req_flags &= ~req_stall;
1067
1241
request->req_operation = next_state;
@@ -1090,24 +1264,7 @@ static void execute_looper(thread_db* tdbb,
1090
1264
(transaction->tra_save_point &&
1091
1265
transaction->tra_save_point ->getNumber () == savNumber));
1092
1266
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);
1111
1268
}
1112
1269
}
1113
1270
@@ -1357,6 +1514,7 @@ bool EXE_get_stack_trace(const Request* request, string& sTrace)
1357
1514
return sTrace .hasData ();
1358
1515
}
1359
1516
1517
+
1360
1518
static void stuff_stack_trace (const Request* request)
1361
1519
{
1362
1520
string sTrace ;
0 commit comments