From ee5b901283216f0e36c4ed85091409c334d3f5a6 Mon Sep 17 00:00:00 2001 From: Vlad Khorsun Date: Tue, 24 Mar 2026 16:57:47 +0200 Subject: [PATCH 1/2] Implement #8912 : Context variables clear/re-initialization support --- doc/sql.extensions/README.context_variables2 | 13 +++- src/common/ParserTokens.h | 1 + src/dsql/parse.y | 2 + src/jrd/SysFunction.cpp | 70 +++++++++++++++++++- 4 files changed, 82 insertions(+), 4 deletions(-) diff --git a/doc/sql.extensions/README.context_variables2 b/doc/sql.extensions/README.context_variables2 index da92964bd5a..714220807a0 100644 --- a/doc/sql.extensions/README.context_variables2 +++ b/doc/sql.extensions/README.context_variables2 @@ -7,15 +7,17 @@ Function: connection and current transaction. Also they provide means to associate and retrieve user context data with transaction or connection. -Author: - Nickolay Samofatov +Authors: + Nickolay Samofatov , + Vladyslav Khorsun Format: RDB$SET_CONTEXT( , , ) RDB$GET_CONTEXT( , ) + RDB$RESET_CONTEXT( ) Returned value: - INTEGER for RDB$SET_CONTEXT + INTEGER for RDB$SET_CONTEXT, RDB$RESET_CONTEXT VARCHAR(32765) for RDB$GET_CONTEXT Usage: @@ -36,6 +38,9 @@ Usage: 1 if variable existed before the call and 0 otherwise. To delete variable from context set its value to NULL. + RDB$RESET_CONTEXT removes all variables from given context. It returns count + of removed variables. + Currently, there is a fixed number of pre-defined namespaces you may use. USER_SESSION namespace offers access to session-specific user-defined @@ -183,3 +188,5 @@ execute procedure set_context('skidder', 1); insert into journal(jrn_id) values(0); commit; + +SELECT RDB$RESET_CONTEXT('USER_SESSION') FROM RDB$DATABASE; diff --git a/src/common/ParserTokens.h b/src/common/ParserTokens.h index d2e71068ab8..3ddad43eb78 100644 --- a/src/common/ParserTokens.h +++ b/src/common/ParserTokens.h @@ -404,6 +404,7 @@ PARSER_TOKEN(TOK_RDB_ERROR, "RDB$ERROR", false) PARSER_TOKEN(TOK_RDB_GET_CONTEXT, "RDB$GET_CONTEXT", false) PARSER_TOKEN(TOK_RDB_GET_TRANSACTION_CN, "RDB$GET_TRANSACTION_CN", false) PARSER_TOKEN(TOK_RDB_RECORD_VERSION, "RDB$RECORD_VERSION", false) +PARSER_TOKEN(TOK_RDB_RESET_CONTEXT, "RDB$RESET_CONTEXT", false) PARSER_TOKEN(TOK_RDB_ROLE_IN_USE, "RDB$ROLE_IN_USE", false) PARSER_TOKEN(TOK_RDB_SET_CONTEXT, "RDB$SET_CONTEXT", false) PARSER_TOKEN(TOK_RDB_SYSTEM_PRIVILEGE, "RDB$SYSTEM_PRIVILEGE", false) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index ff9b5f4cde5..b420d9c4fba 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -725,6 +725,7 @@ using namespace Firebird; %token TRUNCATE %token UNLIST %token WITHIN +%token RDB_RESET_CONTEXT // precedence declarations for expression evaluation @@ -9055,6 +9056,7 @@ system_function_std_syntax | RAND | RDB_GET_CONTEXT | RDB_GET_TRANSACTION_CN + | RDB_RESET_CONTEXT | RDB_ROLE_IN_USE | RDB_SET_CONTEXT | REPLACE diff --git a/src/jrd/SysFunction.cpp b/src/jrd/SysFunction.cpp index d34fd07fd99..8cba7c80137 100644 --- a/src/jrd/SysFunction.cpp +++ b/src/jrd/SysFunction.cpp @@ -237,6 +237,7 @@ void setParamsDateDiff(DataTypeUtilBase* dataTypeUtil, const SysFunction* functi void setParamsEncrypt(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args); void setParamsFirstLastDay(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsGetSetContext(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); +void setParamsResetContext(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsHash(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args); void setParamsMakeDbkey(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsOverlay(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); @@ -329,6 +330,7 @@ dsc* evlFloor(thread_db* tdbb, const SysFunction* function, const NestValueArray dsc* evlGenUuid(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlGetContext(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlSetContext(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); +dsc* evlResetContext(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlGetTranCN(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlHash(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlLeft(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); @@ -360,7 +362,8 @@ dsc* evlUuidToChar(thread_db* tdbb, const SysFunction* function, const NestValue // System context function names constexpr char RDB_GET_CONTEXT[] = "RDB$GET_CONTEXT", - RDB_SET_CONTEXT[] = "RDB$SET_CONTEXT"; + RDB_SET_CONTEXT[] = "RDB$SET_CONTEXT", + RDB_RESET_CONTEXT[] = "RDB$RESET_CONTEXT"; // Context namespace names constexpr char @@ -863,6 +866,18 @@ void setParamsGetSetContext(DataTypeUtilBase*, const SysFunction*, int argsCount } +void setParamsResetContext(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args) +{ + fb_assert(argsCount == 1); + + if (args[0]->isUnknown()) + { + args[0]->makeVarying(80, ttype_none); + args[0]->setNullable(true); + } +} + + void setParamsHash(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args) { fb_assert(argsCount == 1 || argsCount == 2); @@ -5005,6 +5020,58 @@ dsc* evlSetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar } +dsc* evlResetContext(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure) +{ + fb_assert(args.getCount() == 1); + + Jrd::Attachment* attachment = tdbb->getAttachment(); + jrd_tra* transaction = tdbb->getTransaction(); + Request* request = tdbb->getRequest(); + + const dsc* nameSpace = EVL_expr(tdbb, request, args[0]); + if (!nameSpace) // Complain if namespace is null + ERR_post(Arg::Gds(isc_ctx_bad_argument) << Arg::Str(RDB_RESET_CONTEXT)); + + const string nameSpaceStr(MOV_make_string2(tdbb, nameSpace, ttype_none)); + + StringMap* contextVars = nullptr; + + if (nameSpaceStr == USER_SESSION_NAMESPACE) + { + if (!attachment) + { + fb_assert(false); + return nullptr; + } + + contextVars = &attachment->att_context_vars; + } + else if (nameSpaceStr == USER_TRANSACTION_NAMESPACE) + { + if (!transaction) + { + fb_assert(false); + return nullptr; + } + + contextVars = &transaction->tra_context_vars; + } + else + { + // "Invalid namespace name %s passed to %s" + ERR_post(Arg::Gds(isc_ctx_namespace_invalid) << + Arg::Str(nameSpaceStr) << Arg::Str(RDB_RESET_CONTEXT)); + } + + impure->vlu_desc.makeLong(0, &impure->vlu_misc.vlu_long); + impure->vlu_misc.vlu_long = (SLONG) contextVars->count(); + + contextVars->clear(); + + return &impure->vlu_desc; +} + + dsc* evlGetTranCN(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure) { @@ -6976,6 +7043,7 @@ const SysFunction SysFunction::functions[] = {RDB_GET_CONTEXT, 2, 2, true, setParamsGetSetContext, makeGetSetContext, evlGetContext, NULL}, {"RDB$GET_TRANSACTION_CN", 1, 1, false, setParamsInt64, makeGetTranCN, evlGetTranCN, NULL}, {"RDB$ROLE_IN_USE", 1, 1, true, setParamsAsciiVal, makeBooleanResult, evlRoleInUse, NULL}, + {RDB_RESET_CONTEXT, 1, 1, false, setParamsResetContext, makeLongResult, evlResetContext, NULL}, {RDB_SET_CONTEXT, 3, 3, false, setParamsGetSetContext, makeGetSetContext, evlSetContext, NULL}, {"RDB$SYSTEM_PRIVILEGE", 1, 1, true, NULL, makeBooleanResult, evlSystemPrivilege, NULL}, {"REPLACE", 3, 3, true, setParamsFromList, makeReplace, evlReplace, NULL}, From cc38e0f0c0e7dfe7df7708d8a4df709e48a06df3 Mon Sep 17 00:00:00 2001 From: Vlad Khorsun Date: Wed, 25 Mar 2026 09:56:16 +0200 Subject: [PATCH 2/2] Follow @dyemanov suggestions --- src/jrd/SysFunction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jrd/SysFunction.cpp b/src/jrd/SysFunction.cpp index 8cba7c80137..4c216b68031 100644 --- a/src/jrd/SysFunction.cpp +++ b/src/jrd/SysFunction.cpp @@ -5024,8 +5024,8 @@ dsc* evlResetContext(thread_db* tdbb, const SysFunction* function, const NestVal { fb_assert(args.getCount() == 1); - Jrd::Attachment* attachment = tdbb->getAttachment(); - jrd_tra* transaction = tdbb->getTransaction(); + Attachment* const attachment = tdbb->getAttachment(); + jrd_tra* const transaction = tdbb->getTransaction(); Request* request = tdbb->getRequest(); const dsc* nameSpace = EVL_expr(tdbb, request, args[0]);