1 | /* |
2 | * The contents of this file are subject to the Initial |
3 | * Developer's Public License Version 1.0 (the "License"); |
4 | * you may not use this file except in compliance with the |
5 | * License. You may obtain a copy of the License at |
6 | * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. |
7 | * |
8 | * Software distributed under the License is distributed AS IS, |
9 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. |
10 | * See the License for the specific language governing rights |
11 | * and limitations under the License. |
12 | * |
13 | * The Original Code was created by Adriano dos Santos Fernandes |
14 | * for the Firebird Open Source RDBMS project. |
15 | * |
16 | * Copyright (c) 2008 Adriano dos Santos Fernandes <adrianosf@uol.com.br> |
17 | * and all contributors signed below. |
18 | * |
19 | * All Rights Reserved. |
20 | * Contributor(s): ______________________________________. |
21 | */ |
22 | |
23 | #include "firebird.h" |
24 | #include "../jrd/ibase.h" |
25 | #include "firebird/UdrEngine.h" |
26 | #include "firebird/UdrCppEngine.h" |
27 | #include "firebird/Plugin.h" |
28 | #include "firebird/ExternalEngine.h" |
29 | #include "../common/classes/alloc.h" |
30 | #include "../common/classes/array.h" |
31 | #include "../common/classes/init.h" |
32 | #include "../common/classes/fb_string.h" |
33 | #include "../common/classes/GenericMap.h" |
34 | #include "../common/classes/objects_array.h" |
35 | #include "../common/os/mod_loader.h" |
36 | #include "../common/os/path_utils.h" |
37 | #include "../common/classes/ImplementHelper.h" |
38 | #include "../common/StatusHolder.h" |
39 | |
40 | |
41 | namespace Firebird |
42 | { |
43 | namespace Udr |
44 | { |
45 | //------------------------------------------------------------------------------ |
46 | |
47 | |
48 | struct Node |
49 | { |
50 | Node() |
51 | : name(*getDefaultMemoryPool()), |
52 | module(*getDefaultMemoryPool()) |
53 | { |
54 | } |
55 | |
56 | string name; |
57 | PathName module; |
58 | }; |
59 | |
60 | struct FunctionNode : public Node |
61 | { |
62 | FunctionFactory* factory; |
63 | FunctionNode* next; |
64 | }; |
65 | |
66 | struct ProcedureNode : public Node |
67 | { |
68 | ProcedureFactory* factory; |
69 | ProcedureNode* next; |
70 | }; |
71 | |
72 | struct TriggerNode : public Node |
73 | { |
74 | TriggerFactory* factory; |
75 | TriggerNode* next; |
76 | }; |
77 | |
78 | |
79 | static GlobalPtr<ObjectsArray<PathName> > paths; |
80 | |
81 | class Engine : public StdPlugin<ExternalEngine, FB_EXTERNAL_ENGINE_VERSION> |
82 | { |
83 | public: |
84 | explicit Engine(IPluginConfig* par) |
85 | : functions(getPool()), |
86 | procedures(getPool()), |
87 | triggers(getPool()) |
88 | { |
89 | RefPtr<IConfig> defaultConfig(REF_NO_INCR, par->getDefaultConfig()); |
90 | |
91 | if (defaultConfig) |
92 | { |
93 | // this plugin is not ready to support different configurations |
94 | // therefore keep legacy approach |
95 | |
96 | RefPtr<IConfigEntry> icp; |
97 | |
98 | for (int n = 0; icp.assignRefNoIncr(defaultConfig->findPos("path" , n)); ++n) |
99 | { |
100 | PathName newPath(icp->getValue()); |
101 | |
102 | bool found = false; |
103 | |
104 | for (ObjectsArray<PathName>::iterator i = paths->begin(); i != paths->end(); ++i) |
105 | { |
106 | if (*i == newPath) |
107 | { |
108 | found = true; |
109 | break; |
110 | } |
111 | } |
112 | |
113 | if (!found) |
114 | paths->add(newPath); |
115 | } |
116 | } |
117 | } |
118 | |
119 | int FB_CARG release() |
120 | { |
121 | if (--refCounter == 0) |
122 | { |
123 | delete this; |
124 | return 0; |
125 | } |
126 | |
127 | return 1; |
128 | } |
129 | |
130 | public: |
131 | void loadModule(const IRoutineMetadata* metadata, PathName* moduleName, string* entryPoint); |
132 | template <typename NodeType, typename ObjType, typename SharedObjType> ObjType* getChild( |
133 | IStatus* status, GenericMap<Pair<NonPooled<ExternalContext*, ObjType*> > >& children, |
134 | SharedObjType* sharedObj, ExternalContext* context, NodeType* nodes, |
135 | SortedArray<SharedObjType*>& sharedObjs, const PathName& moduleName); |
136 | template <typename ObjType> void deleteChildren( |
137 | GenericMap<Pair<NonPooled<ExternalContext*, ObjType*> > >& children); |
138 | |
139 | template <typename T> T* findNode(T* nodes, const PathName& moduleName, |
140 | const string& entryPoint); |
141 | |
142 | private: |
143 | template <typename T, typename T2> T2* getNode(IStatus* status, T* nodes, |
144 | const PathName& moduleName, ExternalContext* context, const IRoutineMetadata* metadata, |
145 | const string& entryPoint); |
146 | |
147 | public: |
148 | virtual void FB_CARG open(IStatus* status, ExternalContext* context, Utf8* name, uint nameSize); |
149 | virtual void FB_CARG openAttachment(IStatus* status, ExternalContext* context); |
150 | virtual void FB_CARG closeAttachment(IStatus* status, ExternalContext* context); |
151 | virtual ExternalFunction* FB_CARG makeFunction(IStatus* status, ExternalContext* context, |
152 | const IRoutineMetadata* metadata, IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder); |
153 | virtual ExternalProcedure* FB_CARG makeProcedure(IStatus* status, ExternalContext* context, |
154 | const IRoutineMetadata* metadata, IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder); |
155 | virtual ExternalTrigger* FB_CARG makeTrigger(IStatus* status, ExternalContext* context, |
156 | const IRoutineMetadata* metadata, IMetadataBuilder* fieldsBuilder); |
157 | |
158 | public: |
159 | virtual void FB_CARG dispose(); |
160 | |
161 | private: |
162 | Mutex childrenMutex; |
163 | |
164 | public: |
165 | SortedArray<class SharedFunction*> functions; |
166 | SortedArray<class SharedProcedure*> procedures; |
167 | SortedArray<class SharedTrigger*> triggers; |
168 | }; |
169 | |
170 | |
171 | class ModulesMap : public GenericMap<Pair<Left<PathName, ModuleLoader::Module*> > > |
172 | { |
173 | public: |
174 | explicit ModulesMap(MemoryPool& p) |
175 | : GenericMap<Pair<Left<PathName, ModuleLoader::Module*> > >(p) |
176 | { |
177 | } |
178 | |
179 | ~ModulesMap(); |
180 | }; |
181 | |
182 | |
183 | //-------------------------------------- |
184 | |
185 | |
186 | static AutoPtr<ModuleLoader::Module> libraryModule; |
187 | |
188 | static GlobalPtr<Mutex> modulesMutex; |
189 | static GlobalPtr<ModulesMap> modules; |
190 | |
191 | static InitInstance<PathName> loadingModule; |
192 | static FunctionNode* registeredFunctions = NULL; |
193 | static ProcedureNode* registeredProcedures = NULL; |
194 | static TriggerNode* registeredTriggers = NULL; |
195 | |
196 | |
197 | //-------------------------------------- |
198 | |
199 | |
200 | class SharedFunction : public DisposeIface<ExternalFunction, FB_EXTERNAL_FUNCTION_VERSION> |
201 | { |
202 | public: |
203 | SharedFunction(IStatus* status, Engine* aEngine, ExternalContext* context, |
204 | const IRoutineMetadata* aMetadata, |
205 | IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder) |
206 | : engine(aEngine), |
207 | metadata(aMetadata), |
208 | moduleName(*getDefaultMemoryPool()), |
209 | entryPoint(*getDefaultMemoryPool()), |
210 | info(*getDefaultMemoryPool()), |
211 | children(*getDefaultMemoryPool()) |
212 | { |
213 | engine->loadModule(metadata, &moduleName, &entryPoint); |
214 | FunctionNode* node = engine->findNode<FunctionNode>( |
215 | registeredFunctions, moduleName, entryPoint); |
216 | node->factory->setup(status, context, metadata, inBuilder, outBuilder); |
217 | } |
218 | |
219 | ~SharedFunction() |
220 | { |
221 | engine->deleteChildren(children); |
222 | } |
223 | |
224 | public: |
225 | virtual void FB_CARG dispose() |
226 | { |
227 | delete this; |
228 | } |
229 | |
230 | public: |
231 | virtual void FB_CARG getCharSet(IStatus* status, ExternalContext* context, |
232 | Utf8* name, uint nameSize) |
233 | { |
234 | strncpy(name, context->getClientCharSet(), nameSize); |
235 | |
236 | try |
237 | { |
238 | ExternalFunction* function = engine->getChild<FunctionNode, ExternalFunction>(status, |
239 | children, this, context, registeredFunctions, engine->functions, moduleName); |
240 | if (function) |
241 | function->getCharSet(status, context, name, nameSize); |
242 | } |
243 | catch (const StatusException& e) |
244 | { |
245 | e.stuff(status); |
246 | } |
247 | } |
248 | |
249 | virtual void FB_CARG execute(IStatus* status, ExternalContext* context, void* inMsg, void* outMsg) |
250 | { |
251 | ExternalFunction* function = engine->getChild<FunctionNode, ExternalFunction>(status, |
252 | children, this, context, registeredFunctions, engine->functions, moduleName); |
253 | if (function) |
254 | function->execute(status, context, inMsg, outMsg); |
255 | } |
256 | |
257 | public: |
258 | Engine* engine; |
259 | const IRoutineMetadata* metadata; |
260 | PathName moduleName; |
261 | string entryPoint; |
262 | string info; |
263 | GenericMap<Pair<NonPooled<ExternalContext*, ExternalFunction*> > > children; |
264 | }; |
265 | |
266 | |
267 | //-------------------------------------- |
268 | |
269 | |
270 | class SharedProcedure : public DisposeIface<ExternalProcedure, FB_EXTERNAL_PROCEDURE_VERSION> |
271 | { |
272 | public: |
273 | SharedProcedure(IStatus* status, Engine* aEngine, ExternalContext* context, |
274 | const IRoutineMetadata* aMetadata, |
275 | IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder) |
276 | : engine(aEngine), |
277 | metadata(aMetadata), |
278 | moduleName(*getDefaultMemoryPool()), |
279 | entryPoint(*getDefaultMemoryPool()), |
280 | info(*getDefaultMemoryPool()), |
281 | children(*getDefaultMemoryPool()) |
282 | { |
283 | engine->loadModule(metadata, &moduleName, &entryPoint); |
284 | ProcedureNode* node = engine->findNode<ProcedureNode>( |
285 | registeredProcedures, moduleName, entryPoint); |
286 | node->factory->setup(status, context, metadata, inBuilder, outBuilder); |
287 | } |
288 | |
289 | ~SharedProcedure() |
290 | { |
291 | engine->deleteChildren(children); |
292 | } |
293 | |
294 | public: |
295 | virtual void FB_CARG dispose() |
296 | { |
297 | delete this; |
298 | } |
299 | |
300 | public: |
301 | virtual void FB_CARG getCharSet(IStatus* status, ExternalContext* context, |
302 | Utf8* name, uint nameSize) |
303 | { |
304 | strncpy(name, context->getClientCharSet(), nameSize); |
305 | |
306 | try |
307 | { |
308 | ExternalProcedure* procedure = engine->getChild<ProcedureNode, ExternalProcedure>(status, |
309 | children, this, context, registeredProcedures, engine->procedures, moduleName); |
310 | if (procedure) |
311 | procedure->getCharSet(status, context, name, nameSize); |
312 | } |
313 | catch (const StatusException& e) |
314 | { |
315 | e.stuff(status); |
316 | } |
317 | } |
318 | |
319 | virtual ExternalResultSet* FB_CARG open(IStatus* status, ExternalContext* context, |
320 | void* inMsg, void* outMsg) |
321 | { |
322 | try |
323 | { |
324 | ExternalProcedure* procedure = engine->getChild<ProcedureNode, ExternalProcedure>(status, |
325 | children, this, context, registeredProcedures, engine->procedures, moduleName); |
326 | return procedure ? procedure->open(status, context, inMsg, outMsg) : NULL; |
327 | } |
328 | catch (const StatusException& e) |
329 | { |
330 | e.stuff(status); |
331 | return NULL; |
332 | } |
333 | } |
334 | |
335 | public: |
336 | Engine* engine; |
337 | const IRoutineMetadata* metadata; |
338 | PathName moduleName; |
339 | string entryPoint; |
340 | string info; |
341 | GenericMap<Pair<NonPooled<ExternalContext*, ExternalProcedure*> > > children; |
342 | }; |
343 | |
344 | |
345 | //-------------------------------------- |
346 | |
347 | |
348 | class SharedTrigger : public DisposeIface<ExternalTrigger, FB_EXTERNAL_TRIGGER_VERSION> |
349 | { |
350 | public: |
351 | SharedTrigger(IStatus* status, Engine* aEngine, ExternalContext* context, |
352 | const IRoutineMetadata* aMetadata, IMetadataBuilder* fieldsBuilder) |
353 | : engine(aEngine), |
354 | metadata(aMetadata), |
355 | moduleName(*getDefaultMemoryPool()), |
356 | entryPoint(*getDefaultMemoryPool()), |
357 | info(*getDefaultMemoryPool()), |
358 | children(*getDefaultMemoryPool()) |
359 | { |
360 | engine->loadModule(metadata, &moduleName, &entryPoint); |
361 | TriggerNode* node = engine->findNode<TriggerNode>(registeredTriggers, moduleName, entryPoint); |
362 | node->factory->setup(status, context, metadata, fieldsBuilder); |
363 | } |
364 | |
365 | ~SharedTrigger() |
366 | { |
367 | engine->deleteChildren(children); |
368 | } |
369 | |
370 | public: |
371 | virtual void FB_CARG dispose() |
372 | { |
373 | delete this; |
374 | } |
375 | |
376 | public: |
377 | virtual void FB_CARG getCharSet(IStatus* status, ExternalContext* context, |
378 | Utf8* name, uint nameSize) |
379 | { |
380 | strncpy(name, context->getClientCharSet(), nameSize); |
381 | |
382 | try |
383 | { |
384 | ExternalTrigger* trigger = engine->getChild<TriggerNode, ExternalTrigger>(status, |
385 | children, this, context, registeredTriggers, engine->triggers, moduleName); |
386 | if (trigger) |
387 | trigger->getCharSet(status, context, name, nameSize); |
388 | } |
389 | catch (const StatusException& e) |
390 | { |
391 | e.stuff(status); |
392 | } |
393 | } |
394 | |
395 | virtual void FB_CARG execute(IStatus* status, ExternalContext* context, |
396 | ExternalTrigger::Action action, void* oldMsg, void* newMsg) |
397 | { |
398 | ExternalTrigger* trigger = engine->getChild<TriggerNode, ExternalTrigger>(status, |
399 | children, this, context, registeredTriggers, engine->triggers, moduleName); |
400 | if (trigger) |
401 | trigger->execute(status, context, action, oldMsg, newMsg); |
402 | } |
403 | |
404 | public: |
405 | Engine* engine; |
406 | const IRoutineMetadata* metadata; |
407 | PathName moduleName; |
408 | string entryPoint; |
409 | string info; |
410 | GenericMap<Pair<NonPooled<ExternalContext*, ExternalTrigger*> > > children; |
411 | }; |
412 | |
413 | |
414 | //-------------------------------------- |
415 | |
416 | |
417 | extern "C" void fbUdrRegFunction(const char* name, FunctionFactory* factory) |
418 | { |
419 | FunctionNode* node = new FunctionNode(); |
420 | node->name = name; |
421 | node->module = loadingModule(); |
422 | node->factory = factory; |
423 | node->next = registeredFunctions; |
424 | registeredFunctions = node; |
425 | } |
426 | |
427 | |
428 | extern "C" void fbUdrRegProcedure(const char* name, ProcedureFactory* factory) |
429 | { |
430 | ProcedureNode* node = new ProcedureNode(); |
431 | node->name = name; |
432 | node->module = loadingModule(); |
433 | node->factory = factory; |
434 | node->next = registeredProcedures; |
435 | registeredProcedures = node; |
436 | } |
437 | |
438 | |
439 | extern "C" void fbUdrRegTrigger(const char* name, TriggerFactory* factory) |
440 | { |
441 | TriggerNode* node = new TriggerNode(); |
442 | node->name = name; |
443 | node->module = loadingModule(); |
444 | node->factory = factory; |
445 | node->next = registeredTriggers; |
446 | registeredTriggers = node; |
447 | } |
448 | |
449 | |
450 | ModulesMap::~ModulesMap() |
451 | { |
452 | while (registeredFunctions) |
453 | { |
454 | FunctionNode* del = registeredFunctions; |
455 | registeredFunctions = registeredFunctions->next; |
456 | delete del; |
457 | } |
458 | |
459 | while (registeredProcedures) |
460 | { |
461 | ProcedureNode* del = registeredProcedures; |
462 | registeredProcedures = registeredProcedures->next; |
463 | delete del; |
464 | } |
465 | |
466 | while (registeredTriggers) |
467 | { |
468 | TriggerNode* del = registeredTriggers; |
469 | registeredTriggers = registeredTriggers->next; |
470 | delete del; |
471 | } |
472 | |
473 | Accessor accessor(this); |
474 | for (bool cont = accessor.getFirst(); cont; cont = accessor.getNext()) |
475 | delete accessor.current()->second; |
476 | } |
477 | |
478 | |
479 | //-------------------------------------- |
480 | |
481 | |
482 | void Engine::loadModule(const IRoutineMetadata* metadata, PathName* moduleName, string* entryPoint) |
483 | { |
484 | LocalStatus status; |
485 | const string str(metadata->getEntryPoint(&status)); |
486 | StatusException::check(status.get()); |
487 | |
488 | const size_t pos = str.find('!'); |
489 | if (pos == string::npos) |
490 | { |
491 | static const ISC_STATUS statusVector[] = { |
492 | isc_arg_gds, |
493 | isc_random, |
494 | isc_arg_string, (ISC_STATUS) "Invalid entry point" , |
495 | isc_arg_end |
496 | }; |
497 | |
498 | StatusException::check(statusVector); |
499 | } |
500 | |
501 | *moduleName = PathName(str.substr(0, pos).c_str()); |
502 | // Do not allow module names with directory separators as a security measure. |
503 | if (moduleName->find_first_of("/\\" ) != string::npos) |
504 | { |
505 | static const ISC_STATUS statusVector[] = { |
506 | isc_arg_gds, |
507 | isc_random, |
508 | isc_arg_string, (ISC_STATUS) "Invalid module name" , |
509 | isc_arg_end |
510 | }; |
511 | |
512 | StatusException::check(statusVector); |
513 | } |
514 | |
515 | *entryPoint = str.substr(pos + 1); |
516 | |
517 | size_t n = entryPoint->find('!'); |
518 | *entryPoint = (n == string::npos ? *entryPoint : entryPoint->substr(0, n)); |
519 | |
520 | MutexLockGuard guard(modulesMutex, FB_FUNCTION); |
521 | |
522 | if (modules->exist(*moduleName)) |
523 | return; |
524 | |
525 | loadingModule() = *moduleName; |
526 | |
527 | for (ObjectsArray<PathName>::iterator i = paths->begin(); i != paths->end(); ++i) |
528 | { |
529 | PathName path; |
530 | PathUtils::concatPath(path, *i, *moduleName); |
531 | |
532 | ModuleLoader::Module* module = ModuleLoader::fixAndLoadModule(path); |
533 | |
534 | if (module) |
535 | { |
536 | modules->put(*moduleName, module); |
537 | break; |
538 | } |
539 | else |
540 | { |
541 | static const ISC_STATUS statusVector[] = { |
542 | isc_arg_gds, |
543 | isc_random, |
544 | isc_arg_string, (ISC_STATUS) "Module not found" , |
545 | isc_arg_end |
546 | }; |
547 | |
548 | StatusException::check(statusVector); |
549 | } |
550 | } |
551 | } |
552 | |
553 | |
554 | template <typename NodeType, typename ObjType, typename SharedObjType> ObjType* Engine::getChild( |
555 | IStatus* status, GenericMap<Pair<NonPooled<ExternalContext*, ObjType*> > >& children, |
556 | SharedObjType* sharedObj, ExternalContext* context, NodeType* nodes, |
557 | SortedArray<SharedObjType*>& sharedObjs, const PathName& moduleName) |
558 | { |
559 | MutexLockGuard guard(childrenMutex, FB_FUNCTION); |
560 | |
561 | if (!sharedObjs.exist(sharedObj)) |
562 | sharedObjs.add(sharedObj); |
563 | |
564 | ObjType* obj; |
565 | if (!children.get(context, obj)) |
566 | { |
567 | obj = getNode<NodeType, ObjType>(status, nodes, moduleName, context, sharedObj->metadata, |
568 | sharedObj->entryPoint); |
569 | |
570 | if (obj) |
571 | children.put(context, obj); |
572 | } |
573 | |
574 | return obj; |
575 | } |
576 | |
577 | |
578 | template <typename ObjType> void Engine::deleteChildren( |
579 | GenericMap<Pair<NonPooled<ExternalContext*, ObjType*> > >& children) |
580 | { |
581 | // No need to lock childrenMutex as if there are more threads simultaneously accessing |
582 | // these children in this moment there will be a memory corruption anyway. |
583 | |
584 | typedef typename GenericMap<Pair<NonPooled<ExternalContext*, ObjType*> > >::Accessor ChildrenAccessor; |
585 | ChildrenAccessor accessor(&children); |
586 | for (bool found = accessor.getFirst(); found; found = accessor.getNext()) |
587 | delete accessor.current()->second; |
588 | } |
589 | |
590 | |
591 | template <typename T> T* Engine::findNode(T* nodes, const PathName& moduleName, |
592 | const string& entryPoint) |
593 | { |
594 | for (T* node = nodes; node; node = node->next) |
595 | { |
596 | if (node->module == moduleName && entryPoint == node->name) |
597 | return node; |
598 | } |
599 | |
600 | static const ISC_STATUS statusVector[] = { |
601 | isc_arg_gds, |
602 | isc_random, |
603 | isc_arg_string, (ISC_STATUS) "Entry point not found" , |
604 | isc_arg_end |
605 | }; |
606 | |
607 | StatusException::check(statusVector); |
608 | |
609 | return NULL; |
610 | } |
611 | |
612 | |
613 | template <typename T, typename T2> T2* Engine::getNode(IStatus* status, T* nodes, |
614 | const PathName& moduleName, ExternalContext* context, const IRoutineMetadata* metadata, |
615 | const string& entryPoint) |
616 | { |
617 | T* node = findNode<T>(nodes, moduleName, entryPoint); |
618 | return node->factory->newItem(status, context, metadata); |
619 | } |
620 | |
621 | |
622 | void FB_CARG Engine::open(IStatus* /*status*/, ExternalContext* /*context*/, Utf8* name, uint nameSize) |
623 | { |
624 | strncpy(name, "UTF-8" , nameSize); |
625 | } |
626 | |
627 | |
628 | void FB_CARG Engine::openAttachment(IStatus* /*status*/, ExternalContext* /*context*/) |
629 | { |
630 | } |
631 | |
632 | |
633 | void FB_CARG Engine::closeAttachment(IStatus* status, ExternalContext* context) |
634 | { |
635 | MutexLockGuard guard(childrenMutex, FB_FUNCTION); |
636 | |
637 | for (SortedArray<SharedFunction*>::iterator i = functions.begin(); i != functions.end(); ++i) |
638 | { |
639 | ExternalFunction* function; |
640 | if ((*i)->children.get(context, function)) |
641 | { |
642 | function->dispose(); |
643 | (*i)->children.remove(context); |
644 | } |
645 | } |
646 | |
647 | for (SortedArray<SharedProcedure*>::iterator i = procedures.begin(); i != procedures.end(); ++i) |
648 | { |
649 | ExternalProcedure* procedure; |
650 | if ((*i)->children.get(context, procedure)) |
651 | { |
652 | procedure->dispose(); |
653 | (*i)->children.remove(context); |
654 | } |
655 | } |
656 | |
657 | for (SortedArray<SharedTrigger*>::iterator i = triggers.begin(); i != triggers.end(); ++i) |
658 | { |
659 | ExternalTrigger* trigger; |
660 | if ((*i)->children.get(context, trigger)) |
661 | { |
662 | trigger->dispose(); |
663 | (*i)->children.remove(context); |
664 | } |
665 | } |
666 | } |
667 | |
668 | |
669 | ExternalFunction* FB_CARG Engine::makeFunction(IStatus* status, ExternalContext* context, |
670 | const IRoutineMetadata* metadata, IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder) |
671 | { |
672 | try |
673 | { |
674 | return new SharedFunction(status, this, context, metadata, inBuilder, outBuilder); |
675 | } |
676 | catch (const StatusException& e) |
677 | { |
678 | e.stuff(status); |
679 | return NULL; |
680 | } |
681 | } |
682 | |
683 | |
684 | ExternalProcedure* FB_CARG Engine::makeProcedure(IStatus* status, ExternalContext* context, |
685 | const IRoutineMetadata* metadata, IMetadataBuilder* inBuilder, IMetadataBuilder* outBuilder) |
686 | { |
687 | try |
688 | { |
689 | return new SharedProcedure(status, this, context, metadata, inBuilder, outBuilder); |
690 | } |
691 | catch (const StatusException& e) |
692 | { |
693 | e.stuff(status); |
694 | return NULL; |
695 | } |
696 | } |
697 | |
698 | |
699 | ExternalTrigger* FB_CARG Engine::makeTrigger(IStatus* status, ExternalContext* context, |
700 | const IRoutineMetadata* metadata, IMetadataBuilder* fieldsBuilder) |
701 | { |
702 | try |
703 | { |
704 | return new SharedTrigger(status, this, context, metadata, fieldsBuilder); |
705 | } |
706 | catch (const StatusException& e) |
707 | { |
708 | e.stuff(status); |
709 | return NULL; |
710 | } |
711 | } |
712 | |
713 | |
714 | void FB_CARG Engine::dispose() |
715 | { |
716 | delete this; |
717 | } |
718 | |
719 | |
720 | //-------------------------------------- |
721 | |
722 | |
723 | class ExternalEngineFactoryImpl : public SimpleFactory<Engine> |
724 | { |
725 | } factory; |
726 | |
727 | extern "C" void FB_PLUGIN_ENTRY_POINT(IMaster* master) |
728 | { |
729 | CachedMasterInterface::set(master); |
730 | |
731 | PluginManagerInterfacePtr pi; |
732 | pi->registerPluginFactory(PluginType::ExternalEngine, "UDR" , &factory); |
733 | myModule->registerMe(); |
734 | |
735 | PathName libraryName("fbclient" ); |
736 | ModuleLoader::doctorModuleExtension(libraryName); |
737 | |
738 | libraryModule.reset(ModuleLoader::loadModule(libraryName)); |
739 | } |
740 | |
741 | |
742 | //------------------------------------------------------------------------------ |
743 | } // namespace Udr |
744 | } // namespace Firebird |
745 | |