8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 04:03:04 +01:00

Fix CORE-5173

This commit is contained in:
Dimitry Sibiryakov 2016-03-26 16:38:13 +01:00
parent ed38cf98a6
commit 99f4d16448

View File

@ -558,6 +558,31 @@ const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
if (handlers && handlers->statements.getCount() > 0) if (handlers && handlers->statements.getCount() > 0)
{ {
// First of all rollback failed work
if (transaction != sysTransaction)
{
count = *request->getImpure<SLONG>(impureOffset);
// Since there occurred an error (req_unwind), undo all savepoints
// up to, _but not including_, the savepoint of this block.
// That's why transaction->rollbackToSavepoint() cannot be used here
// The savepoint of this block will be dealt with below.
// Do this only if error handlers exist. If not - leave rollbacking to caller node
while (transaction->tra_save_point &&
transaction->tra_save_point->sav_next &&
count < transaction->tra_save_point->sav_next->sav_number)
{
transaction->rollforwardSavepoint(tdbb);
}
// There can be no savepoints above the given one
if (transaction->tra_save_point && transaction->tra_save_point->sav_number > count)
{
transaction->rollbackSavepoint(tdbb);
}
// after that we still have to have our savepoint. If not - CORE-4424/4483 is sneaking around
fb_assert(transaction->tra_save_point && transaction->tra_save_point->sav_number == count);
}
temp = parentStmt; temp = parentStmt;
bool handled = false; bool handled = false;
const NestConst<StmtNode>* ptr = handlers->statements.begin(); const NestConst<StmtNode>* ptr = handlers->statements.begin();
@ -575,31 +600,6 @@ const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
temp = handlerNode->action; temp = handlerNode->action;
exeState->errorPending = false; exeState->errorPending = false;
if (transaction != sysTransaction)
{
count = *request->getImpure<SLONG>(impureOffset);
// Since there occurred an error (req_unwind), undo all savepoints
// up to, _but not including_, the savepoint of this block.
// That's why transaction->rollbackToSavepoint() cannot be used here
// The savepoint of this block will be dealt with below.
// Do this only if error handlers exist. If not - leave rollbacking to caller node
while (transaction->tra_save_point &&
transaction->tra_save_point->sav_next &&
count < transaction->tra_save_point->sav_next->sav_number)
{
transaction->rollforwardSavepoint(tdbb);
}
// There can be no savepoints above the given one
if (transaction->tra_save_point && transaction->tra_save_point->sav_number > count)
{
transaction->rollbackSavepoint(tdbb);
}
// after that we still have to have our savepoint. If not - CORE-4424/4483 is sneaking around
fb_assert(transaction->tra_save_point && transaction->tra_save_point->sav_number == count);
}
// On entering looper exeState->oldRequest etc. are saved. // On entering looper exeState->oldRequest etc. are saved.
// On recursive calling we will loose the actual old // On recursive calling we will loose the actual old
// request for that invocation of looper. Avoid this. // request for that invocation of looper. Avoid this.
@ -647,9 +647,16 @@ const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
if (handled && transaction != sysTransaction) if (handled && transaction != sysTransaction)
{ {
// Check that exception handlers wee executed in context of right savepoint. // Check that exception handlers were executed in context of right savepoint.
// If not - mirror copy of CORE-4424 or CORE-4483 is around here. // If not - mirror copy of CORE-4424 or CORE-4483 is around here.
fb_assert(transaction->tra_save_point && transaction->tra_save_point->sav_number == count); // Except the case of nested exception handlers and throwing in inner one.
// In this case execution flow is like this:
// inner before (block that rollbacking savepoints above)
// outer before
// outer after (this block)
// inner after
// Because of this following assert is commentd out
//fb_assert(transaction->tra_save_point && transaction->tra_save_point->sav_number == count);
for (const Savepoint* save_point = transaction->tra_save_point; for (const Savepoint* save_point = transaction->tra_save_point;
save_point && count <= save_point->sav_number; save_point && count <= save_point->sav_number;
save_point = transaction->tra_save_point) save_point = transaction->tra_save_point)