diff --git a/src/common/StatusArg.cpp b/src/common/StatusArg.cpp index d66758b172..af22d32d51 100644 --- a/src/common/StatusArg.cpp +++ b/src/common/StatusArg.cpp @@ -212,6 +212,14 @@ void StatusVector::ImplStatusVector::append(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()); if (newVector.appendErrors(v.implementation)) diff --git a/src/common/classes/auto.h b/src/common/classes/auto.h index 0bb70fc0e3..d77c555d8b 100644 --- a/src/common/classes/auto.h +++ b/src/common/classes/auto.h @@ -269,6 +269,12 @@ public: *value |= oldValue; } + void release(T cleanBit) + { + bit &= ~cleanBit; + oldValue &= ~cleanBit; + } + private: // copying is prohibited AutoSetRestoreFlag(const AutoSetRestoreFlag&); diff --git a/src/jrd/Attachment.cpp b/src/jrd/Attachment.cpp index a0ea8190e9..9612457348 100644 --- a/src/jrd/Attachment.cpp +++ b/src/jrd/Attachment.cpp @@ -602,6 +602,12 @@ void Jrd::Attachment::resetSession(thread_db* tdbb, jrd_tra** traHandle) } catch (const Exception& ex) { + if (att_ext_call_depth && !shutAtt) + { + flags.release(ATT_resetting); // reset is incomplete - keep state + shutAtt = true; + } + if (shutAtt) signalShutdown(isc_ses_reset_failed); diff --git a/src/jrd/extds/ExtDS.cpp b/src/jrd/extds/ExtDS.cpp index 0e74394d7c..6d4b9dcb41 100644 --- a/src/jrd/extds/ExtDS.cpp +++ b/src/jrd/extds/ExtDS.cpp @@ -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) { ConnectionsPool* connPool = conn.getConnPool(); + Attachment* att = conn.getBoundAtt(); { // m_mutex scope - Attachment* att = conn.getBoundAtt(); MutexLockGuard guard(m_mutex, FB_FUNCTION); bool found = false; @@ -464,7 +464,42 @@ void Provider::releaseConnection(thread_db* tdbb, Connection& conn, bool inPool) 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 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); Connection::deleteConnection(tdbb, &conn); + resetError.check(); } - else - connPool->putConnection(tdbb, &conn); } void Provider::clearConnections(thread_db* tdbb) diff --git a/src/jrd/extds/IscDS.cpp b/src/jrd/extds/IscDS.cpp index 2c9ef72daa..8d2efb2ab2 100644 --- a/src/jrd/extds/IscDS.cpp +++ b/src/jrd/extds/IscDS.cpp @@ -274,6 +274,7 @@ bool IscConnection::resetSession(thread_db* tdbb) return true; } + ERR_post_nothrow(&status); return false; } diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 6b81cbb5e2..a79d2fe149 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -8352,8 +8352,11 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign const TrigVector* const trig_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 && - !(attachment->att_flags & ATT_no_db_triggers) && + !(attachment->att_flags & (ATT_no_db_triggers | ATT_resetting)) && trig_disconnect && !trig_disconnect->isEmpty()) { ThreadStatusGuard temp_status(tdbb);