From e9f74f04d1f24dd9a11854a4f8b6c0beb714c805 Mon Sep 17 00:00:00 2001 From: asfernandes Date: Sun, 25 Jan 2015 20:27:46 +0000 Subject: [PATCH] Improvements to the UDR plugin. --- builds/posix/Makefile.in.plugins_examples | 2 +- builds/win32/msvc10/udrcpp_example.vcxproj | 8 +- builds/win32/msvc12/udrcpp_example.vcxproj | 8 +- builds/win32/msvc9/Firebird3_Examples.sln | 1 - examples/udr/UdrCppExample.cpp | 3 + src/include/firebird/FirebirdInterface.idl | 15 +- src/include/firebird/IdlFbInterfaces.h | 219 +++++++++++- src/include/firebird/Interface.h | 1 + src/include/firebird/UdrCppEngine.h | 137 +++++++- src/include/firebird/UdrEngine.h | 52 --- src/plugins/udr_engine/UdrEngine.cpp | 391 +++++++++++++-------- 11 files changed, 585 insertions(+), 252 deletions(-) delete mode 100644 src/include/firebird/UdrEngine.h diff --git a/builds/posix/Makefile.in.plugins_examples b/builds/posix/Makefile.in.plugins_examples index a5331c8773..6c4f398ac2 100644 --- a/builds/posix/Makefile.in.plugins_examples +++ b/builds/posix/Makefile.in.plugins_examples @@ -67,7 +67,7 @@ ifeq ($(PLATFORM),DARWIN) $(FIREBIRD_LIBRARY_LINK) else $(LIB_LINK) $(LIB_LINK_OPTIONS) $(LIB_LINK_SONAME)udrcpp_example.$(SHRLIB_EXT) \ - $(LIB_PATH_OPTS) -o $@ $^ $(THR_LIBS) $(PLUGINS)/$(LIB_PREFIX)udr_engine.$(SHRLIB_EXT) \ + $(LIB_PATH_OPTS) -o $@ $^ $(THR_LIBS) \ $(FIREBIRD_LIBRARY_LINK) endif diff --git a/builds/win32/msvc10/udrcpp_example.vcxproj b/builds/win32/msvc10/udrcpp_example.vcxproj index bc9e111f15..526668b476 100644 --- a/builds/win32/msvc10/udrcpp_example.vcxproj +++ b/builds/win32/msvc10/udrcpp_example.vcxproj @@ -207,13 +207,7 @@ ..\..\..\src\jrd - - - {20debf08-ef0a-4c94-adeb-fe9bba14588b} - false - - - \ No newline at end of file + diff --git a/builds/win32/msvc12/udrcpp_example.vcxproj b/builds/win32/msvc12/udrcpp_example.vcxproj index 79a2022f8e..e25e985cef 100644 --- a/builds/win32/msvc12/udrcpp_example.vcxproj +++ b/builds/win32/msvc12/udrcpp_example.vcxproj @@ -211,13 +211,7 @@ ..\..\..\src\jrd - - - {20debf08-ef0a-4c94-adeb-fe9bba14588b} - false - - - \ No newline at end of file + diff --git a/builds/win32/msvc9/Firebird3_Examples.sln b/builds/win32/msvc9/Firebird3_Examples.sln index d293864d3d..928b2e1089 100644 --- a/builds/win32/msvc9/Firebird3_Examples.sln +++ b/builds/win32/msvc9/Firebird3_Examples.sln @@ -12,7 +12,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "intlbuild", "intlbuild.vcpr EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "udrcpp_example", "udrcpp_example.vcproj", "{FF0FD8DF-1E5C-486E-B395-A620376A4633}" ProjectSection(ProjectDependencies) = postProject - {20DEBF08-EF0A-4C94-ADEB-FE9BBA14588B} = {20DEBF08-EF0A-4C94-ADEB-FE9BBA14588B} {4FE03933-98CD-4879-A135-FD9430087A6B} = {4FE03933-98CD-4879-A135-FD9430087A6B} EndProjectSection EndProject diff --git a/examples/udr/UdrCppExample.cpp b/examples/udr/UdrCppExample.cpp index b741d8f462..079de7dbfc 100644 --- a/examples/udr/UdrCppExample.cpp +++ b/examples/udr/UdrCppExample.cpp @@ -783,3 +783,6 @@ FB_UDR_BEGIN_TRIGGER(replicate_persons) AutoRelease triggerMetadata; AutoRelease stmt; FB_UDR_END_TRIGGER + + +FB_UDR_IMPLEMENT_ENTRY_POINT diff --git a/src/include/firebird/FirebirdInterface.idl b/src/include/firebird/FirebirdInterface.idl index 2c94449036..8dcb137fa1 100644 --- a/src/include/firebird/FirebirdInterface.idl +++ b/src/include/firebird/FirebirdInterface.idl @@ -1216,23 +1216,32 @@ interface TraceFactory : PluginBase // UDR Factory interfaces. They should be singletons instances created by user's modules and // registered. When UDR engine is going to load a routine, it calls newItem. -interface UdrFunctionFactory : Versioned +interface UdrFunctionFactory : Disposable { void setup(Status status, ExternalContext context, RoutineMetadata metadata, MetadataBuilder inBuilder, MetadataBuilder outBuilder); ExternalFunction newItem(Status status, ExternalContext context, RoutineMetadata metadata); } -interface UdrProcedureFactory : Versioned +interface UdrProcedureFactory : Disposable { void setup(Status status, ExternalContext context, RoutineMetadata metadata, MetadataBuilder inBuilder, MetadataBuilder outBuilder); ExternalProcedure newItem(Status status, ExternalContext context, RoutineMetadata metadata); } -interface UdrTriggerFactory : Versioned +interface UdrTriggerFactory : Disposable { void setup(Status status, ExternalContext context, RoutineMetadata metadata, MetadataBuilder fieldsBuilder); ExternalTrigger newItem(Status status, ExternalContext context, RoutineMetadata metadata); } + +interface UdrPlugin : Versioned +{ + Master getMaster(); + + void registerFunction(Status status, const string name, UdrFunctionFactory factory); + void registerProcedure(Status status, const string name, UdrProcedureFactory factory); + void registerTrigger(Status status, const string name, UdrTriggerFactory factory); +} diff --git a/src/include/firebird/IdlFbInterfaces.h b/src/include/firebird/IdlFbInterfaces.h index ecd1a65597..654135c43c 100644 --- a/src/include/firebird/IdlFbInterfaces.h +++ b/src/include/firebird/IdlFbInterfaces.h @@ -3,6 +3,8 @@ #ifndef IDL_FB_INTERFACES_H #define IDL_FB_INTERFACES_H +#include + #ifndef CLOOP_CARG #define CLOOP_CARG #endif @@ -106,6 +108,7 @@ namespace Firebird class IUdrFunctionFactory; class IUdrProcedureFactory; class IUdrTriggerFactory; + class IUdrPlugin; // Interfaces declarations @@ -4401,10 +4404,10 @@ namespace Firebird } }; - class IUdrFunctionFactory : public IVersioned + class IUdrFunctionFactory : public IDisposable { public: - struct VTable : public IVersioned::VTable + struct VTable : public IDisposable::VTable { void (CLOOP_CARG *setup)(IUdrFunctionFactory* self, IStatus* status, IExternalContext* context, IRoutineMetadata* metadata, IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder) throw(); IExternalFunction* (CLOOP_CARG *newItem)(IUdrFunctionFactory* self, IStatus* status, IExternalContext* context, IRoutineMetadata* metadata) throw(); @@ -4412,7 +4415,7 @@ namespace Firebird protected: IUdrFunctionFactory(DoNotInherit) - : IVersioned(DoNotInherit()) + : IDisposable(DoNotInherit()) { } @@ -4421,7 +4424,7 @@ namespace Firebird } public: - static const unsigned VERSION = 2; + static const unsigned VERSION = 3; template void setup(StatusType* status, IExternalContext* context, IRoutineMetadata* metadata, IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder) { @@ -4437,10 +4440,10 @@ namespace Firebird } }; - class IUdrProcedureFactory : public IVersioned + class IUdrProcedureFactory : public IDisposable { public: - struct VTable : public IVersioned::VTable + struct VTable : public IDisposable::VTable { void (CLOOP_CARG *setup)(IUdrProcedureFactory* self, IStatus* status, IExternalContext* context, IRoutineMetadata* metadata, IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder) throw(); IExternalProcedure* (CLOOP_CARG *newItem)(IUdrProcedureFactory* self, IStatus* status, IExternalContext* context, IRoutineMetadata* metadata) throw(); @@ -4448,7 +4451,7 @@ namespace Firebird protected: IUdrProcedureFactory(DoNotInherit) - : IVersioned(DoNotInherit()) + : IDisposable(DoNotInherit()) { } @@ -4457,7 +4460,7 @@ namespace Firebird } public: - static const unsigned VERSION = 2; + static const unsigned VERSION = 3; template void setup(StatusType* status, IExternalContext* context, IRoutineMetadata* metadata, IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder) { @@ -4473,10 +4476,10 @@ namespace Firebird } }; - class IUdrTriggerFactory : public IVersioned + class IUdrTriggerFactory : public IDisposable { public: - struct VTable : public IVersioned::VTable + struct VTable : public IDisposable::VTable { void (CLOOP_CARG *setup)(IUdrTriggerFactory* self, IStatus* status, IExternalContext* context, IRoutineMetadata* metadata, IMetadataBuilder* fieldsBuilder) throw(); IExternalTrigger* (CLOOP_CARG *newItem)(IUdrTriggerFactory* self, IStatus* status, IExternalContext* context, IRoutineMetadata* metadata) throw(); @@ -4484,7 +4487,7 @@ namespace Firebird protected: IUdrTriggerFactory(DoNotInherit) - : IVersioned(DoNotInherit()) + : IDisposable(DoNotInherit()) { } @@ -4493,7 +4496,7 @@ namespace Firebird } public: - static const unsigned VERSION = 2; + static const unsigned VERSION = 3; template void setup(StatusType* status, IExternalContext* context, IRoutineMetadata* metadata, IMetadataBuilder* fieldsBuilder) { @@ -4509,6 +4512,55 @@ namespace Firebird } }; + class IUdrPlugin : public IVersioned + { + public: + struct VTable : public IVersioned::VTable + { + IMaster* (CLOOP_CARG *getMaster)(IUdrPlugin* self) throw(); + void (CLOOP_CARG *registerFunction)(IUdrPlugin* self, IStatus* status, const char* name, IUdrFunctionFactory* factory) throw(); + void (CLOOP_CARG *registerProcedure)(IUdrPlugin* self, IStatus* status, const char* name, IUdrProcedureFactory* factory) throw(); + void (CLOOP_CARG *registerTrigger)(IUdrPlugin* self, IStatus* status, const char* name, IUdrTriggerFactory* factory) throw(); + }; + + protected: + IUdrPlugin(DoNotInherit) + : IVersioned(DoNotInherit()) + { + } + + ~IUdrPlugin() + { + } + + public: + static const unsigned VERSION = 2; + + IMaster* getMaster() + { + IMaster* ret = static_cast(this->cloopVTable)->getMaster(this); + return ret; + } + + template void registerFunction(StatusType* status, const char* name, IUdrFunctionFactory* factory) + { + static_cast(this->cloopVTable)->registerFunction(this, status, name, factory); + StatusType::checkException(status); + } + + template void registerProcedure(StatusType* status, const char* name, IUdrProcedureFactory* factory) + { + static_cast(this->cloopVTable)->registerProcedure(this, status, name, factory); + StatusType::checkException(status); + } + + template void registerTrigger(StatusType* status, const char* name, IUdrTriggerFactory* factory) + { + static_cast(this->cloopVTable)->registerTrigger(this, status, name, factory); + StatusType::checkException(status); + } + }; + // Interfaces implementations template @@ -14377,6 +14429,7 @@ namespace Firebird VTableImpl() { this->version = Base::VERSION; + this->dispose = &Name::cloopdisposeDispatcher; this->setup = &Name::cloopsetupDispatcher; this->newItem = &Name::cloopnewItemDispatcher; } @@ -14413,9 +14466,21 @@ namespace Firebird return static_cast(0); } } + + static void CLOOP_CARG cloopdisposeDispatcher(IDisposable* self) throw() + { + try + { + static_cast(self)->Name::dispose(); + } + catch (...) + { + StatusType::catchException(0); + } + } }; - template > > + template > > > > class IUdrFunctionFactoryImpl : public IUdrFunctionFactoryBaseImpl { protected: @@ -14445,6 +14510,7 @@ namespace Firebird VTableImpl() { this->version = Base::VERSION; + this->dispose = &Name::cloopdisposeDispatcher; this->setup = &Name::cloopsetupDispatcher; this->newItem = &Name::cloopnewItemDispatcher; } @@ -14481,9 +14547,21 @@ namespace Firebird return static_cast(0); } } + + static void CLOOP_CARG cloopdisposeDispatcher(IDisposable* self) throw() + { + try + { + static_cast(self)->Name::dispose(); + } + catch (...) + { + StatusType::catchException(0); + } + } }; - template > > + template > > > > class IUdrProcedureFactoryImpl : public IUdrProcedureFactoryBaseImpl { protected: @@ -14513,6 +14591,7 @@ namespace Firebird VTableImpl() { this->version = Base::VERSION; + this->dispose = &Name::cloopdisposeDispatcher; this->setup = &Name::cloopsetupDispatcher; this->newItem = &Name::cloopnewItemDispatcher; } @@ -14549,9 +14628,21 @@ namespace Firebird return static_cast(0); } } + + static void CLOOP_CARG cloopdisposeDispatcher(IDisposable* self) throw() + { + try + { + static_cast(self)->Name::dispose(); + } + catch (...) + { + StatusType::catchException(0); + } + } }; - template > > + template > > > > class IUdrTriggerFactoryImpl : public IUdrTriggerFactoryBaseImpl { protected: @@ -14567,6 +14658,104 @@ namespace Firebird virtual void setup(StatusType* status, IExternalContext* context, IRoutineMetadata* metadata, IMetadataBuilder* fieldsBuilder) = 0; virtual IExternalTrigger* newItem(StatusType* status, IExternalContext* context, IRoutineMetadata* metadata) = 0; }; + + template + class IUdrPluginBaseImpl : public Base + { + public: + typedef IUdrPlugin Declaration; + + IUdrPluginBaseImpl(DoNotInherit = DoNotInherit()) + { + static struct VTableImpl : Base::VTable + { + VTableImpl() + { + this->version = Base::VERSION; + this->getMaster = &Name::cloopgetMasterDispatcher; + this->registerFunction = &Name::cloopregisterFunctionDispatcher; + this->registerProcedure = &Name::cloopregisterProcedureDispatcher; + this->registerTrigger = &Name::cloopregisterTriggerDispatcher; + } + } vTable; + + this->cloopVTable = &vTable; + } + + static IMaster* CLOOP_CARG cloopgetMasterDispatcher(IUdrPlugin* self) throw() + { + try + { + return static_cast(self)->Name::getMaster(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } + + static void CLOOP_CARG cloopregisterFunctionDispatcher(IUdrPlugin* self, IStatus* status, const char* name, IUdrFunctionFactory* factory) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::registerFunction(&status2, name, factory); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopregisterProcedureDispatcher(IUdrPlugin* self, IStatus* status, const char* name, IUdrProcedureFactory* factory) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::registerProcedure(&status2, name, factory); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopregisterTriggerDispatcher(IUdrPlugin* self, IStatus* status, const char* name, IUdrTriggerFactory* factory) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::registerTrigger(&status2, name, factory); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + }; + + template > > + class IUdrPluginImpl : public IUdrPluginBaseImpl + { + protected: + IUdrPluginImpl(DoNotInherit = DoNotInherit()) + { + } + + public: + virtual ~IUdrPluginImpl() + { + } + + virtual IMaster* getMaster() = 0; + virtual void registerFunction(StatusType* status, const char* name, IUdrFunctionFactory* factory) = 0; + virtual void registerProcedure(StatusType* status, const char* name, IUdrProcedureFactory* factory) = 0; + virtual void registerTrigger(StatusType* status, const char* name, IUdrTriggerFactory* factory) = 0; + }; }; diff --git a/src/include/firebird/Interface.h b/src/include/firebird/Interface.h index 5ddcb13559..a469e353c3 100644 --- a/src/include/firebird/Interface.h +++ b/src/include/firebird/Interface.h @@ -239,5 +239,6 @@ namespace Firebird } // namespace Firebird #define FB_PLUGIN_ENTRY_POINT firebird_plugin +#define FB_UDR_PLUGIN_ENTRY_POINT firebird_udr_plugin #endif // FB_INTERFACE_H diff --git a/src/include/firebird/UdrCppEngine.h b/src/include/firebird/UdrCppEngine.h index 6c4dfb5ec5..80bb1125ee 100644 --- a/src/include/firebird/UdrCppEngine.h +++ b/src/include/firebird/UdrCppEngine.h @@ -27,20 +27,51 @@ #error FB_UDR_STATUS_TYPE must be defined with the Status class before UdrCppEngine.h inclusion. #endif -#include "./UdrEngine.h" #include "./Message.h" -#ifndef JRD_IBASE_H -#include "ibase.h" -#include "iberror.h" -#endif #include -namespace Firebird -{ - namespace Udr - { -//------------------------------------------------------------------------------ +#define FB_UDR_IMPLEMENT_ENTRY_POINT \ + namespace Firebird \ + { \ + namespace Udr \ + { \ + RegistrationNode* regFunctions = NULL; \ + RegistrationNode* regProcedures = NULL; \ + RegistrationNode* regTriggers = NULL; \ + } \ + } \ + \ + extern "C" FB_BOOLEAN* FB_UDR_PLUGIN_ENTRY_POINT(IStatus* status, FB_BOOLEAN* theirUnloadFlag, \ + IUdrPlugin* udrPlugin) \ + { \ + ::Firebird::Udr::FactoryRegistration::finish(status, udrPlugin); \ + \ + class UnloadDetector \ + { \ + public: \ + UnloadDetector(FB_BOOLEAN* aTheirUnloadFlag, IUdrPlugin* aUdrPlugin) \ + : myUnloadFlag(FB_FALSE), \ + theirUnloadFlag(aTheirUnloadFlag), \ + udrPlugin(aUdrPlugin) \ + { \ + } \ + \ + ~UnloadDetector() \ + { \ + if (!myUnloadFlag) \ + *theirUnloadFlag = FB_TRUE; \ + } \ + \ + FB_BOOLEAN myUnloadFlag; \ + FB_BOOLEAN* theirUnloadFlag; \ + IUdrPlugin* udrPlugin; \ + }; \ + \ + static UnloadDetector unloadDetector(theirUnloadFlag, udrPlugin); \ + \ + return &unloadDetector.myUnloadFlag; \ + } #define FB_UDR_BEGIN_FUNCTION(name) \ @@ -176,6 +207,13 @@ namespace Firebird } +namespace Firebird +{ + namespace Udr + { +//------------------------------------------------------------------------------ + + template class Procedure; @@ -311,13 +349,76 @@ public: }; +template struct RegistrationNode +{ + const char* name; + T* factory; + RegistrationNode* next; +}; + +extern RegistrationNode* regFunctions; +extern RegistrationNode* regProcedures; +extern RegistrationNode* regTriggers; + +class FactoryRegistration +{ +public: + template static void schedule(const char* name, T* factory, + RegistrationNode** list) + { + RegistrationNode* node = new RegistrationNode(); + node->name = name; + node->factory = factory; + node->next = *list; + + *list = node; + } + + static void finish(IStatus* status, IUdrPlugin* plugin) + { + CheckStatusWrapper statusWrapper(status); + + if (!run(&statusWrapper, plugin, &IUdrPlugin::registerFunction, regFunctions)) + return; + + if (!run(&statusWrapper, plugin, &IUdrPlugin::registerProcedure, regProcedures)) + return; + + if (!run(&statusWrapper, plugin, &IUdrPlugin::registerTrigger, regTriggers)) + return; + } + +private: + template + static bool run(CheckStatusWrapper* statusWrapper, IUdrPlugin* plugin, + void (IUdrPlugin::*routine)(CheckStatusWrapper* status, const char* name, T* factory), + RegistrationNode* list) + { + for (RegistrationNode* node = list; node; node = node->next) + { + (plugin->*routine)(statusWrapper, node->name, node->factory); + + if (statusWrapper->getStatus() & IStatus::FB_HAS_ERRORS) + return false; + } + + return true; + } +}; + + template class FunctionFactoryImpl : public IUdrFunctionFactoryImpl, StatusType> { public: explicit FunctionFactoryImpl(const char* name) { - fbUdrRegFunction(name, this); + FactoryRegistration::schedule(name, this, ®Functions); + } + + void dispose() + { + // Do not delete this. The instances are statically allocated. } void setup(StatusType* status, IExternalContext* /*context*/, @@ -341,7 +442,12 @@ template class ProcedureFactoryImpl : public: explicit ProcedureFactoryImpl(const char* name) { - fbUdrRegProcedure(name, this); + FactoryRegistration::schedule(name, this, ®Procedures); + } + + void dispose() + { + // Do not delete this. The instances are statically allocated. } void setup(StatusType* status, IExternalContext* /*context*/, @@ -365,7 +471,12 @@ template class TriggerFactoryImpl : public: explicit TriggerFactoryImpl(const char* name) { - fbUdrRegTrigger(name, this); + FactoryRegistration::schedule(name, this, ®Triggers); + } + + void dispose() + { + // Do not delete this. The instances are statically allocated. } void setup(StatusType* status, IExternalContext* /*context*/, diff --git a/src/include/firebird/UdrEngine.h b/src/include/firebird/UdrEngine.h deleted file mode 100644 index 75266a3b0d..0000000000 --- a/src/include/firebird/UdrEngine.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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) 2008 Adriano dos Santos Fernandes - * and all contributors signed below. - * - * All Rights Reserved. - * Contributor(s): ______________________________________. - */ - -#ifndef FIREBIRD_UDR_H -#define FIREBIRD_UDR_H - -#include "./Interface.h" - -#ifndef FB_EXPORTED -#if defined(DARWIN) -#define FB_EXPORTED __attribute__((visibility("default"))) -#else -#define FB_EXPORTED -#endif // OS choice (DARWIN) -#endif // FB_EXPORTED - - -namespace Firebird -{ -//------------------------------------------------------------------------------ - - -//// TODO: review -// Routine registration functions. -extern "C" void FB_EXPORTED fbUdrRegFunction(const char* name, IUdrFunctionFactory* factory); -extern "C" void FB_EXPORTED fbUdrRegProcedure(const char* name, IUdrProcedureFactory* factory); -extern "C" void FB_EXPORTED fbUdrRegTrigger(const char* name, IUdrTriggerFactory* factory); - - -//------------------------------------------------------------------------------ -} // namespace Firebird - -#endif // FIREBIRD_UDR_H diff --git a/src/plugins/udr_engine/UdrEngine.cpp b/src/plugins/udr_engine/UdrEngine.cpp index d142498c32..d793779c6e 100644 --- a/src/plugins/udr_engine/UdrEngine.cpp +++ b/src/plugins/udr_engine/UdrEngine.cpp @@ -22,7 +22,6 @@ #include "firebird.h" #include "../jrd/ibase.h" -#include "firebird/UdrEngine.h" #include "firebird/Interface.h" #include "../common/classes/alloc.h" #include "../common/classes/array.h" @@ -43,35 +42,7 @@ namespace Firebird //------------------------------------------------------------------------------ -struct Node -{ - Node() - : name(*getDefaultMemoryPool()), - module(*getDefaultMemoryPool()) - { - } - - string name; - PathName module; -}; - -struct FunctionNode : public Node -{ - IUdrFunctionFactory* factory; - FunctionNode* next; -}; - -struct ProcedureNode : public Node -{ - IUdrProcedureFactory* factory; - ProcedureNode* next; -}; - -struct TriggerNode : public Node -{ - IUdrTriggerFactory* factory; - TriggerNode* next; -}; +class UdrPluginImpl; static GlobalPtr > paths; @@ -129,24 +100,20 @@ public: } public: - void loadModule(ThrowStatusWrapper* status, IRoutineMetadata* metadata, + UdrPluginImpl* loadModule(ThrowStatusWrapper* status, IRoutineMetadata* metadata, PathName* moduleName, string* entryPoint); template ObjType* getChild( - ThrowStatusWrapper* status, GenericMap > >& children, - SharedObjType* sharedObj, IExternalContext* context, NodeType* nodes, + ThrowStatusWrapper* status, + GenericMap > >& children, + SharedObjType* sharedObj, IExternalContext* context, SortedArray& sharedObjs, const PathName& moduleName); template void deleteChildren( GenericMap > >& children); - template T* findNode(ThrowStatusWrapper* status, T* nodes, - const PathName& moduleName, const string& entryPoint); - -private: - template T2* getNode(ThrowStatusWrapper* status, T* nodes, - const PathName& moduleName, IExternalContext* context, IRoutineMetadata* metadata, - const string& entryPoint); + template T* findNode(ThrowStatusWrapper* status, + const GenericMap > >& nodes, const string& entryPoint); public: void open(ThrowStatusWrapper* status, IExternalContext* context, char* name, unsigned nameSize); @@ -172,11 +139,11 @@ public: }; -class ModulesMap : public GenericMap > > +class ModulesMap : public GenericMap > > { public: explicit ModulesMap(MemoryPool& p) - : GenericMap > >(p) + : GenericMap > >(p) { } @@ -190,15 +157,125 @@ public: static GlobalPtr modulesMutex; static GlobalPtr modules; -static InitInstance loadingModule; -static FunctionNode* registeredFunctions = NULL; -static ProcedureNode* registeredProcedures = NULL; -static TriggerNode* registeredTriggers = NULL; - //-------------------------------------- +class UdrPluginImpl : public VersionedIface > +{ +public: + UdrPluginImpl(const PathName& aModuleName, ModuleLoader::Module* aModule) + : moduleName(*getDefaultMemoryPool(), aModuleName), + module(aModule), + myUnloadFlag(FB_FALSE), + theirUnloadFlag(NULL), + functionsMap(*getDefaultMemoryPool()), + proceduresMap(*getDefaultMemoryPool()), + triggersMap(*getDefaultMemoryPool()) + { + } + + ~UdrPluginImpl() + { + if (myUnloadFlag) + return; + + *theirUnloadFlag = FB_TRUE; + + { + GenericMap > >::Accessor accessor(&functionsMap); + for (bool cont = accessor.getFirst(); cont; cont = accessor.getNext()) + accessor.current()->second->dispose(); + } + + { + GenericMap > >::Accessor accessor(&proceduresMap); + for (bool cont = accessor.getFirst(); cont; cont = accessor.getNext()) + accessor.current()->second->dispose(); + } + + { + GenericMap > >::Accessor accessor(&triggersMap); + for (bool cont = accessor.getFirst(); cont; cont = accessor.getNext()) + accessor.current()->second->dispose(); + } + + delete module; + } + +public: + IMaster* getMaster() + { + return MasterInterfacePtr(); + } + + void registerFunction(ThrowStatusWrapper* status, const char* name, + IUdrFunctionFactory* factory) + { + if (functionsMap.exist(name)) + { + static const ISC_STATUS statusVector[] = { + isc_arg_gds, isc_random, + isc_arg_string, (ISC_STATUS) "Duplicate UDR function", + //// TODO: isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) name, + isc_arg_end + }; + + throw FbException(status, statusVector); + } + + functionsMap.put(name, factory); + } + + void registerProcedure(ThrowStatusWrapper* status, const char* name, + IUdrProcedureFactory* factory) + { + if (proceduresMap.exist(name)) + { + static const ISC_STATUS statusVector[] = { + isc_arg_gds, isc_random, + isc_arg_string, (ISC_STATUS) "Duplicate UDR procedure", + //// TODO: isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) name, + isc_arg_end + }; + + throw FbException(status, statusVector); + } + + proceduresMap.put(name, factory); + } + + void registerTrigger(ThrowStatusWrapper* status, const char* name, + IUdrTriggerFactory* factory) + { + if (triggersMap.exist(name)) + { + static const ISC_STATUS statusVector[] = { + isc_arg_gds, isc_random, + isc_arg_string, (ISC_STATUS) "Duplicate UDR trigger", + //// TODO: isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) name, + isc_arg_end + }; + + throw FbException(status, statusVector); + } + + triggersMap.put(name, factory); + } + +private: + PathName moduleName; + ModuleLoader::Module* module; + +public: + FB_BOOLEAN myUnloadFlag; + FB_BOOLEAN* theirUnloadFlag; + GenericMap > > functionsMap; + GenericMap > > proceduresMap; + GenericMap > > triggersMap; +}; + + class SharedFunction : public DisposeIface > { public: @@ -212,10 +289,12 @@ public: info(*getDefaultMemoryPool()), children(*getDefaultMemoryPool()) { - engine->loadModule(status, metadata, &moduleName, &entryPoint); - FunctionNode* node = engine->findNode( - status, registeredFunctions, moduleName, entryPoint); - node->factory->setup(status, context, metadata, inBuilder, outBuilder); + module = engine->loadModule(status, metadata, &moduleName, &entryPoint); + + IUdrFunctionFactory* factory = engine->findNode( + status, module->functionsMap, entryPoint); + + factory->setup(status, context, metadata, inBuilder, outBuilder); } ~SharedFunction() @@ -235,8 +314,8 @@ public: { strncpy(name, context->getClientCharSet(), nameSize); - IExternalFunction* function = engine->getChild(status, - children, this, context, registeredFunctions, engine->functions, moduleName); + IExternalFunction* function = engine->getChild( + status, children, this, context, engine->functions, moduleName); if (function) function->getCharSet(status, context, name, nameSize); @@ -244,8 +323,9 @@ public: void execute(ThrowStatusWrapper* status, IExternalContext* context, void* inMsg, void* outMsg) { - IExternalFunction* function = engine->getChild(status, - children, this, context, registeredFunctions, engine->functions, moduleName); + IExternalFunction* function = engine->getChild( + status, children, this, context, engine->functions, moduleName); + if (function) function->execute(status, context, inMsg, outMsg); } @@ -257,6 +337,7 @@ public: string entryPoint; string info; GenericMap > > children; + UdrPluginImpl* module; }; @@ -276,10 +357,12 @@ public: info(*getDefaultMemoryPool()), children(*getDefaultMemoryPool()) { - engine->loadModule(status, metadata, &moduleName, &entryPoint); - ProcedureNode* node = engine->findNode( - status, registeredProcedures, moduleName, entryPoint); - node->factory->setup(status, context, metadata, inBuilder, outBuilder); + module = engine->loadModule(status, metadata, &moduleName, &entryPoint); + + IUdrProcedureFactory* factory = engine->findNode( + status, module->proceduresMap, entryPoint); + + factory->setup(status, context, metadata, inBuilder, outBuilder); } ~SharedProcedure() @@ -299,8 +382,8 @@ public: { strncpy(name, context->getClientCharSet(), nameSize); - IExternalProcedure* procedure = engine->getChild(status, - children, this, context, registeredProcedures, engine->procedures, moduleName); + IExternalProcedure* procedure = engine->getChild( + status, children, this, context, engine->procedures, moduleName); if (procedure) procedure->getCharSet(status, context, name, nameSize); @@ -309,8 +392,8 @@ public: IExternalResultSet* open(ThrowStatusWrapper* status, IExternalContext* context, void* inMsg, void* outMsg) { - IExternalProcedure* procedure = engine->getChild(status, - children, this, context, registeredProcedures, engine->procedures, moduleName); + IExternalProcedure* procedure = engine->getChild( + status, children, this, context, engine->procedures, moduleName); return procedure ? procedure->open(status, context, inMsg, outMsg) : NULL; } @@ -322,6 +405,7 @@ public: string entryPoint; string info; GenericMap > > children; + UdrPluginImpl* module; }; @@ -340,12 +424,12 @@ public: info(*getDefaultMemoryPool()), children(*getDefaultMemoryPool()) { - engine->loadModule(status, metadata, &moduleName, &entryPoint); + module = engine->loadModule(status, metadata, &moduleName, &entryPoint); - TriggerNode* node = engine->findNode(status, - registeredTriggers, moduleName, entryPoint); + IUdrTriggerFactory* factory = engine->findNode( + status, module->triggersMap, entryPoint); - node->factory->setup(status, context, metadata, fieldsBuilder); + factory->setup(status, context, metadata, fieldsBuilder); } ~SharedTrigger() @@ -365,8 +449,8 @@ public: { strncpy(name, context->getClientCharSet(), nameSize); - IExternalTrigger* trigger = engine->getChild(status, - children, this, context, registeredTriggers, engine->triggers, moduleName); + IExternalTrigger* trigger = engine->getChild( + status, children, this, context, engine->triggers, moduleName); if (trigger) trigger->getCharSet(status, context, name, nameSize); @@ -375,8 +459,9 @@ public: void execute(ThrowStatusWrapper* status, IExternalContext* context, unsigned action, void* oldMsg, void* newMsg) { - IExternalTrigger* trigger = engine->getChild(status, - children, this, context, registeredTriggers, engine->triggers, moduleName); + IExternalTrigger* trigger = engine->getChild( + status, children, this, context, engine->triggers, moduleName); + if (trigger) trigger->execute(status, context, action, oldMsg, newMsg); } @@ -388,68 +473,43 @@ public: string entryPoint; string info; GenericMap > > children; + UdrPluginImpl* module; }; //-------------------------------------- -extern "C" void FB_EXPORTED fbUdrRegFunction(const char* name, IUdrFunctionFactory* factory) +template GenericMap > >& getFactoryMap( + UdrPluginImpl* udrPlugin) { - FunctionNode* node = new FunctionNode(); - node->name = name; - node->module = loadingModule(); - node->factory = factory; - node->next = registeredFunctions; - registeredFunctions = node; + fb_assert(false); +} + +template <> GenericMap > >& getFactoryMap( + UdrPluginImpl* udrPlugin) +{ + return udrPlugin->functionsMap; +} + +template <> GenericMap > >& getFactoryMap( + UdrPluginImpl* udrPlugin) +{ + return udrPlugin->proceduresMap; +} + +template <> GenericMap > >& getFactoryMap( + UdrPluginImpl* udrPlugin) +{ + return udrPlugin->triggersMap; } -extern "C" void FB_EXPORTED fbUdrRegProcedure(const char* name, IUdrProcedureFactory* factory) -{ - ProcedureNode* node = new ProcedureNode(); - node->name = name; - node->module = loadingModule(); - node->factory = factory; - node->next = registeredProcedures; - registeredProcedures = node; -} - - -extern "C" void FB_EXPORTED fbUdrRegTrigger(const char* name, IUdrTriggerFactory* factory) -{ - TriggerNode* node = new TriggerNode(); - node->name = name; - node->module = loadingModule(); - node->factory = factory; - node->next = registeredTriggers; - registeredTriggers = node; -} +//-------------------------------------- ModulesMap::~ModulesMap() { - while (registeredFunctions) - { - FunctionNode* del = registeredFunctions; - registeredFunctions = registeredFunctions->next; - delete del; - } - - while (registeredProcedures) - { - ProcedureNode* del = registeredProcedures; - registeredProcedures = registeredProcedures->next; - delete del; - } - - while (registeredTriggers) - { - TriggerNode* del = registeredTriggers; - registeredTriggers = registeredTriggers->next; - delete del; - } - Accessor accessor(this); for (bool cont = accessor.getFirst(); cont; cont = accessor.getNext()) delete accessor.current()->second; @@ -459,7 +519,7 @@ ModulesMap::~ModulesMap() //-------------------------------------- -void Engine::loadModule(ThrowStatusWrapper* status, IRoutineMetadata* metadata, +UdrPluginImpl* Engine::loadModule(ThrowStatusWrapper* status, IRoutineMetadata* metadata, PathName* moduleName, string* entryPoint) { const string str(metadata->getEntryPoint(status)); @@ -468,9 +528,9 @@ void Engine::loadModule(ThrowStatusWrapper* status, IRoutineMetadata* metadata, if (pos == string::npos) { static const ISC_STATUS statusVector[] = { - isc_arg_gds, - isc_random, + isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) "Invalid entry point", + //// TODO: isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) entryPoint.c_str(), isc_arg_end }; @@ -482,9 +542,9 @@ void Engine::loadModule(ThrowStatusWrapper* status, IRoutineMetadata* metadata, if (moduleName->find_first_of("/\\") != string::npos) { static const ISC_STATUS statusVector[] = { - isc_arg_gds, - isc_random, + isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) "Invalid module name", + //// TODO: isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) moduleName->c_str(), isc_arg_end }; @@ -498,10 +558,10 @@ void Engine::loadModule(ThrowStatusWrapper* status, IRoutineMetadata* metadata, MutexLockGuard guard(modulesMutex, FB_FUNCTION); - if (modules->exist(*moduleName)) - return; + UdrPluginImpl* ret; - loadingModule() = *moduleName; + if (modules->get(*moduleName, ret)) + return ret; for (ObjectsArray::iterator i = paths->begin(); i != paths->end(); ++i) { @@ -512,27 +572,59 @@ void Engine::loadModule(ThrowStatusWrapper* status, IRoutineMetadata* metadata, if (module) { - modules->put(*moduleName, module); - break; + FB_BOOLEAN* (*entryPoint)(IStatus*, FB_BOOLEAN*, IUdrPlugin*); + + if (!module->findSymbol(STRINGIZE(FB_UDR_PLUGIN_ENTRY_POINT), entryPoint)) + { + static const ISC_STATUS statusVector[] = { + isc_arg_gds, isc_random, + isc_arg_string, (ISC_STATUS) "UDR plugin entry point not found", + isc_arg_end + }; + + throw FbException(status, statusVector); + } + + UdrPluginImpl* udrPlugin = new UdrPluginImpl(*moduleName, module); + udrPlugin->theirUnloadFlag = entryPoint(status, &udrPlugin->myUnloadFlag, udrPlugin); + + if (status->getStatus() & IStatus::FB_HAS_ERRORS) + { + delete udrPlugin; + ThrowStatusWrapper::checkException(status); + } + + modules->put(*moduleName, udrPlugin); + + return udrPlugin; } else { static const ISC_STATUS statusVector[] = { - isc_arg_gds, - isc_random, + isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) "Module not found", + //// TODO: isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) moduleName->c_str(), isc_arg_end }; throw FbException(status, statusVector); } } + + static const ISC_STATUS statusVector[] = { + isc_arg_gds, isc_random, + isc_arg_string, (ISC_STATUS) "No UDR module path was configured", + isc_arg_end + }; + + throw FbException(status, statusVector); } template ObjType* Engine::getChild( - ThrowStatusWrapper* status, GenericMap > >& children, - SharedObjType* sharedObj, IExternalContext* context, NodeType* nodes, + ThrowStatusWrapper* status, + GenericMap > >& children, SharedObjType* sharedObj, + IExternalContext* context, SortedArray& sharedObjs, const PathName& moduleName) { MutexLockGuard guard(childrenMutex, FB_FUNCTION); @@ -543,8 +635,11 @@ template ObjType* ObjType* obj; if (!children.get(context, obj)) { - obj = getNode(status, nodes, moduleName, context, sharedObj->metadata, - sharedObj->entryPoint); + GenericMap > >& nodes = getFactoryMap( + sharedObj->module); + + NodeType* factory = findNode(status, nodes, sharedObj->entryPoint); + obj = factory->newItem(status, context, sharedObj->metadata); if (obj) children.put(context, obj); @@ -567,19 +662,18 @@ template void Engine::deleteChildren( } -template T* Engine::findNode(ThrowStatusWrapper* status, T* nodes, - const PathName& moduleName, const string& entryPoint) +template T* Engine::findNode(ThrowStatusWrapper* status, + const GenericMap > >& nodes, const string& entryPoint) { - for (T* node = nodes; node; node = node->next) - { - if (node->module == moduleName && entryPoint == node->name) - return node; - } + T* factory; + + if (nodes.get(entryPoint, factory)) + return factory; static const ISC_STATUS statusVector[] = { - isc_arg_gds, - isc_random, + isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) "Entry point not found", + //// TODO: isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) entryPoint.c_str(), isc_arg_end }; @@ -589,15 +683,6 @@ template T* Engine::findNode(ThrowStatusWrapper* status, T* nodes, } -template T2* Engine::getNode(ThrowStatusWrapper* status, T* nodes, - const PathName& moduleName, IExternalContext* context, IRoutineMetadata* metadata, - const string& entryPoint) -{ - T* node = findNode(status, nodes, moduleName, entryPoint); - return node->factory->newItem(status, context, metadata); -} - - void Engine::open(ThrowStatusWrapper* /*status*/, IExternalContext* /*context*/, char* name, unsigned nameSize) { strncpy(name, "UTF-8", nameSize);