From eda332a9296f4d13a5e5ee812bbbe6a485751753 Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 12 May 2026 16:13:50 +0300 Subject: [PATCH 1/7] Search existing package constants in all SCHEMAs --- src/dsql/DdlNodes.epp | 2 +- src/dsql/ExprNodes.cpp | 2 +- src/jrd/met.epp | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 4af33e2d9c3..b5fc874eb00 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -1527,7 +1527,7 @@ DdlNode* CommentOnNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) case obj_package_constant: { QualifiedName constantName(subName, name.schema, name.object); // name is a package - dsqlScratch->qualifyNewName(constantName); // Search for a schema + dsqlScratch->qualifyExistingName(constantName, obj_package_constant); // Search for a schema if (!PackageReferenceNode::constantExists(tdbb, transaction, constantName)) { diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index 382669c0217..14fee7d989c 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -6477,7 +6477,7 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec if (constantName.package.hasData()) { - dsqlScratch->qualifyNewName(constantName); + dsqlScratch->qualifyExistingName(constantName, obj_package_constant); if (PackageReferenceNode::constantExists(tdbb, dsqlScratch->getTransaction(), constantName)) { diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 05294e6aba6..c95709db675 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -5509,6 +5509,25 @@ std::optional MET_qualify_existing_name(thread_db* tdbb, QualifiedNa break; } + case obj_package_constant: + { + static const CachedRequestId consatntHandleId; + handle.reset(tdbb, consatntHandleId); + + FOR (REQUEST_HANDLE handle) + CONST IN RDB$CONSTANTS + WITH CONST.RDB$SCHEMA_NAME EQ searchSchema.c_str() AND + CONST.RDB$CONSTANT_NAME EQ name.object.c_str() AND + CONST.RDB$PACKAGE_NAME EQUIV NULLIF(name.package.c_str(), '') + { + found = true; + break; + } + END_FOR + + break; + } + default: fb_assert(false); } From ac7f1c5afb13978ef48f304e378fc1f75014e129 Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 12 May 2026 16:13:56 +0300 Subject: [PATCH 2/7] Add constant missing RDB$CONSTANT_SOURCE setup --- src/dsql/PackageNodes.epp | 5 ++++- src/dsql/PackageNodes.h | 3 +++ src/dsql/parse.y | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/dsql/PackageNodes.epp b/src/dsql/PackageNodes.epp index f542974aa41..71cefa69ef6 100644 --- a/src/dsql/PackageNodes.epp +++ b/src/dsql/PackageNodes.epp @@ -576,6 +576,7 @@ string CreatePackageConstantNode::internalPrint(NodePrinter& printer) const DdlNode::internalPrint(printer); NODE_PRINT(printer, name); + NODE_PRINT(printer, source); NODE_PRINT(printer, m_type); NODE_PRINT(printer, m_expr); NODE_PRINT(printer, m_isPrivate); @@ -587,6 +588,8 @@ DdlNode* CreatePackageConstantNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { dsqlScratch->qualifyNewName(name); + source.ltrim("\n\r\t "); + m_expr = m_expr->dsqlPass(dsqlScratch); QualifiedName dummyCollationName; @@ -676,7 +679,7 @@ void CreatePackageConstantNode::executeCreate(thread_db* tdbb, DsqlCompilerScrat CONST.RDB$PRIVATE_FLAG = m_isPrivate; - CONST.RDB$CONSTANT_SOURCE.NULL = TRUE; + attachment->storeBinaryBlob(tdbb, transaction, &CONST.RDB$CONSTANT_SOURCE, source); } END_STORE } diff --git a/src/dsql/PackageNodes.h b/src/dsql/PackageNodes.h index 971e29815eb..b6edd07f23b 100644 --- a/src/dsql/PackageNodes.h +++ b/src/dsql/PackageNodes.h @@ -172,6 +172,7 @@ class CreatePackageConstantNode final : public DdlNode dsql_fld* type = nullptr, ValueExprNode* value = nullptr, bool isPrivate = false) : DdlNode(pool), name(pool, name), + source(pool), m_type(type), m_expr(value), m_isPrivate(isPrivate) @@ -209,6 +210,8 @@ class CreatePackageConstantNode final : public DdlNode public: QualifiedName name; + Firebird::string source; + bool create = false; bool alter = false; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 31b5e7c5174..8203e3798a1 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -3341,6 +3341,7 @@ package_const_item : symbol_package_const_name data_type_descriptor '=' value { $$ = newNode(*$1, $2, $4); + $$->source = makeParseStr(YYPOSNARG(3), YYPOSNARG(4)); } ; From af74e2cb72e8c940a52b06b2abdb8371cfb1032a Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 12 May 2026 16:14:29 +0300 Subject: [PATCH 3/7] Store EXECUTE privilege for all SYSTEM packages --- src/jrd/dyn.h | 1 + src/jrd/ini.epp | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/jrd/dyn.h b/src/jrd/dyn.h index 6aa0352e992..965b4aaaddc 100644 --- a/src/jrd/dyn.h +++ b/src/jrd/dyn.h @@ -37,6 +37,7 @@ inline constexpr const char* EXEC_PRIVILEGES = "X"; // execute privilege inline constexpr const char* PACKAGE_PRIVILEGES = "XSIUD"; // all applicable package privileges inline constexpr const char* USAGE_PRIVILEGES = "G"; // usage privilege inline constexpr const char* ALL_DDL_PRIVILEGES = "CLO"; +inline constexpr const char* SYSTEM_PACKAGE_PRIVILEGES = "XU"; // execute and usage privileges inline constexpr int DYN_MSG_FAC = FB_IMPL_MSG_FACILITY_DYN; diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index d098093bc5d..11953e11d17 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -397,14 +397,14 @@ namespace break; case obj_package_header: - privileges = EXEC_PRIVILEGES; + privileges = SYSTEM_PACKAGE_PRIVILEGES; break; default: fb_assert(false); } - fb_assert(privileges && privileges[0] && !privileges[1]); + fb_assert(privileges && privileges[0] && (!privileges[1] || !privileges[2])); const auto userName = getOwnerName(); fb_assert(userName && *userName); @@ -421,8 +421,9 @@ namespace PAD(users[i], PRIV.RDB$USER); PAD(SYSTEM_SCHEMA, PRIV.RDB$RELATION_SCHEMA_NAME); PAD(objName, PRIV.RDB$RELATION_NAME); - PRIV.RDB$PRIVILEGE[0] = *privileges; - PRIV.RDB$PRIVILEGE[1] = 0; + PRIV.RDB$PRIVILEGE[0] = privileges[0]; + PRIV.RDB$PRIVILEGE[1] = privileges[1]; + PRIV.RDB$PRIVILEGE[2] = 0; PRIV.RDB$GRANT_OPTION = grantOptions[i]; PRIV.RDB$USER_TYPE = obj_user; PRIV.RDB$OBJECT_TYPE = objType; From 4e5dafa48e926eaf329f81e22c060b54e8704b2d Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 12 May 2026 18:00:06 +0300 Subject: [PATCH 4/7] Store each package privilege in separate record --- src/jrd/ini.epp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index 11953e11d17..9a49c8ebd7e 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -404,7 +404,7 @@ namespace fb_assert(false); } - fb_assert(privileges && privileges[0] && (!privileges[1] || !privileges[2])); + fb_assert(privileges); const auto userName = getOwnerName(); fb_assert(userName && *userName); @@ -415,21 +415,23 @@ namespace for (unsigned i = 0; i < FB_NELEM(users); i++) { - STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES + for (const char* privilege = privileges; *privilege != '\0'; ++privilege) { - PAD(users[i], PRIV.RDB$USER); - PAD(SYSTEM_SCHEMA, PRIV.RDB$RELATION_SCHEMA_NAME); - PAD(objName, PRIV.RDB$RELATION_NAME); - PRIV.RDB$PRIVILEGE[0] = privileges[0]; - PRIV.RDB$PRIVILEGE[1] = privileges[1]; - PRIV.RDB$PRIVILEGE[2] = 0; - PRIV.RDB$GRANT_OPTION = grantOptions[i]; - PRIV.RDB$USER_TYPE = obj_user; - PRIV.RDB$OBJECT_TYPE = objType; - PRIV.RDB$GRANTOR.NULL = TRUE; + STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + { + PAD(users[i], PRIV.RDB$USER); + PAD(SYSTEM_SCHEMA, PRIV.RDB$RELATION_SCHEMA_NAME); + PAD(objName, PRIV.RDB$RELATION_NAME); + PRIV.RDB$PRIVILEGE[0] = *privilege; + PRIV.RDB$PRIVILEGE[1] = 0; + PRIV.RDB$GRANT_OPTION = grantOptions[i]; + PRIV.RDB$USER_TYPE = obj_user; + PRIV.RDB$OBJECT_TYPE = objType; + PRIV.RDB$GRANTOR.NULL = TRUE; + } + END_STORE } - END_STORE } } From 6402472be29b917966b938b64fa1e02321255a5e Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 12 May 2026 18:01:39 +0300 Subject: [PATCH 5/7] Allow all users to query constants from SYSTEM packages --- src/common/classes/vector.h | 5 +++++ src/jrd/ini.epp | 24 ++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/common/classes/vector.h b/src/common/classes/vector.h index dfa49ebac4f..6a04e8bc4e5 100644 --- a/src/common/classes/vector.h +++ b/src/common/classes/vector.h @@ -33,6 +33,7 @@ #include "../common/gdsassert.h" #include #include +#include namespace Firebird { @@ -42,6 +43,10 @@ class Vector { public: Vector() : count(0) {} + Vector(const std::initializer_list items) : count(0) + { + push(items.begin(), items.size()); + } T& operator[](FB_SIZE_T index) noexcept { diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index 9a49c8ebd7e..3849c86f91d 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -330,16 +330,20 @@ namespace const size_t ownerNameLength = ownerName.length(); fb_assert(ownerNameLength <= MAX_UCHAR); - const UCHAR privilege = package ? priv_execute : priv_usage; + Firebird::Vector NON_REL_OWNER_ACL + {ACL_priv_list, priv_control, priv_alter, priv_drop, priv_usage, ACL_end}; - const UCHAR NON_REL_OWNER_ACL[] = - {ACL_priv_list, priv_control, priv_alter, priv_drop, privilege, ACL_end}; + Firebird::Vector NON_REL_PUBLIC_ACL + {ACL_priv_list, priv_usage, ACL_end}; - const UCHAR NON_REL_PUBLIC_ACL[] = - {ACL_priv_list, privilege, ACL_end}; + if (package) + { + NON_REL_OWNER_ACL.insert(NON_REL_OWNER_ACL.getCount() - 2, priv_execute); + NON_REL_PUBLIC_ACL.insert(NON_REL_PUBLIC_ACL.getCount() - 2, priv_execute); + } fb_assert(sizeof(buffer) >= 8 + ownerNameLength + - sizeof(NON_REL_OWNER_ACL) + sizeof(NON_REL_PUBLIC_ACL)); + NON_REL_OWNER_ACL.getCount() + NON_REL_PUBLIC_ACL.getCount()); UCHAR* acl = buffer; *acl++ = ACL_version; @@ -352,14 +356,14 @@ namespace *acl++ = ACL_end; - memcpy(acl, NON_REL_OWNER_ACL, sizeof(NON_REL_OWNER_ACL)); - acl += sizeof(NON_REL_OWNER_ACL); + memcpy(acl, NON_REL_OWNER_ACL.begin(), NON_REL_OWNER_ACL.getCount()); + acl += NON_REL_OWNER_ACL.getCount(); *acl++ = ACL_id_list; *acl++ = ACL_end; - memcpy(acl, NON_REL_PUBLIC_ACL, sizeof(NON_REL_PUBLIC_ACL)); - acl += sizeof(NON_REL_PUBLIC_ACL); + memcpy(acl, NON_REL_PUBLIC_ACL.begin(), NON_REL_PUBLIC_ACL.getCount()); + acl += NON_REL_PUBLIC_ACL.getCount(); *acl++ = ACL_end; // Extra terminator to avoid scl.epp:walk_acl() missing the end From 42e68e8893a66d8f6d2eb4e4e3625333904c9e17 Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 12 May 2026 20:34:20 +0300 Subject: [PATCH 6/7] Use storeMetaDataBlob to store Source of Constant --- src/dsql/PackageNodes.epp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dsql/PackageNodes.epp b/src/dsql/PackageNodes.epp index 71cefa69ef6..fbbf75ccdab 100644 --- a/src/dsql/PackageNodes.epp +++ b/src/dsql/PackageNodes.epp @@ -679,7 +679,7 @@ void CreatePackageConstantNode::executeCreate(thread_db* tdbb, DsqlCompilerScrat CONST.RDB$PRIVATE_FLAG = m_isPrivate; - attachment->storeBinaryBlob(tdbb, transaction, &CONST.RDB$CONSTANT_SOURCE, source); + attachment->storeMetaDataBlob(tdbb, transaction, &CONST.RDB$CONSTANT_SOURCE, source); } END_STORE } From 98c1caaab64ecff2310c3ef095921be05989fea6 Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Wed, 13 May 2026 14:37:21 +0300 Subject: [PATCH 7/7] Remove unneccecery Firebird:: qualifier --- src/jrd/ini.epp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index 3849c86f91d..682805cbb88 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -330,10 +330,10 @@ namespace const size_t ownerNameLength = ownerName.length(); fb_assert(ownerNameLength <= MAX_UCHAR); - Firebird::Vector NON_REL_OWNER_ACL + Vector NON_REL_OWNER_ACL {ACL_priv_list, priv_control, priv_alter, priv_drop, priv_usage, ACL_end}; - Firebird::Vector NON_REL_PUBLIC_ACL + Vector NON_REL_PUBLIC_ACL {ACL_priv_list, priv_usage, ACL_end}; if (package)