From 9dc3f5e6cc9d87c0cd419966ca794a7c15a6e5fe Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Tue, 31 Jan 2023 12:01:59 +0300 Subject: [PATCH] Postfix for #7446: never attempt to delete savepoints belonging to a different transaction --- src/dsql/StmtNodes.cpp | 9 +++++++-- src/jrd/req.h | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 7b89d06ea6..453dc7ee80 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -3712,6 +3712,7 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r org_transaction->tra_lock_timeout, org_transaction); + request->pushTransaction(org_transaction); TRA_attach_request(transaction, request); tdbb->setTransaction(transaction); @@ -3722,12 +3723,13 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r } catch (Exception&) { + TRA_detach_request(request); + request->popTransaction(); TRA_attach_request(org_transaction, request); tdbb->setTransaction(org_transaction); throw; } - request->req_auto_trans.push(org_transaction); impure->traNumber = transaction->tra_number; VIO_start_save_point(tdbb, transaction); @@ -3841,8 +3843,11 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r } impure->traNumber = impure->savNumber = 0; - transaction = request->req_auto_trans.pop(); + // Normally request is detached by commit/rollback, but they may fail. + // It should be done before request->popTransaction(). + TRA_detach_request(request); + transaction = request->popTransaction(); TRA_attach_request(transaction, request); tdbb->setTransaction(transaction); diff --git a/src/jrd/req.h b/src/jrd/req.h index 4f917303d4..eb9a60becf 100644 --- a/src/jrd/req.h +++ b/src/jrd/req.h @@ -164,6 +164,21 @@ private: class jrd_req : public pool_alloc { + // Context data saved/restored with every new autonomous transaction + + struct AutoTranCtx + { + AutoTranCtx() : m_transaction(NULL), m_savepoints(NULL) + {} + + AutoTranCtx(jrd_tra* tran, Savepoint* save) : + m_transaction(tran), m_savepoints(save) + {} + + jrd_tra* m_transaction; + Savepoint* m_savepoints; + }; + public: jrd_req(Attachment* attachment, /*const*/ JrdStatement* aStatement, Firebird::MemoryStats* parent_stats) @@ -263,7 +278,7 @@ public: ULONG req_src_column; dsc* req_domain_validation; // Current VALUE for constraint validation - Firebird::Stack req_auto_trans; // Autonomous transactions + Firebird::Stack req_auto_trans; // Autonomous transactions SortOwner req_sorts; Firebird::Array req_rpb; // record parameter blocks Firebird::Array impureArea; // impure area @@ -294,6 +309,24 @@ public: } req_base_stats.assign(req_stats); } + + // Save context when switching to the autonomous transaction + void pushTransaction(jrd_tra* const transaction) + { + req_auto_trans.push(AutoTranCtx(transaction, req_proc_sav_point)); + req_proc_sav_point = NULL; + } + + // Restore context + jrd_tra* popTransaction() + { + fb_assert(!req_transaction); // must be detached + + const AutoTranCtx tmp = req_auto_trans.pop(); + req_proc_sav_point = tmp.m_savepoints; + + return tmp.m_transaction; + } }; // Flags for req_flags