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

Fixed bug CORE-5681 : AV when external statement is executed and local transaction is rolled back

This commit is contained in:
hvlad 2017-12-17 02:05:00 +02:00
parent 40897c40de
commit 860f179712
2 changed files with 27 additions and 8 deletions

View File

@ -365,8 +365,24 @@ Transaction* Connection::createTransaction()
return tran; return tran;
} }
void Connection::deleteTransaction(Transaction* tran) void Connection::deleteTransaction(thread_db* tdbb, Transaction* tran)
{ {
// Close all active statements in tran context avoiding commit of already
// deleted transaction
Statement** stmt_ptr = m_statements.begin();
while (stmt_ptr < m_statements.end())
{
Statement* stmt = *stmt_ptr;
if (stmt->getTransaction() == tran)
{
if (stmt->isActive())
stmt->close(tdbb, true);
}
// close() above could destroy statement and remove it from m_statements
if (stmt_ptr < m_statements.end() && *stmt_ptr == stmt)
stmt_ptr++;
}
FB_SIZE_T pos; FB_SIZE_T pos;
if (m_transactions.find(tran, pos)) if (m_transactions.find(tran, pos))
{ {
@ -378,7 +394,7 @@ void Connection::deleteTransaction(Transaction* tran)
} }
if (!m_used_stmts && m_transactions.getCount() == 0 && !m_deleting) if (!m_used_stmts && m_transactions.getCount() == 0 && !m_deleting)
m_provider.releaseConnection(JRD_get_thread_data(), *this); m_provider.releaseConnection(tdbb, *this);
} }
Statement* Connection::createStatement(const string& sql) Statement* Connection::createStatement(const string& sql)
@ -657,7 +673,7 @@ void Transaction::commit(thread_db* tdbb, bool retain)
if (!retain) if (!retain)
{ {
detachFromJrdTran(); detachFromJrdTran();
m_connection.deleteTransaction(this); m_connection.deleteTransaction(tdbb, this);
} }
} }
@ -670,7 +686,7 @@ void Transaction::rollback(thread_db* tdbb, bool retain)
if (!retain) if (!retain)
{ {
detachFromJrdTran(); detachFromJrdTran();
m_connection.deleteTransaction(this); m_connection.deleteTransaction(tdbb, this);
} }
if (status->getState() & IStatus::STATE_ERRORS) { if (status->getState() & IStatus::STATE_ERRORS) {
@ -710,7 +726,7 @@ Transaction* Transaction::getTransaction(thread_db* tdbb, Connection* conn, TraS
} }
catch (const Exception&) catch (const Exception&)
{ {
conn->deleteTransaction(ext_tran); conn->deleteTransaction(tdbb, ext_tran);
throw; throw;
} }
} }
@ -913,7 +929,7 @@ bool Statement::fetch(thread_db* tdbb, const ValueListNode* out_params)
return true; return true;
} }
void Statement::close(thread_db* tdbb) void Statement::close(thread_db* tdbb, bool invalidTran)
{ {
// we must stuff exception if and only if this is the first time it occurs // we must stuff exception if and only if this is the first time it occurs
// once we stuff exception we must punt // once we stuff exception we must punt
@ -942,6 +958,9 @@ void Statement::close(thread_db* tdbb)
unBindFromRequest(); unBindFromRequest();
} }
if (invalidTran)
m_transaction = NULL;
if (m_transaction && m_transaction->getScope() == traAutonomous) if (m_transaction && m_transaction->getScope() == traAutonomous)
{ {
bool commitFailed = false; bool commitFailed = false;

View File

@ -201,7 +201,7 @@ public:
// transaction into m_transactions array and delete not needed transaction // transaction into m_transactions array and delete not needed transaction
// immediately (as we didn't pool transactions) // immediately (as we didn't pool transactions)
Transaction* createTransaction(); Transaction* createTransaction();
void deleteTransaction(Transaction* tran); void deleteTransaction(Jrd::thread_db* tdbb, Transaction* tran);
// Statements management within connection scope : put newly created // Statements management within connection scope : put newly created
// statement into m_statements array, but don't delete freed statement // statement into m_statements array, but don't delete freed statement
@ -325,7 +325,7 @@ public:
void open(Jrd::thread_db* tdbb, Transaction* tran, void open(Jrd::thread_db* tdbb, Transaction* tran,
const Firebird::MetaName* const* in_names, const Jrd::ValueListNode* in_params, bool singleton); const Firebird::MetaName* const* in_names, const Jrd::ValueListNode* in_params, bool singleton);
bool fetch(Jrd::thread_db* tdbb, const Jrd::ValueListNode* out_params); bool fetch(Jrd::thread_db* tdbb, const Jrd::ValueListNode* out_params);
void close(Jrd::thread_db* tdbb); void close(Jrd::thread_db* tdbb, bool invalidTran = false);
void deallocate(Jrd::thread_db* tdbb); void deallocate(Jrd::thread_db* tdbb);
const Firebird::string& getSql() const { return m_sql; } const Firebird::string& getSql() const { return m_sql; }