mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 10:00:38 +01:00
Fix for #8077: Error "Too many recursion levels" does not stop execuition of code that uses ON DISCONNECT trigger (PR#8119)
Co-authored-by: Vlad Khorsun <hvlad@users.sourceforge.net>
This commit is contained in:
parent
995dd02b3a
commit
7a4bbedf31
@ -212,6 +212,14 @@ void StatusVector::ImplStatusVector::append(const StatusVector& v) noexcept
|
|||||||
|
|
||||||
void StatusVector::ImplStatusVector::prepend(const StatusVector& v) noexcept
|
void StatusVector::ImplStatusVector::prepend(const StatusVector& v) noexcept
|
||||||
{
|
{
|
||||||
|
auto errFrom = v.implementation->value();
|
||||||
|
auto lenFrom = v.implementation->firstWarning() ? v.implementation->firstWarning() : v.implementation->length();
|
||||||
|
auto errTo = value();
|
||||||
|
auto lenTo = firstWarning() ? firstWarning() : length();
|
||||||
|
|
||||||
|
if (lenFrom < lenTo && fb_utils::cmpStatus(lenFrom, errFrom, errTo))
|
||||||
|
return; // already here - ToDo: check warnings
|
||||||
|
|
||||||
ImplStatusVector newVector(getKind(), getCode());
|
ImplStatusVector newVector(getKind(), getCode());
|
||||||
|
|
||||||
if (newVector.appendErrors(v.implementation))
|
if (newVector.appendErrors(v.implementation))
|
||||||
|
@ -269,6 +269,12 @@ public:
|
|||||||
*value |= oldValue;
|
*value |= oldValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void release(T cleanBit)
|
||||||
|
{
|
||||||
|
bit &= ~cleanBit;
|
||||||
|
oldValue &= ~cleanBit;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// copying is prohibited
|
// copying is prohibited
|
||||||
AutoSetRestoreFlag(const AutoSetRestoreFlag&);
|
AutoSetRestoreFlag(const AutoSetRestoreFlag&);
|
||||||
|
@ -602,6 +602,12 @@ void Jrd::Attachment::resetSession(thread_db* tdbb, jrd_tra** traHandle)
|
|||||||
}
|
}
|
||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
|
if (att_ext_call_depth && !shutAtt)
|
||||||
|
{
|
||||||
|
flags.release(ATT_resetting); // reset is incomplete - keep state
|
||||||
|
shutAtt = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (shutAtt)
|
if (shutAtt)
|
||||||
signalShutdown(isc_ses_reset_failed);
|
signalShutdown(isc_ses_reset_failed);
|
||||||
|
|
||||||
|
@ -441,9 +441,9 @@ void Provider::jrdAttachmentEnd(thread_db* tdbb, Jrd::Attachment* att, bool forc
|
|||||||
void Provider::releaseConnection(thread_db* tdbb, Connection& conn, bool inPool)
|
void Provider::releaseConnection(thread_db* tdbb, Connection& conn, bool inPool)
|
||||||
{
|
{
|
||||||
ConnectionsPool* connPool = conn.getConnPool();
|
ConnectionsPool* connPool = conn.getConnPool();
|
||||||
|
Attachment* att = conn.getBoundAtt();
|
||||||
|
|
||||||
{ // m_mutex scope
|
{ // m_mutex scope
|
||||||
Attachment* att = conn.getBoundAtt();
|
|
||||||
MutexLockGuard guard(m_mutex, FB_FUNCTION);
|
MutexLockGuard guard(m_mutex, FB_FUNCTION);
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@ -464,7 +464,42 @@ void Provider::releaseConnection(thread_db* tdbb, Connection& conn, bool inPool)
|
|||||||
m_connections.add(AttToConn(NULL, &conn));
|
m_connections.add(AttToConn(NULL, &conn));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inPool || !connPool || !connPool->getMaxCount() || !conn.isConnected() || !conn.resetSession(tdbb))
|
FbLocalStatus resetError;
|
||||||
|
inPool = inPool && connPool && connPool->getMaxCount() && conn.isConnected();
|
||||||
|
|
||||||
|
if (inPool)
|
||||||
|
{
|
||||||
|
inPool = conn.resetSession(tdbb);
|
||||||
|
|
||||||
|
// Check if reset of external session failed when parent (local) attachment
|
||||||
|
// is resetting or run ON DISCONNECT trigger.
|
||||||
|
|
||||||
|
const auto status = tdbb->tdbb_status_vector;
|
||||||
|
if (!inPool && status->hasData())
|
||||||
|
{
|
||||||
|
if (att->att_flags & ATT_resetting)
|
||||||
|
resetError.loadFrom(status);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto req = tdbb->getRequest();
|
||||||
|
while (req)
|
||||||
|
{
|
||||||
|
if (req->req_trigger_action == TRIGGER_DISCONNECT)
|
||||||
|
{
|
||||||
|
resetError.loadFrom(status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
req = req->req_caller;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inPool)
|
||||||
|
{
|
||||||
|
connPool->putConnection(tdbb, &conn);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
{ // scope
|
{ // scope
|
||||||
MutexLockGuard guard(m_mutex, FB_FUNCTION);
|
MutexLockGuard guard(m_mutex, FB_FUNCTION);
|
||||||
@ -477,9 +512,8 @@ void Provider::releaseConnection(thread_db* tdbb, Connection& conn, bool inPool)
|
|||||||
connPool->delConnection(tdbb, &conn, false);
|
connPool->delConnection(tdbb, &conn, false);
|
||||||
|
|
||||||
Connection::deleteConnection(tdbb, &conn);
|
Connection::deleteConnection(tdbb, &conn);
|
||||||
|
resetError.check();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
connPool->putConnection(tdbb, &conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Provider::clearConnections(thread_db* tdbb)
|
void Provider::clearConnections(thread_db* tdbb)
|
||||||
|
@ -274,6 +274,7 @@ bool IscConnection::resetSession(thread_db* tdbb)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ERR_post_nothrow(&status);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8352,8 +8352,11 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
|
|||||||
const TrigVector* const trig_disconnect =
|
const TrigVector* const trig_disconnect =
|
||||||
attachment->att_triggers[DB_TRIGGER_DISCONNECT];
|
attachment->att_triggers[DB_TRIGGER_DISCONNECT];
|
||||||
|
|
||||||
|
// ATT_resetting may be set here only in a case when running on disconnect triggers
|
||||||
|
// in ALTER SESSION RESET already failed and attachment was shut down.
|
||||||
|
// Trying them once again here makes no sense.
|
||||||
if (!forcedPurge &&
|
if (!forcedPurge &&
|
||||||
!(attachment->att_flags & ATT_no_db_triggers) &&
|
!(attachment->att_flags & (ATT_no_db_triggers | ATT_resetting)) &&
|
||||||
trig_disconnect && !trig_disconnect->isEmpty())
|
trig_disconnect && !trig_disconnect->isEmpty())
|
||||||
{
|
{
|
||||||
ThreadStatusGuard temp_status(tdbb);
|
ThreadStatusGuard temp_status(tdbb);
|
||||||
|
Loading…
Reference in New Issue
Block a user