/* * The contents of this file are subject to the Initial * Developer's Public License Version 1.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. * * Software distributed under the License is distributed AS IS, * WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the License for the specific language governing rights * and limitations under the License. * * The Original Code was created by Adriano dos Santos Fernandes * for the Firebird Open Source RDBMS project. * * Copyright (c) 2009 Adriano dos Santos Fernandes * and all contributors signed below. * * All Rights Reserved. * Contributor(s): ______________________________________. */ #include "firebird.h" #include "../dsql/PackageNodes.h" #include "../jrd/dyn.h" #include "../jrd/intl.h" #include "../jrd/jrd.h" #include "../jrd/tra.h" #include "../jrd/dfw_proto.h" #include "../jrd/exe_proto.h" #include "../jrd/met_proto.h" #include "../jrd/vio_proto.h" #include "../dsql/make_proto.h" #include "../dsql/pass1_proto.h" #include "../common/StatusArg.h" #include "../jrd/Attachment.h" using namespace Firebird; namespace Jrd { using namespace Firebird; DATABASE DB = STATIC "ODS.RDB"; //---------------------- namespace { struct ParameterInfo { explicit ParameterInfo(MemoryPool& p) : type(0), number(0), name(p), fieldSource(p), fieldName(p), relationName(p), mechanism(0) { defaultSource.clear(); defaultValue.clear(); } ParameterInfo(MemoryPool& p, const ParameterInfo& o) : type(o.type), number(o.number), name(p, o.name), fieldSource(p, o.fieldSource), fieldName(p, o.fieldName), relationName(p, o.relationName), collationId(o.collationId), nullFlag(o.nullFlag), mechanism(o.mechanism), fieldLength(o.fieldLength), fieldScale(o.fieldScale), fieldType(o.fieldType), fieldSubType(o.fieldSubType), fieldSegmentLength(o.fieldSegmentLength), fieldNullFlag(o.fieldNullFlag), fieldCharLength(o.fieldCharLength), fieldCollationId(o.fieldCollationId), fieldCharSetId(o.fieldCharSetId), fieldPrecision(o.fieldPrecision), defaultSource(o.defaultSource), defaultValue(o.defaultValue) { } SSHORT type; SSHORT number; MetaName name; MetaName fieldSource; MetaName fieldName; MetaName relationName; Nullable collationId; Nullable nullFlag; SSHORT mechanism; Nullable fieldLength; Nullable fieldScale; Nullable fieldType; Nullable fieldSubType; Nullable fieldSegmentLength; Nullable fieldNullFlag; Nullable fieldCharLength; Nullable fieldCollationId; Nullable fieldCharSetId; Nullable fieldPrecision; // Not compared bid defaultSource; bid defaultValue; bool operator >(const ParameterInfo& o) const { return type > o.type || (type == o.type && number > o.number); } bool operator ==(const ParameterInfo& o) const { return type == o.type && number == o.number && name == o.name && (fieldSource == o.fieldSource || (fb_utils::implicit_domain(fieldSource.c_str()) && fb_utils::implicit_domain(o.fieldSource.c_str()))) && fieldName == o.fieldName && relationName == o.relationName && collationId == o.collationId && nullFlag == o.nullFlag && mechanism == o.mechanism && fieldLength == o.fieldLength && fieldScale == o.fieldScale && fieldType == o.fieldType && fieldSubType == o.fieldSubType && fieldSegmentLength == o.fieldSegmentLength && fieldNullFlag == o.fieldNullFlag && fieldCharLength == o.fieldCharLength && fieldCollationId == o.fieldCollationId && fieldCharSetId == o.fieldCharSetId && fieldPrecision == o.fieldPrecision; } bool operator !=(const ParameterInfo& o) const { return !(*this == o); } }; struct Signature { Signature(MemoryPool& p, const MetaName& aName) : name(p, aName), parameters(p), defined(false) { } explicit Signature(const MetaName& aName) : name(aName), parameters(*getDefaultMemoryPool()), defined(false) { } explicit Signature(MemoryPool& p) : name(p), parameters(p), defined(false) { } Signature(MemoryPool& p, const Signature& o) : name(p, o.name), parameters(p), defined(o.defined) { for (SortedObjectsArray::const_iterator i = o.parameters.begin(); i != o.parameters.end(); ++i) { parameters.add(*i); } } bool operator >(const Signature& o) const { return name > o.name; } bool operator ==(const Signature& o) const { if (name != o.name || parameters.getCount() != o.parameters.getCount()) return false; for (SortedObjectsArray::const_iterator i = parameters.begin(), j = o.parameters.begin(); i != parameters.end(); ++i, ++j) { if (*i != *j) return false; } return true; } bool operator !=(const Signature& o) const { return !(*this == o); } MetaName name; SortedObjectsArray parameters; bool defined; }; // Return function and procedure names (in the user charset) and optionally its details for a // given package. void collectPackagedItems(thread_db* tdbb, jrd_tra* transaction, const MetaName& metaName, SortedObjectsArray& functions, SortedObjectsArray& procedures, bool details) { AutoCacheRequest requestHandle(tdbb, drq_l_pkg_funcs, DYN_REQUESTS); AutoCacheRequest requestHandle2(tdbb, drq_l_pkg_func_args, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS WITH FUN.RDB$PACKAGE_NAME EQ metaName.c_str() { Signature function(FUN.RDB$FUNCTION_NAME); function.defined = !FUN.RDB$FUNCTION_BLR.NULL || !FUN.RDB$ENTRYPOINT.NULL; if (details) { FOR (REQUEST_HANDLE requestHandle2 TRANSACTION_HANDLE transaction) ARG IN RDB$FUNCTION_ARGUMENTS CROSS FLD IN RDB$FIELDS WITH ARG.RDB$PACKAGE_NAME EQ metaName.c_str() AND ARG.RDB$FUNCTION_NAME EQ FUN.RDB$FUNCTION_NAME AND FLD.RDB$FIELD_NAME EQ ARG.RDB$FIELD_SOURCE { ParameterInfo parameter(*getDefaultMemoryPool()); parameter.number = ARG.RDB$ARGUMENT_POSITION; parameter.name = ARG.RDB$ARGUMENT_NAME; parameter.fieldSource = ARG.RDB$FIELD_SOURCE; parameter.mechanism = ARG.RDB$ARGUMENT_MECHANISM; if (!ARG.RDB$FIELD_NAME.NULL) parameter.fieldName = ARG.RDB$FIELD_NAME; if (!ARG.RDB$RELATION_NAME.NULL) parameter.relationName = ARG.RDB$RELATION_NAME; if (!ARG.RDB$COLLATION_ID.NULL) parameter.collationId = ARG.RDB$COLLATION_ID; if (!ARG.RDB$NULL_FLAG.NULL) parameter.nullFlag = ARG.RDB$NULL_FLAG; if (!FLD.RDB$FIELD_LENGTH.NULL) parameter.fieldLength = FLD.RDB$FIELD_LENGTH; if (!FLD.RDB$FIELD_SCALE.NULL) parameter.fieldScale = FLD.RDB$FIELD_SCALE; if (!FLD.RDB$FIELD_TYPE.NULL) parameter.fieldType = FLD.RDB$FIELD_TYPE; if (!FLD.RDB$FIELD_SUB_TYPE.NULL) parameter.fieldSubType = FLD.RDB$FIELD_SUB_TYPE; if (!FLD.RDB$SEGMENT_LENGTH.NULL) parameter.fieldSegmentLength = FLD.RDB$SEGMENT_LENGTH; if (!FLD.RDB$NULL_FLAG.NULL) parameter.fieldNullFlag = FLD.RDB$NULL_FLAG; if (!FLD.RDB$CHARACTER_LENGTH.NULL) parameter.fieldCharLength = FLD.RDB$CHARACTER_LENGTH; if (!FLD.RDB$COLLATION_ID.NULL) parameter.fieldCollationId = FLD.RDB$COLLATION_ID; if (!FLD.RDB$CHARACTER_SET_ID.NULL) parameter.fieldCharSetId = FLD.RDB$CHARACTER_SET_ID; if (!FLD.RDB$FIELD_PRECISION.NULL) parameter.fieldPrecision = FLD.RDB$FIELD_PRECISION; if (!ARG.RDB$DEFAULT_SOURCE.NULL) parameter.defaultSource = ARG.RDB$DEFAULT_SOURCE; if (!ARG.RDB$DEFAULT_VALUE.NULL) parameter.defaultValue = ARG.RDB$DEFAULT_VALUE; function.parameters.add(parameter); } END_FOR } functions.add(function); } END_FOR requestHandle.reset(tdbb, drq_l_pkg_procs, DYN_REQUESTS); requestHandle2.reset(tdbb, drq_l_pkg_proc_args, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRC IN RDB$PROCEDURES WITH PRC.RDB$PACKAGE_NAME EQ metaName.c_str() { Signature procedure(PRC.RDB$PROCEDURE_NAME); procedure.defined = !PRC.RDB$PROCEDURE_BLR.NULL || !PRC.RDB$ENTRYPOINT.NULL; if (details) { FOR (REQUEST_HANDLE requestHandle2 TRANSACTION_HANDLE transaction) PRM IN RDB$PROCEDURE_PARAMETERS CROSS FLD IN RDB$FIELDS WITH PRM.RDB$PACKAGE_NAME EQ metaName.c_str() AND PRM.RDB$PROCEDURE_NAME EQ PRC.RDB$PROCEDURE_NAME AND FLD.RDB$FIELD_NAME EQ PRM.RDB$FIELD_SOURCE { ParameterInfo parameter(*getDefaultMemoryPool()); parameter.type = PRM.RDB$PARAMETER_TYPE; parameter.number = PRM.RDB$PARAMETER_NUMBER; parameter.name = PRM.RDB$PARAMETER_NAME; parameter.fieldSource = PRM.RDB$FIELD_SOURCE; parameter.mechanism = PRM.RDB$PARAMETER_MECHANISM; if (!PRM.RDB$FIELD_NAME.NULL) parameter.fieldName = PRM.RDB$FIELD_NAME; if (!PRM.RDB$RELATION_NAME.NULL) parameter.relationName = PRM.RDB$RELATION_NAME; if (!PRM.RDB$COLLATION_ID.NULL) parameter.collationId = PRM.RDB$COLLATION_ID; if (!PRM.RDB$NULL_FLAG.NULL) parameter.nullFlag = PRM.RDB$NULL_FLAG; if (!FLD.RDB$FIELD_LENGTH.NULL) parameter.fieldLength = FLD.RDB$FIELD_LENGTH; if (!FLD.RDB$FIELD_SCALE.NULL) parameter.fieldScale = FLD.RDB$FIELD_SCALE; if (!FLD.RDB$FIELD_TYPE.NULL) parameter.fieldType = FLD.RDB$FIELD_TYPE; if (!FLD.RDB$FIELD_SUB_TYPE.NULL) parameter.fieldSubType = FLD.RDB$FIELD_SUB_TYPE; if (!FLD.RDB$SEGMENT_LENGTH.NULL) parameter.fieldSegmentLength = FLD.RDB$SEGMENT_LENGTH; if (!FLD.RDB$NULL_FLAG.NULL) parameter.fieldNullFlag = FLD.RDB$NULL_FLAG; if (!FLD.RDB$CHARACTER_LENGTH.NULL) parameter.fieldCharLength = FLD.RDB$CHARACTER_LENGTH; if (!FLD.RDB$COLLATION_ID.NULL) parameter.fieldCollationId = FLD.RDB$COLLATION_ID; if (!FLD.RDB$CHARACTER_SET_ID.NULL) parameter.fieldCharSetId = FLD.RDB$CHARACTER_SET_ID; if (!FLD.RDB$FIELD_PRECISION.NULL) parameter.fieldPrecision = FLD.RDB$FIELD_PRECISION; if (!PRM.RDB$DEFAULT_SOURCE.NULL) parameter.defaultSource = PRM.RDB$DEFAULT_SOURCE; if (!PRM.RDB$DEFAULT_VALUE.NULL) parameter.defaultValue = PRM.RDB$DEFAULT_VALUE; procedure.parameters.add(parameter); } END_FOR } procedures.add(procedure); } END_FOR } } // namespace //---------------------- void CreateAlterPackageNode::print(string& text) const { fb_assert(items); text.printf( "CreateAlterPackageNode\n" " name: '%s' create: %d alter: %d\n" " Items:\n" "--------\n", name.c_str(), create, alter); for (unsigned i = 0; i < items->getCount(); ++i) { string item; switch ((*items)[i].type) { case Item::FUNCTION: (*items)[i].function->print(item); break; case Item::PROCEDURE: (*items)[i].procedure->print(item); break; } text += item; } text += "--------\n"; } DdlNode* CreateAlterPackageNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { source.ltrim("\n\r\t "); // items for (unsigned i = 0; i < items->getCount(); ++i) { DsqlCompiledStatement* itemStatement = FB_NEW(getPool()) DsqlCompiledStatement(getPool()); DsqlCompilerScratch* itemScratch = (*items)[i].dsqlScratch = FB_NEW(getPool()) DsqlCompilerScratch(getPool(), dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), itemStatement); itemScratch->clientDialect = dsqlScratch->clientDialect; itemScratch->package = name; switch ((*items)[i].type) { case CreateAlterPackageNode::Item::FUNCTION: { CreateAlterFunctionNode* const fun = (*items)[i].function; functionNames.add(fun->name); fun->alter = true; fun->package = name; fun->dsqlPass(itemScratch); } break; case CreateAlterPackageNode::Item::PROCEDURE: { CreateAlterProcedureNode* const proc = (*items)[i].procedure; procedureNames.add(proc->name); proc->alter = true; proc->package = name; proc->dsqlPass(itemScratch); } break; } } return DdlNode::dsqlPass(dsqlScratch); } void CreateAlterPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { fb_assert(create || alter); //Database* dbb = tdbb->getDatabase(); //dbb->checkOdsForDsql(ODS_12_0); // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); if (alter) { if (!executeAlter(tdbb, dsqlScratch, transaction)) { if (create) // create or alter executeCreate(tdbb, dsqlScratch, transaction); else { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name)); } } } else executeCreate(tdbb, dsqlScratch, transaction); // items for (unsigned i = 0; i < items->getCount(); ++i) { switch ((*items)[i].type) { case Item::FUNCTION: (*items)[i].function->packageOwner = owner; (*items)[i].function->executeDdl(tdbb, (*items)[i].dsqlScratch, transaction); break; case Item::PROCEDURE: (*items)[i].procedure->packageOwner = owner; (*items)[i].procedure->executeDdl(tdbb, (*items)[i].dsqlScratch, transaction); break; } } savePoint.release(); // everything is ok } void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { Attachment* attachment = transaction->getAttachment(); const string& userName = attachment->att_user->usr_user_name; executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_PACKAGE, name); AutoCacheRequest requestHandle(tdbb, drq_s_pkg, DYN_REQUESTS); STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES USING { PKG.RDB$PACKAGE_NAME.NULL = FALSE; strcpy(PKG.RDB$PACKAGE_NAME, name.c_str()); PKG.RDB$SYSTEM_FLAG.NULL = FALSE; PKG.RDB$SYSTEM_FLAG = 0; PKG.RDB$OWNER_NAME.NULL = FALSE; strcpy(PKG.RDB$OWNER_NAME, userName.c_str()); PKG.RDB$PACKAGE_HEADER_SOURCE.NULL = FALSE; attachment->storeMetaDataBlob(tdbb, transaction, &PKG.RDB$PACKAGE_HEADER_SOURCE, source); } END_STORE storePrivileges(tdbb, transaction, name, obj_package_header, EXEC_PRIVILEGES); owner = userName; executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_PACKAGE, name); } bool CreateAlterPackageNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { Attachment* attachment = transaction->getAttachment(); AutoCacheRequest requestHandle(tdbb, drq_m_pkg, DYN_REQUESTS); bool modified = false; FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES WITH PKG.RDB$PACKAGE_NAME EQ name.c_str() { modified = true; executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_PACKAGE, name); SortedObjectsArray existingFuncs(getPool()); SortedObjectsArray existingProcs(getPool()); collectPackagedItems(tdbb, transaction, name, existingFuncs, existingProcs, false); for (SortedObjectsArray::iterator i = existingFuncs.begin(); i != existingFuncs.end(); ++i) { if (!functionNames.exist(i->name)) { DropFunctionNode dropNode(getPool(), i->name); dropNode.package = name; dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction); } } for (SortedObjectsArray::iterator i = existingProcs.begin(); i != existingProcs.end(); ++i) { if (!procedureNames.exist(i->name)) { DropProcedureNode dropNode(getPool(), i->name); dropNode.package = name; dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction); } } MODIFY PKG PKG.RDB$PACKAGE_HEADER_SOURCE.NULL = FALSE; attachment->storeMetaDataBlob(tdbb, transaction, &PKG.RDB$PACKAGE_HEADER_SOURCE, source); PKG.RDB$PACKAGE_BODY_SOURCE.NULL = TRUE; END_MODIFY owner = PKG.RDB$OWNER_NAME; } END_FOR if (modified) executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_ALTER_PACKAGE, name); return modified; } //---------------------- void DropPackageNode::print(string& text) const { text.printf( "DropPackageNode\n" " name: '%s'\n", name.c_str()); } void DropPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); bool found = false; AutoCacheRequest requestHandle(tdbb, drq_e_pkg, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES WITH PKG.RDB$PACKAGE_NAME EQ name.c_str() { found = true; executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_PACKAGE, name); ERASE PKG; if (!PKG.RDB$SECURITY_CLASS.NULL) deleteSecurityClass(tdbb, transaction, PKG.RDB$SECURITY_CLASS); dsc desc; desc.makeText(name.length(), ttype_metadata, (UCHAR*) const_cast(name.c_str())); // safe const_cast DFW_post_work(transaction, dfw_drop_package_header, &desc, 0); } END_FOR if (!found && !silent) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name)); } SortedObjectsArray existingFuncs(getPool()); SortedObjectsArray existingProcs(getPool()); collectPackagedItems(tdbb, transaction, name, existingFuncs, existingProcs, false); for (SortedObjectsArray::iterator i = existingFuncs.begin(); i != existingFuncs.end(); ++i) { DropFunctionNode dropNode(getPool(), i->name); dropNode.package = name; dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction); } for (SortedObjectsArray::iterator i = existingProcs.begin(); i != existingProcs.end(); ++i) { DropProcedureNode dropNode(getPool(), i->name); dropNode.package = name; dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction); } requestHandle.reset(tdbb, drq_e_pkg_prv, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRIV IN RDB$USER_PRIVILEGES WITH (PRIV.RDB$RELATION_NAME EQ name.c_str() AND PRIV.RDB$OBJECT_TYPE = obj_package_header) OR (PRIV.RDB$USER EQ name.c_str() AND PRIV.RDB$USER_TYPE = obj_package_header) { ERASE PRIV; } END_FOR if (found) executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_PACKAGE, name); savePoint.release(); // everything is ok } //---------------------- void CreatePackageBodyNode::print(string& text) const { fb_assert(items); text.printf( "CreatePackageBodyNode\n" " name: '%s'\n" " declaredItems:\n" "--------\n", name.c_str()); if (declaredItems) { for (unsigned i = 0; i < declaredItems->getCount(); ++i) { string item; switch ((*declaredItems)[i].type) { case CreateAlterPackageNode::Item::FUNCTION: (*declaredItems)[i].function->print(item); break; case CreateAlterPackageNode::Item::PROCEDURE: (*declaredItems)[i].procedure->print(item); break; } text += item; } } text += "--------\n" " items:\n" "--------\n"; for (unsigned i = 0; i < items->getCount(); ++i) { string item; switch ((*items)[i].type) { case CreateAlterPackageNode::Item::FUNCTION: (*items)[i].function->print(item); break; case CreateAlterPackageNode::Item::PROCEDURE: (*items)[i].procedure->print(item); break; } text += item; } text += "--------\n"; } DdlNode* CreatePackageBodyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { source.ltrim("\n\r\t "); // process declaredItems and items Array* arrays[] = {declaredItems, items}; for (unsigned i = 0; i < FB_NELEM(arrays); ++i) { if (!arrays[i]) continue; for (unsigned j = 0; j < arrays[i]->getCount(); ++j) { DsqlCompiledStatement* itemStatement = FB_NEW(getPool()) DsqlCompiledStatement(getPool()); DsqlCompilerScratch* itemScratch = (*arrays[i])[j].dsqlScratch = FB_NEW(getPool()) DsqlCompilerScratch(getPool(), dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), itemStatement); itemScratch->clientDialect = dsqlScratch->clientDialect; itemScratch->package = name; switch ((*arrays[i])[j].type) { case CreateAlterPackageNode::Item::FUNCTION: { CreateAlterFunctionNode* const fun = (*arrays[i])[j].function; fun->package = name; fun->create = true; if (arrays[i] == items) fun->alter = true; fun->dsqlPass(itemScratch); } break; case CreateAlterPackageNode::Item::PROCEDURE: { CreateAlterProcedureNode* const proc = (*arrays[i])[j].procedure; proc->package = name; proc->create = true; if (arrays[i] == items) proc->alter = true; proc->dsqlPass(itemScratch); } break; } } } return DdlNode::dsqlPass(dsqlScratch); } void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { Attachment* attachment = transaction->getAttachment(); // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); AutoCacheRequest requestHandle(tdbb, drq_m_pkg_body, DYN_REQUESTS); bool modified = false; FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES WITH PKG.RDB$PACKAGE_NAME EQ name.c_str() { if (!PKG.RDB$PACKAGE_BODY_SOURCE.NULL) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_package_body_exists) << Arg::Str(name)); } executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_PACKAGE_BODY, name); MODIFY PKG PKG.RDB$PACKAGE_BODY_SOURCE.NULL = FALSE; attachment->storeMetaDataBlob(tdbb, transaction, &PKG.RDB$PACKAGE_BODY_SOURCE, source); END_MODIFY modified = true; owner = PKG.RDB$OWNER_NAME; } END_FOR if (!modified) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name)); } SortedObjectsArray headerFuncs(getPool()); SortedObjectsArray headerProcs(getPool()); collectPackagedItems(tdbb, transaction, name, headerFuncs, headerProcs, false); SortedObjectsArray existingFuncs(getPool()); SortedObjectsArray existingProcs(getPool()); // process declaredItems and items Array* arrays[] = {declaredItems, items}; for (unsigned i = 0; i < FB_NELEM(arrays); ++i) { if (!arrays[i]) continue; if (arrays[i] == items) collectPackagedItems(tdbb, transaction, name, existingFuncs, existingProcs, true); for (unsigned j = 0; j < arrays[i]->getCount(); ++j) { CreateAlterPackageNode::Item& elem = (*arrays[i])[j]; switch (elem.type) { case CreateAlterPackageNode::Item::FUNCTION: { CreateAlterFunctionNode* func = elem.function; if (arrays[i] == items) func->privateScope = !headerFuncs.exist(Signature(func->name)); func->packageOwner = owner; func->executeDdl(tdbb, elem.dsqlScratch, transaction); } break; case CreateAlterPackageNode::Item::PROCEDURE: { CreateAlterProcedureNode* proc = elem.procedure; if (arrays[i] == items) proc->privateScope = !headerProcs.exist(Signature(proc->name)); proc->packageOwner = owner; proc->executeDdl(tdbb, elem.dsqlScratch, transaction); } break; } } } SortedObjectsArray newFuncs(getPool()); SortedObjectsArray newProcs(getPool()); collectPackagedItems(tdbb, transaction, name, newFuncs, newProcs, true); for (SortedObjectsArray::iterator i = existingFuncs.begin(); i != existingFuncs.end(); ++i) { size_t pos; bool found = newFuncs.find(Signature(getPool(), i->name), pos); if (!found || !newFuncs[pos].defined) { status_exception::raise( Arg::Gds(isc_dyn_funcnotdef_package) << i->name.c_str() << name.c_str()); } else if (newFuncs[pos] != *i) { status_exception::raise( Arg::Gds(isc_dyn_funcsignat_package) << i->name.c_str() << name.c_str()); } } for (SortedObjectsArray::iterator i = existingProcs.begin(); i != existingProcs.end(); ++i) { size_t pos; bool found = newProcs.find(Signature(getPool(), i->name), pos); if (!found || !newProcs[pos].defined) { status_exception::raise( Arg::Gds(isc_dyn_procnotdef_package) << i->name.c_str() << name.c_str()); } else if (newProcs[pos] != *i) { status_exception::raise( Arg::Gds(isc_dyn_procsignat_package) << i->name.c_str() << name.c_str()); } for (SortedObjectsArray::iterator j = newProcs[pos].parameters.begin(); j != newProcs[pos].parameters.end(); ++j) { if (!j->defaultSource.isEmpty() || !j->defaultValue.isEmpty()) { status_exception::raise( Arg::Gds(isc_dyn_defvaldecl_package) << name.c_str() << i->name.c_str()); } } } // Lets recreate default of public procedure/function parameters requestHandle.reset(tdbb, drq_m_pkg_prm_defs, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRM IN RDB$PROCEDURE_PARAMETERS WITH PRM.RDB$PACKAGE_NAME EQ name.c_str() { size_t pos; if (existingProcs.find(Signature(getPool(), MetaName(PRM.RDB$PROCEDURE_NAME)), pos)) { const Signature& proc = existingProcs[pos]; ParameterInfo paramKey(getPool()); paramKey.type = PRM.RDB$PARAMETER_TYPE; paramKey.number = PRM.RDB$PARAMETER_NUMBER; if (proc.parameters.find(paramKey, pos)) { const ParameterInfo& param = proc.parameters[pos]; MODIFY PRM PRM.RDB$DEFAULT_SOURCE = param.defaultSource; PRM.RDB$DEFAULT_SOURCE.NULL = param.defaultSource.isEmpty(); PRM.RDB$DEFAULT_VALUE = param.defaultValue; PRM.RDB$DEFAULT_VALUE.NULL = param.defaultValue.isEmpty(); END_MODIFY } } } END_FOR requestHandle.reset(tdbb, drq_m_pkg_arg_defs, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) ARG IN RDB$FUNCTION_ARGUMENTS WITH ARG.RDB$PACKAGE_NAME EQ name.c_str() { size_t pos; if (existingFuncs.find(Signature(getPool(), MetaName(ARG.RDB$FUNCTION_NAME)), pos)) { const Signature& func = existingFuncs[pos]; ParameterInfo paramKey(getPool()); paramKey.number = ARG.RDB$ARGUMENT_POSITION; if (func.parameters.find(paramKey, pos)) { const ParameterInfo& param = func.parameters[pos]; MODIFY ARG ARG.RDB$DEFAULT_SOURCE = param.defaultSource; ARG.RDB$DEFAULT_SOURCE.NULL = param.defaultSource.isEmpty(); ARG.RDB$DEFAULT_VALUE = param.defaultValue; ARG.RDB$DEFAULT_VALUE.NULL = param.defaultValue.isEmpty(); END_MODIFY } } } END_FOR executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_PACKAGE_BODY, name); savePoint.release(); // everything is ok } //---------------------- void DropPackageBodyNode::print(string& text) const { text.printf( "DropPackageBodyNode\n" " name: '%s'\n", name.c_str()); } void DropPackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); bool found = false; AutoCacheRequest requestHandle(tdbb, drq_m_pkg_body2, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PKG IN RDB$PACKAGES WITH PKG.RDB$PACKAGE_NAME EQ name.c_str() { found = true; executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_PACKAGE_BODY, name); MODIFY PKG PKG.RDB$PACKAGE_BODY_SOURCE.NULL = TRUE; dsc desc; desc.makeText(name.length(), ttype_metadata, (UCHAR*) const_cast(name.c_str())); // safe const_cast DFW_post_work(transaction, dfw_drop_package_body, &desc, 0); END_MODIFY } END_FOR if (!found) { status_exception::raise( Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_dyn_package_not_found) << Arg::Str(name)); } requestHandle.reset(tdbb, drq_m_pkg_fun, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) FUN IN RDB$FUNCTIONS WITH FUN.RDB$PACKAGE_NAME EQ name.c_str() { if (!FUN.RDB$PRIVATE_FLAG.NULL && FUN.RDB$PRIVATE_FLAG != 0) { DropFunctionNode dropNode(getPool(), FUN.RDB$FUNCTION_NAME); dropNode.package = name; dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction); } else { MODIFY FUN FUN.RDB$FUNCTION_TYPE.NULL = TRUE; FUN.RDB$FUNCTION_BLR.NULL = TRUE; FUN.RDB$DEBUG_INFO.NULL = TRUE; FUN.RDB$MODULE_NAME.NULL = TRUE; FUN.RDB$ENGINE_NAME.NULL = TRUE; FUN.RDB$ENTRYPOINT.NULL = TRUE; END_MODIFY } } END_FOR requestHandle.reset(tdbb, drq_m_pkg_prc, DYN_REQUESTS); FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) PRC IN RDB$PROCEDURES WITH PRC.RDB$PACKAGE_NAME EQ name.c_str() { if (!PRC.RDB$PRIVATE_FLAG.NULL && PRC.RDB$PRIVATE_FLAG != 0) { DropProcedureNode dropNode(getPool(), PRC.RDB$PROCEDURE_NAME); dropNode.package = name; dropNode.dsqlPass(dsqlScratch); dropNode.executeDdl(tdbb, dsqlScratch, transaction); } else { MODIFY PRC PRC.RDB$PROCEDURE_TYPE.NULL = TRUE; PRC.RDB$PROCEDURE_BLR.NULL = TRUE; PRC.RDB$DEBUG_INFO.NULL = TRUE; PRC.RDB$ENGINE_NAME.NULL = TRUE; PRC.RDB$ENTRYPOINT.NULL = TRUE; END_MODIFY } } END_FOR executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_PACKAGE_BODY, name); savePoint.release(); // everything is ok } } // namespace Jrd