diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index 0843f08a9eb..89fafdb074d 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -6470,7 +6470,7 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec // Use context to check conflicts beween . and . dsql_ctx packageContext(dsqlScratch->getPool()); - { // Consatnts + { // Constants QualifiedName constantName(dsqlName, dsqlQualifier.schema.hasData() ? dsqlQualifier.schema : dsqlScratch->package.schema, @@ -6480,7 +6480,9 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec { dsqlScratch->qualifyExistingName(constantName, obj_package_constant); - if (PackageReferenceNode::constantExists(tdbb, dsqlScratch->getTransaction(), constantName)) + dsc constantDsc{}; + auto transaction = dsqlScratch->getTransaction(); + if (PackageReferenceNode::constantExists(tdbb, transaction, constantName, &constantDsc)) { // Alias is a package name, not a constant packageContext.ctx_alias.push(QualifiedName(constantName.package, constantName.schema)); @@ -6488,7 +6490,8 @@ ValueExprNode* FieldNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, Rec ambiguousCtxStack.push(&packageContext); MemoryPool& pool = dsqlScratch->getPool(); - node = FB_NEW_POOL(pool) PackageReferenceNode(pool, constantName, blr_pkg_reference_to_constant); + node = FB_NEW_POOL(pool) PackageReferenceNode(pool, + constantName, blr_pkg_reference_to_constant, &constantDsc); } } } @@ -14243,11 +14246,12 @@ ValueExprNode* VariableNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { thread_db* tdbb = JRD_get_thread_data(); QualifiedName constantFullName(dsqlName, dsqlScratch->package.schema, dsqlScratch->package.object); - if (PackageReferenceNode::constantExists(tdbb, dsqlScratch->getTransaction(), constantFullName)) + dsc constantDsc{}; + if (PackageReferenceNode::constantExists(tdbb, dsqlScratch->getTransaction(), constantFullName, &constantDsc)) { delete node; return FB_NEW_POOL(dsqlScratch->getPool()) PackageReferenceNode(dsqlScratch->getPool(), - constantFullName, blr_pkg_reference_to_constant); + constantFullName, blr_pkg_reference_to_constant, &constantDsc); } } diff --git a/src/dsql/PackageNodes.epp b/src/dsql/PackageNodes.epp index dd57836cdc7..4803a360838 100644 --- a/src/dsql/PackageNodes.epp +++ b/src/dsql/PackageNodes.epp @@ -370,10 +370,14 @@ void PackageItemsHolder::clear() static RegisterNode regPackageReferenceNode({blr_package_reference}); -PackageReferenceNode::PackageReferenceNode(MemoryPool& pool, const QualifiedName& fullName, const UCHAR itemType) +PackageReferenceNode::PackageReferenceNode(MemoryPool& pool, const QualifiedName& fullName, const UCHAR itemType, + const dsc* type) : TypedNode(pool), m_fullName(fullName), m_itemType(itemType) -{} +{ + if (type) + m_cachedDsc = *type; +} string PackageReferenceNode::internalPrint(NodePrinter& printer) const { @@ -392,7 +396,7 @@ ValueExprNode* PackageReferenceNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) thread_db* tdbb = JRD_get_thread_data(); bool isPrivate = false; - if (constantExists(tdbb, transaction, m_fullName, &isPrivate)) + if (constantExists(tdbb, transaction, m_fullName, &m_cachedDsc, &isPrivate)) { // External objects do not have access to private constants if (isPrivate) @@ -407,8 +411,7 @@ ValueExprNode* PackageReferenceNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) Arg::Str(m_fullName.toQuotedString())); } - auto* node = FB_NEW_POOL(pool) PackageReferenceNode(pool, m_fullName, m_itemType); - return node; + return FB_NEW_POOL(pool) PackageReferenceNode(pool, m_fullName, m_itemType, &m_cachedDsc); } DmlNode* PackageReferenceNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR) @@ -434,20 +437,23 @@ DmlNode* PackageReferenceNode::parse(thread_db* tdbb, MemoryPool& pool, Compiler csb->addDependency(dependency); } + ConstantValue* constant = nullptr; { // Package cache auto package = MetadataCache::getVersioned(tdbb, fullName.getSchemaAndPackage(), CacheFlag::AUTOCREATE); if (package) { node->m_package = csb->csb_resources->packages.registerResource(package->getPermanent()); + constant = package->findConstant(fullName); } } - if (!node->m_package) + if (constant == nullptr) { status_exception::raise(Arg::Gds(isc_bad_constant_name) << Arg::Str(fullName.toQuotedString())); } + node->m_cachedDsc = constant->getDesc(); return node; } // TODO: rowtype @@ -474,13 +480,12 @@ void PackageReferenceNode::setParameterName(dsql_par* parameter) const 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); + fb_assert(m_cachedDsc.dsc_dtype != dtype_unknown); + *desc = m_cachedDsc; } bool PackageReferenceNode::constantExists(thread_db* tdbb, Jrd::jrd_tra* transaction, - const QualifiedName& fullName, bool* isPrivate) + const QualifiedName& fullName, dsc* outConstantDesc, bool* isPrivate) { if (fullName.package.isEmpty() || fullName.object.isEmpty()) return false; @@ -500,18 +505,22 @@ bool PackageReferenceNode::constantExists(thread_db* tdbb, Jrd::jrd_tra* transac if (isPrivate) *isPrivate = value->isPrivate; + if (outConstantDesc) + *outConstantDesc = value->getDesc(); + return true; } -void PackageReferenceNode::getDesc(thread_db* tdbb, CompilerScratch*, dsc* desc) +void PackageReferenceNode::getDesc(thread_db*, CompilerScratch*, dsc* desc) { - *desc = ConstantValue::getDesc(tdbb, tdbb->getTransaction(), m_fullName); + fb_assert(m_cachedDsc.dsc_dtype != dtype_unknown); + *desc = m_cachedDsc; } ValueExprNode* PackageReferenceNode::copy(thread_db* tdbb, NodeCopier& copier) const { MemoryPool& pool = *tdbb->getDefaultPool(); - auto* node = FB_NEW_POOL(pool) PackageReferenceNode(pool, m_fullName, m_itemType); + auto* node = FB_NEW_POOL(pool) PackageReferenceNode(pool, m_fullName, m_itemType, &m_cachedDsc); node->m_package = copier.csb->csb_resources->packages.registerResource(m_package()); diff --git a/src/dsql/PackageNodes.h b/src/dsql/PackageNodes.h index b6edd07f23b..d62dcb1ed09 100644 --- a/src/dsql/PackageNodes.h +++ b/src/dsql/PackageNodes.h @@ -124,7 +124,7 @@ class PackageReferenceNode final : public TypedNode m_package; const QualifiedName m_fullName; + dsc m_cachedDsc = {}; const UCHAR m_itemType; ULONG m_impureOffset = 0; diff --git a/src/jrd/Package.epp b/src/jrd/Package.epp index 405c22f416e..d2a2f5baf33 100644 --- a/src/jrd/Package.epp +++ b/src/jrd/Package.epp @@ -55,8 +55,8 @@ static_assert(DSC_SIZE_TO_HASH - offsetof(dsc, dsc_flags) == sizeof(dsc::dsc_fla bool ConstantValue::hash(thread_db* tdbb, Firebird::sha512& digest) const { - fb_assert(m_value.vlu_desc.dsc_dtype != dtype_unknown); - digest.process(DSC_SIZE_TO_HASH, &m_value.vlu_desc); + fb_assert(m_type.dsc_dtype != dtype_unknown); + digest.process(DSC_SIZE_TO_HASH, &m_type); // The value hashing is unneccecery as Alex Peshkoff explained // See https://groups.google.com/g/firebird-devel/c/xIxhL_QAjEg/m/9RGT47ugAwAJ @@ -72,46 +72,6 @@ bool ConstantValue::hash(thread_db* tdbb, Firebird::sha512& digest) const return true; } -dsc ConstantValue::getDesc(thread_db* tdbb, Jrd::jrd_tra* transaction, const QualifiedName& name) -{ - dsc desc{}; - bool found = false; - - FbLocalStatus status; - static const CachedRequestId requestId; - AutoCacheRequest getConstantDscRequest(tdbb, requestId); - FOR(REQUEST_HANDLE getConstantDscRequest TRANSACTION_HANDLE transaction) - CONST IN RDB$CONSTANTS CROSS FLD IN RDB$FIELDS - WITH CONST.RDB$SCHEMA_NAME EQ name.schema.c_str() AND - CONST.RDB$PACKAGE_NAME EQ name.package.c_str() AND - CONST.RDB$CONSTANT_NAME EQ name.object.c_str() AND - FLD.RDB$SCHEMA_NAME EQ CONST.RDB$FIELD_SOURCE_SCHEMA_NAME AND - FLD.RDB$FIELD_NAME EQ CONST.RDB$FIELD_SOURCE - { - found = true; - - const bool succeed = DSC_make_descriptor(&desc, - FLD.RDB$FIELD_TYPE, - FLD.RDB$FIELD_SCALE, - FLD.RDB$FIELD_LENGTH, - FLD.RDB$FIELD_SUB_TYPE, - CSetId(FLD.RDB$CHARACTER_SET_ID), - CollId(FLD.RDB$COLLATION_ID)); - - 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 - - if (!found) - (Arg::Gds(isc_bad_constant_name) << Arg::Str(name.toQuotedString())).raise(); - - return desc; -} - void ConstantValue::genConstantBlr(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, ValueExprNode* constExpr, dsql_fld* type, const MetaName& schema) { @@ -251,7 +211,7 @@ void ConstantValue::executeCsbNode(thread_db* tdbb, CompilerScratch* csb) } else { - exprNode->getDesc(tdbb, csb, &m_value.vlu_desc); + m_value.vlu_desc = m_type; m_value.vlu_desc.setNull(); } } @@ -330,27 +290,8 @@ ScanResult Package::scan(thread_db* tdbb, ObjectBase::Flag flags) END_FOR } - { // Constants - static const CachedRequestId requestId; - AutoCacheRequest requestConst(tdbb, requestId); - - FOR(REQUEST_HANDLE requestConst TRANSACTION_HANDLE metaTransaction) - PKG IN RDB$PACKAGES CROSS CONST IN RDB$CONSTANTS - WITH PKG.RDB$PACKAGE_ID EQ getId() AND - PKG.RDB$PACKAGE_NAME EQ CONST.RDB$PACKAGE_NAME AND - PKG.RDB$SCHEMA_NAME EQ CONST.RDB$SCHEMA_NAME - { - addConstant(tdbb, - QualifiedName(CONST.RDB$CONSTANT_NAME, CONST.RDB$SCHEMA_NAME, CONST.RDB$PACKAGE_NAME), - CONST.RDB$PRIVATE_FLAG != 0, - CONST.RDB$CONSTANT_BLR, - skipMakeValue); - - if (skipMakeValue) - this->m_callReload = true; // Value is necessary for to calculate hash - } - END_FOR - } + fb_assert(constants.values.isEmpty()); + collectConstants(tdbb, skipMakeValue); return this->m_callReload ? ScanResult::REPEAT : ScanResult::COMPLETE; } @@ -373,18 +314,7 @@ ScanResult Package::reload(thread_db* tdbb, ObjectBase::Flag fl) AutoCacheRequest requestConst(tdbb, requestId); constants.clear(); - FOR(REQUEST_HANDLE requestConst TRANSACTION_HANDLE metaTransaction) - PKG IN RDB$PACKAGES CROSS CONST IN RDB$CONSTANTS - WITH PKG.RDB$PACKAGE_ID EQ getId() AND - PKG.RDB$PACKAGE_NAME EQ CONST.RDB$PACKAGE_NAME AND - PKG.RDB$SCHEMA_NAME EQ CONST.RDB$SCHEMA_NAME - { - addConstant(tdbb, - QualifiedName(CONST.RDB$CONSTANT_NAME, CONST.RDB$SCHEMA_NAME, CONST.RDB$PACKAGE_NAME), - CONST.RDB$PRIVATE_FLAG != 0, - CONST.RDB$CONSTANT_BLR); - } - END_FOR + collectConstants(tdbb, false); m_callReload = false; return ScanResult::COMPLETE; @@ -412,7 +342,7 @@ ConstantValue& Package::addConstant(thread_db* tdbb, DsqlDescMaker::fromField(&typeDesc, type); auto& value = constants.add(constName, isPrivate); - value.updateValue(typeDesc); + value.setType(typeDesc); return value; } @@ -420,11 +350,13 @@ ConstantValue& Package::addConstant(thread_db* tdbb, ConstantValue& Package::addConstant(thread_db* tdbb, const QualifiedName& constName, const bool isPrivate, + const dsc type, const bid blrBlobId, const bool skipMakeValue) { auto& value = constants.add(constName, isPrivate); - value.updateValue(blrBlobId); + value.setType(type); + value.setValue(blrBlobId); if (!skipMakeValue) value.makeValue(tdbb, nullptr); @@ -443,7 +375,7 @@ ConstantValue& Package::updateConstant(thread_db* tdbb, const QualifiedName& nam auto& constant = constants.values[*innerId]; constant.isPrivate = isPrivate; - constant.updateValue(typeDesc); + constant.setType(typeDesc); return constant; } @@ -457,3 +389,52 @@ ConstantValue* Package::findConstant(const QualifiedName& name) return nullptr; } + +void Package::collectConstants(thread_db* tdbb, const bool skipMakingValue) +{ + Attachment* attachment = tdbb->getAttachment(); + jrd_tra* metaTransaction = attachment->getMetaTransaction(tdbb); + Database* dbb = tdbb->getDatabase(); + + MemoryPool& pool = getPermanent()->getPool(); + + static const CachedRequestId requestId; + AutoCacheRequest requestConst(tdbb, requestId); + FOR(REQUEST_HANDLE requestConst TRANSACTION_HANDLE metaTransaction) + PKG IN RDB$PACKAGES + CROSS CONST IN RDB$CONSTANTS + CROSS FLD IN RDB$FIELDS + WITH PKG.RDB$PACKAGE_ID EQ getId() AND + PKG.RDB$PACKAGE_NAME EQ CONST.RDB$PACKAGE_NAME AND + PKG.RDB$SCHEMA_NAME EQ CONST.RDB$SCHEMA_NAME AND + FLD.RDB$SCHEMA_NAME EQ CONST.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ CONST.RDB$FIELD_SOURCE + { + QualifiedName name(CONST.RDB$CONSTANT_NAME, CONST.RDB$SCHEMA_NAME, CONST.RDB$PACKAGE_NAME); + + dsc constantType{}; + const bool succeed = DSC_make_descriptor(&constantType, + FLD.RDB$FIELD_TYPE, + FLD.RDB$FIELD_SCALE, + FLD.RDB$FIELD_LENGTH, + FLD.RDB$FIELD_SUB_TYPE, + CSetId(FLD.RDB$CHARACTER_SET_ID), + CollId(FLD.RDB$COLLATION_ID)); + + if (!succeed) + (Arg::Gds(isc_bad_constant_desc) << Arg::Str(name.toQuotedString())).raise(); + + constantType.setNullable(FLD.RDB$NULL_FLAG.NULL || FLD.RDB$NULL_FLAG == 0); + + addConstant(tdbb, + name, + CONST.RDB$PRIVATE_FLAG != 0, + constantType, + CONST.RDB$CONSTANT_BLR, + skipMakingValue); + + if (skipMakingValue) + this->m_callReload = true; // Value is necessary to calculate hash + } + END_FOR +} diff --git a/src/jrd/Package.h b/src/jrd/Package.h index 182b2823ce5..6dac86fc828 100644 --- a/src/jrd/Package.h +++ b/src/jrd/Package.h @@ -60,24 +60,30 @@ class ConstantValue final : public Firebird::PermanentStorage bool hash(thread_db* tdbb, Firebird::sha512& digest) const; - static dsc getDesc(thread_db* tdbb, Jrd::jrd_tra* transaction, const QualifiedName& name); - static void genConstantBlr(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, ValueExprNode* constExpr, dsql_fld* type, const MetaName& schema); - - void updateValue(const dsc typeDesc) + void setType(const dsc typeDesc) { + m_type = typeDesc; m_blrBlobId = {}; delete m_value.vlu_string; m_value = {}; - m_value.vlu_desc = typeDesc; } - void updateValue(const bid blobId) + void setValue(const bid blobId) { m_blrBlobId = blobId; + + delete m_value.vlu_string; + m_value = {}; + } + + inline dsc getDesc() const noexcept + { + fb_assert(m_type.dsc_dtype != dtype_unknown); + return m_type; } bid getBlobId(thread_db* tdbb); @@ -90,8 +96,12 @@ class ConstantValue final : public Firebird::PermanentStorage // Lock in case of makeing value during the execute state Firebird::RWLock m_makeValueLock{}; - // Keep type to gen hash (when not commited - we cannot read it from system table) - // Keep value when scanning and after the first execution + // The constant type and constant value type may differed + // For example, the the defiend type is int but value type is short) + // So keep it explicit + dsc m_type{}; + + // Get the value when scanning (without MINISCAN) or after the first execution impure_value m_value{}; // keep only materialized value @@ -233,6 +243,7 @@ class Package final : public Firebird::PermanentStorage, public ObjectBase ConstantValue& addConstant(thread_db* tdbb, const QualifiedName& constName, const bool isPrivate, + const dsc type, const bid blrBlobId, const bool skipMakeValue = false); @@ -244,6 +255,8 @@ class Package final : public Firebird::PermanentStorage, public ObjectBase ConstantValue* findConstant(const QualifiedName& name); private: + void collectConstants(thread_db* tdbb, const bool skipMakingValue); + virtual ~Package() = default; private: diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 7730eb98726..52cdbb335e0 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -817,11 +817,14 @@ Cached::Relation* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const Package* package = nullptr; FOR(REQUEST_HANDLE request) - DEP IN RDB$DEPENDENCIES CROSS - CONST IN RDB$CONSTANTS CROSS - PKG IN RDB$PACKAGES + DEP IN RDB$DEPENDENCIES + CROSS CONST IN RDB$CONSTANTS + CROSS FLD IN RDB$FIELDS + CROSS PKG IN RDB$PACKAGES WITH PKG.RDB$SCHEMA_NAME EQ schemaName->dsc_address AND PKG.RDB$PACKAGE_NAME EQ CONST.RDB$PACKAGE_NAME AND + FLD.RDB$SCHEMA_NAME EQ CONST.RDB$FIELD_SOURCE_SCHEMA_NAME AND + FLD.RDB$FIELD_NAME EQ CONST.RDB$FIELD_SOURCE AND DEP.RDB$DEPENDED_ON_SCHEMA_NAME EQ schemaName->dsc_address AND DEP.RDB$DEPENDED_ON_NAME EQ fieldSource->dsc_address AND DEP.RDB$DEPENDED_ON_TYPE EQ obj_field AND @@ -843,7 +846,19 @@ Cached::Relation* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const fb_assert(package); } - package->addConstant(tdbb, constantFullName, CONST.RDB$PRIVATE_FLAG != 0, CONST.RDB$CONSTANT_BLR); + dsc constantType{}; + const bool succeed = DSC_make_descriptor(&constantType, + FLD.RDB$FIELD_TYPE, + FLD.RDB$FIELD_SCALE, + FLD.RDB$FIELD_LENGTH, + FLD.RDB$FIELD_SUB_TYPE, + CSetId(FLD.RDB$CHARACTER_SET_ID), + CollId(FLD.RDB$COLLATION_ID)); + + if (!succeed) + (Arg::Gds(isc_bad_constant_desc) << Arg::Str(constantFullName.toQuotedString())).raise(); + + package->addConstant(tdbb, constantFullName, CONST.RDB$PRIVATE_FLAG != 0, constantType, CONST.RDB$CONSTANT_BLR); } END_FOR @@ -5514,8 +5529,8 @@ std::optional MET_qualify_existing_name(thread_db* tdbb, QualifiedNa case obj_package_constant: { - static const CachedRequestId consatntHandleId; - handle.reset(tdbb, consatntHandleId); + static const CachedRequestId constantHandleId; + handle.reset(tdbb, constantHandleId); FOR (REQUEST_HANDLE handle) CONST IN RDB$CONSTANTS