diff --git a/builds/install/misc/firebird.conf b/builds/install/misc/firebird.conf index c35907338d..4cec7d682b 100644 --- a/builds/install/misc/firebird.conf +++ b/builds/install/misc/firebird.conf @@ -611,6 +611,18 @@ #ConnectionIdleTimeout = 0 +# ---------------------------- +# +# Set number of seconds after which ON DISCONNECT trigger execution will be +# automatically cancelled by the engine. Zero means no timeout is set. +# +# Per-database configurable. +# +# Type: integer +# +#OnDisconnectTriggerTimeout = 180 + + # ---------------------------- # # How often the pages are flushed on disk diff --git a/src/common/config/config.h b/src/common/config/config.h index a7b1febc4c..f874213c32 100644 --- a/src/common/config/config.h +++ b/src/common/config/config.h @@ -176,6 +176,7 @@ enum ConfigKey KEY_ENCRYPT_SECURITY_DATABASE, KEY_STMT_TIMEOUT, KEY_CONN_IDLE_TIMEOUT, + KEY_ON_DISCONNECT_TRIG_TIMEOUT, KEY_CLIENT_BATCH_BUFFER, KEY_OUTPUT_REDIRECTION_FILE, KEY_EXT_CONN_POOL_SIZE, @@ -284,6 +285,7 @@ constexpr ConfigEntry entries[MAX_CONFIG_KEY] = {TYPE_BOOLEAN, "AllowEncryptedSecurityDatabase", false, false}, {TYPE_INTEGER, "StatementTimeout", false, 0}, {TYPE_INTEGER, "ConnectionIdleTimeout", false, 0}, + {TYPE_INTEGER, "OnDisconnectTriggerTimeout", false, 180}, {TYPE_INTEGER, "ClientBatchBuffer", false, 128 * 1024}, #ifdef DEV_BUILD {TYPE_STRING, "OutputRedirectionFile", true, "-"}, @@ -603,6 +605,9 @@ public: // set in minutes CONFIG_GET_PER_DB_KEY(unsigned int, getConnIdleTimeout, KEY_CONN_IDLE_TIMEOUT, getInt); + // set in seconds + CONFIG_GET_PER_DB_KEY(unsigned int, getOnDisconnectTrigTimeout, KEY_ON_DISCONNECT_TRIG_TIMEOUT, getInt); + CONFIG_GET_PER_DB_KEY(unsigned int, getClientBatchBuffer, KEY_CLIENT_BATCH_BUFFER, getInt); CONFIG_GET_GLOBAL_STR(getOutputRedirectionFile, KEY_OUTPUT_REDIRECTION_FILE); diff --git a/src/jrd/exe.cpp b/src/jrd/exe.cpp index b9284618d5..b00419452f 100644 --- a/src/jrd/exe.cpp +++ b/src/jrd/exe.cpp @@ -1209,7 +1209,19 @@ void EXE_execute_triggers(thread_db* tdbb, &tdbb->getAttachment()->att_original_timezone, tdbb->getAttachment()->att_current_timezone); - EXE_start(tdbb, trigger, transaction); + if (trigger_action == TRIGGER_DISCONNECT) + { + if (!trigger->req_timer) + trigger->req_timer = FB_NEW_POOL(*tdbb->getAttachment()->att_pool) TimeoutTimer(); + + const unsigned int timeOut = tdbb->getDatabase()->dbb_config->getOnDisconnectTrigTimeout() * 1000; + trigger->req_timer->setup(timeOut, isc_cfg_stmt_timeout); + trigger->req_timer->start(); + thread_db::TimerGuard timerGuard(tdbb, trigger->req_timer, true); + EXE_start(tdbb, trigger, transaction); + } + else + EXE_start(tdbb, trigger, transaction); } const bool ok = (trigger->req_operation != Request::req_unwind); diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index bb01a831d8..1fa7cea8ad 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -8200,15 +8200,21 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign transaction = TRA_start(tdbb, 0, NULL); attachment->att_flags = save_flags; + // Allow cancelling while ON DISCONNECT triggers are running + tdbb->tdbb_flags &= ~TDBB_detaching; + // run ON DISCONNECT triggers EXE_execute_db_triggers(tdbb, transaction, TRIGGER_DISCONNECT); + tdbb->tdbb_flags |= TDBB_detaching; + // and commit the transaction TRA_commit(tdbb, transaction, false); } catch (const Exception& ex) { attachment->att_flags = save_flags; + tdbb->tdbb_flags |= TDBB_detaching; string s; s.printf("Database: %s\n\tError at disconnect:", attachment->att_filename.c_str()); @@ -8927,11 +8933,8 @@ ISC_STATUS thread_db::getCancelState(ISC_STATUS* secondary) if (tdbb_flags & (TDBB_verb_cleanup | TDBB_dfw_cleanup | TDBB_detaching | TDBB_wait_cancel_disable)) return FB_SUCCESS; - if (attachment) + if (attachment && attachment->att_purge_tid != Thread::getId()) { - if (attachment->att_purge_tid == Thread::getId()) - return FB_SUCCESS; - if (attachment->att_flags & ATT_shutdown) { if (database->dbb_ast_flags & DBB_shutdown)