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#ifndef FIREBIRD_UDR_CPP_ENGINE
24#define FIREBIRD_UDR_CPP_ENGINE
25
26#include "./ExternalEngine.h"
27#include "./UdrEngine.h"
28#include "./Message.h"
29#ifndef JRD_IBASE_H
30#include "ibase.h"
31#include "iberror.h"
32#endif
33#include <string.h>
34
35
36namespace Firebird
37{
38 namespace Udr
39 {
40//------------------------------------------------------------------------------
41
42
43#define FB_UDR_BEGIN_FUNCTION(name) \
44 namespace Func##name \
45 { \
46 class Impl; \
47 \
48 static ::Firebird::Udr::FunctionFactoryImpl<Impl> factory(#name); \
49 \
50 class Impl : public ::Firebird::Udr::Function<Impl> \
51 { \
52 public: \
53 FB__UDR_COMMON_IMPL
54
55#define FB_UDR_END_FUNCTION \
56 }; \
57 }
58
59#define FB_UDR_EXECUTE_FUNCTION \
60 virtual void FB_CARG execute(::Firebird::IStatus* status, ::Firebird::ExternalContext* context, \
61 void* in, void* out) \
62 { \
63 try \
64 { \
65 internalExecute(status, context, (InMessage::Type*) in, (OutMessage::Type*) out); \
66 } \
67 FB__UDR_CATCH \
68 } \
69 \
70 void internalExecute(::Firebird::IStatus* status, ::Firebird::ExternalContext* context, \
71 InMessage::Type* in, OutMessage::Type* out)
72
73
74#define FB_UDR_BEGIN_PROCEDURE(name) \
75 namespace Proc##name \
76 { \
77 class Impl; \
78 \
79 static ::Firebird::Udr::ProcedureFactoryImpl<Impl> factory(#name); \
80 \
81 class Impl : public ::Firebird::Udr::Procedure<Impl> \
82 { \
83 public: \
84 FB__UDR_COMMON_IMPL
85
86#define FB_UDR_END_PROCEDURE \
87 }; \
88 }; \
89 }
90
91#define FB_UDR_EXECUTE_PROCEDURE \
92 virtual ::Firebird::ExternalResultSet* FB_CARG open(::Firebird::IStatus* status, \
93 ::Firebird::ExternalContext* context, void* in, void* out) \
94 { \
95 try \
96 { \
97 return new ResultSet(status, context, this, (InMessage::Type*) in, (OutMessage::Type*) out); \
98 } \
99 FB__UDR_CATCH \
100 \
101 return NULL; \
102 } \
103 \
104 class ResultSet : public ::Firebird::Udr::ResultSet<ResultSet, Impl, InMessage, OutMessage> \
105 { \
106 public: \
107 ResultSet(::Firebird::IStatus* status, ::Firebird::ExternalContext* context, \
108 Impl* const procedure, InMessage::Type* const in, OutMessage::Type* const out) \
109 : ::Firebird::Udr::ResultSet<ResultSet, Impl, InMessage, OutMessage>( \
110 context, procedure, in, out)
111
112#define FB_UDR_FETCH_PROCEDURE \
113 virtual FB_BOOLEAN FB_CARG fetch(::Firebird::IStatus* status) \
114 { \
115 try \
116 { \
117 return (FB_BOOLEAN) internalFetch(status); \
118 } \
119 FB__UDR_CATCH \
120 \
121 return FB_FALSE; \
122 } \
123 \
124 bool internalFetch(::Firebird::IStatus* status)
125
126
127#define FB_UDR_BEGIN_TRIGGER(name) \
128 namespace Trig##name \
129 { \
130 class Impl; \
131 \
132 static ::Firebird::Udr::TriggerFactoryImpl<Impl> factory(#name); \
133 \
134 class Impl : public ::Firebird::Udr::Trigger<Impl> \
135 { \
136 public: \
137 FB__UDR_COMMON_IMPL
138
139#define FB_UDR_END_TRIGGER \
140 }; \
141 }
142
143#define FB_UDR_EXECUTE_TRIGGER \
144 virtual void FB_CARG execute(::Firebird::IStatus* status, ::Firebird::ExternalContext* context, \
145 ::Firebird::ExternalTrigger::Action action, void* oldFields, void* newFields) \
146 { \
147 try \
148 { \
149 internalExecute(status, context, action, \
150 (FieldsMessage::Type*) oldFields, (FieldsMessage::Type*) newFields); \
151 } \
152 FB__UDR_CATCH \
153 } \
154 \
155 void internalExecute(::Firebird::IStatus* status, ::Firebird::ExternalContext* context, \
156 ::Firebird::ExternalTrigger::Action action, \
157 FieldsMessage::Type* oldFields, FieldsMessage::Type* newFields)
158
159
160#define FB_UDR_CONSTRUCTOR \
161 Impl(::Firebird::IStatus* const status, ::Firebird::ExternalContext* const context, \
162 const ::Firebird::IRoutineMetadata* const metadata__) \
163 : master(context->getMaster()), \
164 metadata(metadata__)
165
166#define FB_UDR_DESTRUCTOR \
167 ~Impl()
168
169
170#define FB__UDR_COMMON_IMPL \
171 Impl(const void* const, ::Firebird::ExternalContext* const context, \
172 const ::Firebird::IRoutineMetadata* const aMetadata) \
173 : master(context->getMaster()), \
174 metadata(aMetadata) \
175 { \
176 } \
177 \
178 ::Firebird::IMaster* master; \
179 const ::Firebird::IRoutineMetadata* metadata;
180
181#define FB__UDR_COMMON_TYPE(name) \
182 struct name \
183 { \
184 typedef unsigned char Type; \
185 static void setup(::Firebird::IStatus*, ::Firebird::IMetadataBuilder*) {} \
186 }
187
188#define FB__UDR_CATCH \
189 catch (const ::Firebird::Udr::StatusException& e) \
190 { \
191 e.stuff(status); \
192 } \
193 catch (...) \
194 { \
195 ISC_STATUS statusVector[] = { \
196 isc_arg_gds, isc_random, isc_arg_string, (ISC_STATUS) "Unrecognized C++ exception", \
197 isc_arg_end}; \
198 status->set(statusVector); \
199 }
200
201
202class StatusException
203{
204public:
205 StatusException(const ISC_STATUS* vector)
206 {
207 ISC_STATUS* p = statusVector;
208
209 while (*vector != isc_arg_end)
210 {
211 switch (*vector)
212 {
213 case isc_arg_warning:
214 case isc_arg_gds:
215 case isc_arg_number:
216 case isc_arg_interpreted:
217 case isc_arg_vms:
218 case isc_arg_unix:
219 case isc_arg_win32:
220 *p++ = *vector++;
221 *p++ = *vector++;
222 break;
223
224 case isc_arg_string:
225 *p++ = *vector++;
226 *p++ = *vector++;
227 break;
228
229 case isc_arg_cstring:
230 *p++ = *vector++;
231 *p++ = *vector++;
232 *p++ = *vector++;
233 break;
234
235 default:
236 return;
237 }
238 }
239
240 *p = isc_arg_end;
241 }
242
243public:
244 static void check(const ISC_STATUS* vector)
245 {
246 if (vector[1])
247 throw StatusException(vector);
248 }
249
250 static void checkStatus(ISC_STATUS status, const ISC_STATUS* vector)
251 {
252 if (status == 0)
253 return;
254
255 check(vector);
256 }
257
258 template <typename T>
259 static T check(IStatus* status, T value)
260 {
261 check(status->get());
262 return value;
263 }
264
265public:
266 const ISC_STATUS* getStatusVector() const
267 {
268 return statusVector;
269 }
270
271 void stuff(IStatus* status) const
272 {
273 status->set(statusVector);
274 }
275
276private:
277 ISC_STATUS_ARRAY statusVector;
278};
279
280class StatusImpl : public IStatus
281{
282public:
283 StatusImpl(IMaster* master)
284 : delegate(master->getStatus()),
285 success(true)
286 {
287 }
288
289 virtual int FB_CARG getVersion()
290 {
291 return FB_STATUS_VERSION;
292 }
293
294 virtual IPluginModule* FB_CARG getModule()
295 {
296 return NULL;
297 }
298
299 virtual void FB_CARG dispose()
300 {
301 delegate->dispose();
302 delete this;
303 }
304
305 virtual void FB_CARG set(unsigned int length, const ISC_STATUS* value)
306 {
307 delegate->set(length, value);
308 success = delegate->isSuccess();
309 }
310
311 virtual void FB_CARG set(const ISC_STATUS* value)
312 {
313 delegate->set(value);
314 success = delegate->isSuccess();
315 }
316
317 virtual void FB_CARG init()
318 {
319 delegate->init();
320 success = true;
321 }
322
323 virtual const ISC_STATUS* FB_CARG get() const
324 {
325 return delegate->get();
326 }
327
328 virtual int FB_CARG isSuccess() const
329 {
330 return success;
331 }
332
333public:
334 void check()
335 {
336 if (!success)
337 StatusException::check(delegate->get());
338 }
339
340private:
341 IStatus* delegate;
342 bool success;
343};
344
345
346template <typename T> class Procedure;
347
348
349class Helper
350{
351public:
352 static isc_db_handle getIscDbHandle(ExternalContext* context)
353 {
354 StatusImpl status(context->getMaster());
355
356 IAttachment* attachment = context->getAttachment(&status);
357 status.check();
358
359 ISC_STATUS_ARRAY statusVector = {0};
360 isc_db_handle handle = 0;
361
362 fb_get_database_handle(statusVector, &handle, attachment);
363 StatusException::check(statusVector);
364
365 return handle;
366 }
367
368 static isc_tr_handle getIscTrHandle(ExternalContext* context)
369 {
370 StatusImpl status(context->getMaster());
371
372 ITransaction* transaction = context->getTransaction(&status);
373 status.check();
374
375 ISC_STATUS_ARRAY statusVector = {0};
376 isc_tr_handle handle = 0;
377
378 fb_get_transaction_handle(statusVector, &handle, transaction);
379 StatusException::check(statusVector);
380
381 return handle;
382 }
383};
384
385
386template <typename This, typename Procedure, typename InMessage, typename OutMessage>
387class ResultSet : public ExternalResultSet, public Helper
388{
389public:
390 ResultSet(ExternalContext* aContext, Procedure* aProcedure,
391 typename InMessage::Type* aIn, typename OutMessage::Type* aOut)
392 : context(aContext),
393 procedure(aProcedure),
394 in(aIn),
395 out(aOut)
396 {
397 }
398
399public:
400 virtual int FB_CARG getVersion()
401 {
402 return FB_EXTERNAL_RESULT_SET_VERSION;
403 }
404
405 virtual IPluginModule* FB_CARG getModule()
406 {
407 return NULL;
408 }
409
410 virtual void FB_CARG dispose()
411 {
412 delete static_cast<This*>(this);
413 }
414
415protected:
416 ExternalContext* const context;
417 Procedure* const procedure;
418 typename InMessage::Type* const in;
419 typename OutMessage::Type* const out;
420};
421
422
423template <typename This>
424class Function : public ExternalFunction, public Helper
425{
426public:
427 FB__UDR_COMMON_TYPE(InMessage);
428 FB__UDR_COMMON_TYPE(OutMessage);
429
430 virtual int FB_CARG getVersion()
431 {
432 return FB_EXTERNAL_FUNCTION_VERSION;
433 }
434
435 virtual IPluginModule* FB_CARG getModule()
436 {
437 return NULL;
438 }
439
440 virtual void FB_CARG dispose()
441 {
442 delete static_cast<This*>(this);
443 }
444
445 virtual void FB_CARG getCharSet(IStatus* /*status*/, ExternalContext* /*context*/,
446 Utf8* /*name*/, uint /*nameSize*/)
447 {
448 }
449};
450
451
452template <typename This>
453class Procedure : public ExternalProcedure, public Helper
454{
455public:
456 FB__UDR_COMMON_TYPE(InMessage);
457 FB__UDR_COMMON_TYPE(OutMessage);
458
459 virtual int FB_CARG getVersion()
460 {
461 return FB_EXTERNAL_PROCEDURE_VERSION;
462 }
463
464 virtual IPluginModule* FB_CARG getModule()
465 {
466 return NULL;
467 }
468
469 virtual void FB_CARG dispose()
470 {
471 delete static_cast<This*>(this);
472 }
473
474 virtual void FB_CARG getCharSet(IStatus* /*status*/, ExternalContext* /*context*/,
475 Utf8* /*name*/, uint /*nameSize*/)
476 {
477 }
478};
479
480
481template <typename This>
482class Trigger : public ExternalTrigger, public Helper
483{
484public:
485 FB__UDR_COMMON_TYPE(FieldsMessage);
486
487 virtual int FB_CARG getVersion()
488 {
489 return FB_EXTERNAL_TRIGGER_VERSION;
490 }
491
492 virtual IPluginModule* FB_CARG getModule()
493 {
494 return NULL;
495 }
496
497 virtual void FB_CARG dispose()
498 {
499 delete static_cast<This*>(this);
500 }
501
502 virtual void FB_CARG getCharSet(IStatus* /*status*/, ExternalContext* /*context*/,
503 Utf8* /*name*/, uint /*nameSize*/)
504 {
505 }
506};
507
508
509template <typename T> class FunctionFactoryImpl : public FunctionFactory
510{
511public:
512 explicit FunctionFactoryImpl(const char* name)
513 {
514 fbUdrRegFunction(name, this);
515 }
516
517 virtual void FB_CARG setup(IStatus* status, ExternalContext* /*context*/,
518 const IRoutineMetadata* /*metadata*/, IMetadataBuilder* in, IMetadataBuilder* out)
519 {
520 T::InMessage::setup(status, in);
521 T::OutMessage::setup(status, out);
522 }
523
524 virtual ExternalFunction* FB_CARG newItem(IStatus* status, ExternalContext* context,
525 const IRoutineMetadata* metadata)
526 {
527 try
528 {
529 return new T(status, context, metadata);
530 }
531 FB__UDR_CATCH
532
533 return NULL;
534 }
535};
536
537
538template <typename T> class ProcedureFactoryImpl : public ProcedureFactory
539{
540public:
541 explicit ProcedureFactoryImpl(const char* name)
542 {
543 fbUdrRegProcedure(name, this);
544 }
545
546 virtual void FB_CARG setup(IStatus* status, ExternalContext* /*context*/,
547 const IRoutineMetadata* /*metadata*/, IMetadataBuilder* in, IMetadataBuilder* out)
548 {
549 T::InMessage::setup(status, in);
550 T::OutMessage::setup(status, out);
551 }
552
553 virtual ExternalProcedure* FB_CARG newItem(IStatus* status, ExternalContext* context,
554 const IRoutineMetadata* metadata)
555 {
556 try
557 {
558 return new T(status, context, metadata);
559 }
560 FB__UDR_CATCH
561
562 return NULL;
563 }
564};
565
566
567template <typename T> class TriggerFactoryImpl : public TriggerFactory
568{
569public:
570 explicit TriggerFactoryImpl(const char* name)
571 {
572 fbUdrRegTrigger(name, this);
573 }
574
575 virtual void FB_CARG setup(IStatus* status, ExternalContext* /*context*/,
576 const IRoutineMetadata* /*metadata*/, IMetadataBuilder* fields)
577 {
578 T::FieldsMessage::setup(status, fields);
579 }
580
581 virtual ExternalTrigger* FB_CARG newItem(IStatus* status, ExternalContext* context,
582 const IRoutineMetadata* metadata)
583 {
584 try
585 {
586 return new T(status, context, metadata);
587 }
588 FB__UDR_CATCH
589
590 return NULL;
591 }
592};
593
594
595//------------------------------------------------------------------------------
596 } // namespace Udr
597} // namespace Firebird
598
599#endif // FIREBIRD_UDR_CPP_ENGINE
600