From b44d11d081f533a61567d0038fadcd4681f3f052 Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Mon, 25 May 2026 10:36:57 +0300 Subject: [PATCH 1/5] Fix null values processing in constants --- src/dsql/PackageNodes.epp | 10 ++++++++-- src/jrd/Package.epp | 30 ++++++++++++++++++++++-------- src/jrd/Package.h | 3 +++ 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/dsql/PackageNodes.epp b/src/dsql/PackageNodes.epp index ae5b4a3981d..fc3975d9b82 100644 --- a/src/dsql/PackageNodes.epp +++ b/src/dsql/PackageNodes.epp @@ -474,6 +474,7 @@ void PackageReferenceNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) jrd_tra* transaction = dsqlScratch->getTransaction(); thread_db* tdbb = JRD_get_thread_data(); *desc = ConstantValue::getDesc(tdbb, transaction, m_fullName); + desc->setNullable(true); } bool PackageReferenceNode::constantExists(thread_db* tdbb, Jrd::jrd_tra* transaction, @@ -503,6 +504,7 @@ bool PackageReferenceNode::constantExists(thread_db* tdbb, Jrd::jrd_tra* transac void PackageReferenceNode::getDesc(thread_db* tdbb, CompilerScratch*, dsc* desc) { *desc = ConstantValue::getDesc(tdbb, tdbb->getTransaction(), m_fullName); + desc->setNullable(true); } ValueExprNode* PackageReferenceNode::copy(thread_db* tdbb, NodeCopier& copier) const @@ -550,7 +552,6 @@ ValueExprNode* PackageReferenceNode::pass2(thread_db* tdbb, CompilerScratch* csb dsc* PackageReferenceNode::execute(thread_db* tdbb, Request* request) const { - impure_value* outputImpure = request->getImpure(m_impureOffset); switch (m_itemType) { case blr_pkg_reference_to_constant: @@ -558,7 +559,12 @@ dsc* PackageReferenceNode::execute(thread_db* tdbb, Request* request) const Package* package = m_package(request->getResources()); package->checkReload(tdbb); - EVL_make_value(tdbb, package->findConstant(m_fullName)->makeValue(tdbb, request), outputImpure); + dsc* constantDsc = package->findConstant(m_fullName)->makeValue(tdbb, request); + if (constantDsc == nullptr || constantDsc->isNull()) + return nullptr; + + impure_value* outputImpure = request->getImpure(m_impureOffset); + EVL_make_value(tdbb, constantDsc, outputImpure); return &outputImpure->vlu_desc; } default: diff --git a/src/jrd/Package.epp b/src/jrd/Package.epp index 48af17131ea..11727c15052 100644 --- a/src/jrd/Package.epp +++ b/src/jrd/Package.epp @@ -156,12 +156,12 @@ dsc* ConstantValue::makeValue(thread_db* tdbb, Request* request) { { ReadLockGuard guard(m_makeValueLock, FB_FUNCTION); - if (m_value.vlu_desc.dsc_address != nullptr) + if (m_value.vlu_desc.dsc_dtype != 0) return &m_value.vlu_desc; } WriteLockGuard guard(m_makeValueLock, FB_FUNCTION); - if (m_value.vlu_desc.dsc_address != nullptr) // Extra check in case of two callers waiting + if (m_value.vlu_desc.dsc_dtype != 0) // Extra check in case of two callers waiting return &m_value.vlu_desc; Attachment* attachment = tdbb->getAttachment(); @@ -196,14 +196,11 @@ dsc* ConstantValue::makeValue(thread_db* tdbb, Request* request) TRA_attach_request(tdbb->getTransaction(), request); - const dsc* temp = EVL_expr(tdbb, request, static_cast(csb->csb_node)); - EVL_make_value(tdbb, temp, &m_value, &getPool()); + //! Execute it here, while AutoSetRestore2 is active + executeCsbNode(tdbb, csb); } else - { - const dsc* temp = EVL_expr(tdbb, request, static_cast(csb->csb_node)); - EVL_make_value(tdbb, temp, &m_value, &getPool()); - } + executeCsbNode(tdbb, csb); } catch (const Exception& ex) { @@ -226,6 +223,23 @@ dsc* ConstantValue::makeValue(thread_db* tdbb, Request* request) return &m_value.vlu_desc; } +void ConstantValue::executeCsbNode(thread_db* tdbb, CompilerScratch* csb) +{ + ValueExprNode* exprNode = static_cast(csb->csb_node); + fb_assert(exprNode); + + const dsc* temp = EVL_expr(tdbb, tdbb->getRequest(), exprNode); + if (temp != nullptr) + { + EVL_make_value(tdbb, temp, &m_value, &getPool()); + } + else + { + exprNode->getDesc(tdbb, csb, &m_value.vlu_desc); + m_value.vlu_desc.setNull(); + } +} + ConstantValue& ConstantsCache::add(const QualifiedName& constName, const bool isPrivate) { fb_assert(!nameMap.exist(constName)); diff --git a/src/jrd/Package.h b/src/jrd/Package.h index 2be4b2c89b2..182b2823ce5 100644 --- a/src/jrd/Package.h +++ b/src/jrd/Package.h @@ -38,6 +38,7 @@ namespace Jrd { +class CompilerScratch; class DsqlCompilerScratch; class dsql_fld; @@ -84,6 +85,8 @@ class ConstantValue final : public Firebird::PermanentStorage dsc* makeValue(thread_db* tdbb, Request* request); private: + void executeCsbNode(thread_db* tdbb, CompilerScratch* csb); + // Lock in case of makeing value during the execute state Firebird::RWLock m_makeValueLock{}; From 48de76b6cfe2b8f1d756e277741c5c74607467a2 Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Mon, 25 May 2026 10:37:28 +0300 Subject: [PATCH 2/5] Allow collate in constant declaration --- src/dsql/parse.y | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 8d66220d367..2790ed6209c 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -3338,10 +3338,11 @@ replace_package_body_clause %type package_const_item package_const_item - : symbol_package_const_name data_type_descriptor '=' value + : symbol_package_const_name data_type_descriptor collate_clause '=' value { - $$ = newNode(*$1, $2, $4); - $$->source = makeParseStr(YYPOSNARG(3), YYPOSNARG(4)); + setCollate($2, $3); + $$ = newNode(*$1, $2, $5); + $$->source = makeParseStr(YYPOSNARG(4), YYPOSNARG(5)); } ; From 897a1b9b7275870754f1787eb23771102762751f Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 26 May 2026 09:19:36 +0300 Subject: [PATCH 3/5] Correct `nullable` flag set for constant desc --- src/dsql/PackageNodes.epp | 2 -- src/jrd/Package.epp | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dsql/PackageNodes.epp b/src/dsql/PackageNodes.epp index fc3975d9b82..7fb168e7857 100644 --- a/src/dsql/PackageNodes.epp +++ b/src/dsql/PackageNodes.epp @@ -474,7 +474,6 @@ void PackageReferenceNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) jrd_tra* transaction = dsqlScratch->getTransaction(); thread_db* tdbb = JRD_get_thread_data(); *desc = ConstantValue::getDesc(tdbb, transaction, m_fullName); - desc->setNullable(true); } bool PackageReferenceNode::constantExists(thread_db* tdbb, Jrd::jrd_tra* transaction, @@ -504,7 +503,6 @@ bool PackageReferenceNode::constantExists(thread_db* tdbb, Jrd::jrd_tra* transac void PackageReferenceNode::getDesc(thread_db* tdbb, CompilerScratch*, dsc* desc) { *desc = ConstantValue::getDesc(tdbb, tdbb->getTransaction(), m_fullName); - desc->setNullable(true); } ValueExprNode* PackageReferenceNode::copy(thread_db* tdbb, NodeCopier& copier) const diff --git a/src/jrd/Package.epp b/src/jrd/Package.epp index 11727c15052..42be57df02c 100644 --- a/src/jrd/Package.epp +++ b/src/jrd/Package.epp @@ -84,8 +84,10 @@ dsc ConstantValue::getDesc(thread_db* tdbb, Jrd::jrd_tra* transaction, const Qua CSetId(FLD.RDB$CHARACTER_SET_ID), CollId(FLD.RDB$COLLATION_ID)); - if (!succeed) - (Arg::Gds(isc_bad_constant_desc) << Arg::Str(name.toQuotedString())).raise(); + if (!succeed) + (Arg::Gds(isc_bad_constant_desc) << Arg::Str(name.toQuotedString())).raise(); + + desc.setNullable(FLD.RDB$NULL_FLAG.NULL || FLD.RDB$NULL_FLAG == 0); } END_FOR From beda297c1f36bbc2e226a0feb6d6c4369a04d295 Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 26 May 2026 15:39:52 +0300 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Adriano dos Santos Fernandes <529415+asfernandes@users.noreply.github.com> --- src/jrd/Package.epp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jrd/Package.epp b/src/jrd/Package.epp index 42be57df02c..672737f8182 100644 --- a/src/jrd/Package.epp +++ b/src/jrd/Package.epp @@ -163,7 +163,7 @@ dsc* ConstantValue::makeValue(thread_db* tdbb, Request* request) } WriteLockGuard guard(m_makeValueLock, FB_FUNCTION); - if (m_value.vlu_desc.dsc_dtype != 0) // Extra check in case of two callers waiting + if (m_value.vlu_desc.dsc_dtype != dtype_unknown) // Extra check in case of two callers waiting return &m_value.vlu_desc; Attachment* attachment = tdbb->getAttachment(); From 1d7c2afca4f5d717066aea62d893646eda7e90b8 Mon Sep 17 00:00:00 2001 From: Artyom Abakumov Date: Tue, 26 May 2026 15:42:32 +0300 Subject: [PATCH 5/5] Add assert for csb_node kind when executing package constant Also use constant instead of 0 for dtype check --- src/jrd/Package.epp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jrd/Package.epp b/src/jrd/Package.epp index 672737f8182..4c40535b141 100644 --- a/src/jrd/Package.epp +++ b/src/jrd/Package.epp @@ -52,7 +52,7 @@ DATABASE DB = FILENAME "ODS.RDB"; bool ConstantValue::hash(thread_db* tdbb, Firebird::sha512& digest) const { - fb_assert(m_value.vlu_desc.dsc_dtype != 0); + fb_assert(m_value.vlu_desc.dsc_dtype != dtype_unknown); digest.process(sizeof(m_value.vlu_desc), &m_value.vlu_desc); return true; @@ -158,7 +158,7 @@ dsc* ConstantValue::makeValue(thread_db* tdbb, Request* request) { { ReadLockGuard guard(m_makeValueLock, FB_FUNCTION); - if (m_value.vlu_desc.dsc_dtype != 0) + if (m_value.vlu_desc.dsc_dtype != dtype_unknown) return &m_value.vlu_desc; } @@ -227,8 +227,8 @@ dsc* ConstantValue::makeValue(thread_db* tdbb, Request* request) void ConstantValue::executeCsbNode(thread_db* tdbb, CompilerScratch* csb) { + fb_assert(csb->csb_node && csb->csb_node->getKind() == DmlNode::KIND_VALUE); ValueExprNode* exprNode = static_cast(csb->csb_node); - fb_assert(exprNode); const dsc* temp = EVL_expr(tdbb, tdbb->getRequest(), exprNode); if (temp != nullptr)