globegit-postgresql-plruby 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/Changes +121 -0
  2. data/README.markdown +155 -0
  3. data/Rakefile +48 -0
  4. data/docs/plruby.rb +1931 -0
  5. data/ex_trans.sql +33 -0
  6. data/extconf.rb +267 -0
  7. data/plruby.html +1454 -0
  8. data/plruby.rd +1571 -0
  9. data/postgresql-plruby.gemspec +56 -0
  10. data/src/conversions.h +5 -0
  11. data/src/conversions/basic/conversions.h +25 -0
  12. data/src/conversions/basic/extconf.rb +8 -0
  13. data/src/conversions/basic/plruby_basic.c +357 -0
  14. data/src/conversions/bitstring/bitstring.sql +75 -0
  15. data/src/conversions/bitstring/conversions.h +15 -0
  16. data/src/conversions/bitstring/extconf.rb +8 -0
  17. data/src/conversions/bitstring/plruby_bitstring.c +579 -0
  18. data/src/conversions/convcommon.h +129 -0
  19. data/src/conversions/datetime/conversions.h +13 -0
  20. data/src/conversions/datetime/extconf.rb +8 -0
  21. data/src/conversions/datetime/plruby_datetime.c +269 -0
  22. data/src/conversions/geometry/conversions.h +37 -0
  23. data/src/conversions/geometry/extconf.rb +8 -0
  24. data/src/conversions/geometry/geometry.sql +196 -0
  25. data/src/conversions/geometry/plruby_geometry.c +2494 -0
  26. data/src/conversions/network/conversions.h +21 -0
  27. data/src/conversions/network/extconf.rb +8 -0
  28. data/src/conversions/network/network.sql +63 -0
  29. data/src/conversions/network/plruby_network.c +537 -0
  30. data/src/package.h +20 -0
  31. data/src/plpl.c +1708 -0
  32. data/src/plplan.c +893 -0
  33. data/src/plruby.c +1676 -0
  34. data/src/plruby.h +324 -0
  35. data/src/pltrans.c +388 -0
  36. data/test/conv_bitstring/b.rb +45 -0
  37. data/test/conv_bitstring/runtest +26 -0
  38. data/test/conv_bitstring/test.expected.73 +148 -0
  39. data/test/conv_bitstring/test.expected.74 +148 -0
  40. data/test/conv_bitstring/test.expected.80 +148 -0
  41. data/test/conv_bitstring/test.expected.81 +148 -0
  42. data/test/conv_bitstring/test.expected.82 +148 -0
  43. data/test/conv_bitstring/test.expected.83 +148 -0
  44. data/test/conv_bitstring/test.expected.84 +148 -0
  45. data/test/conv_bitstring/test.out +148 -0
  46. data/test/conv_bitstring/test_mklang.sql +8 -0
  47. data/test/conv_bitstring/test_queries.sql +63 -0
  48. data/test/conv_bitstring/test_queries.sql.in +63 -0
  49. data/test/conv_geometry/b.rb +45 -0
  50. data/test/conv_geometry/runtest +26 -0
  51. data/test/conv_geometry/test.expected.73 +265 -0
  52. data/test/conv_geometry/test.expected.74 +265 -0
  53. data/test/conv_geometry/test.expected.80 +265 -0
  54. data/test/conv_geometry/test.expected.81 +265 -0
  55. data/test/conv_geometry/test.expected.82 +265 -0
  56. data/test/conv_geometry/test.expected.83 +265 -0
  57. data/test/conv_geometry/test.expected.84 +265 -0
  58. data/test/conv_geometry/test.out +265 -0
  59. data/test/conv_geometry/test_mklang.sql +8 -0
  60. data/test/conv_geometry/test_queries.sql +194 -0
  61. data/test/conv_geometry/test_queries.sql.in +194 -0
  62. data/test/conv_network/b.rb +45 -0
  63. data/test/conv_network/runtest +26 -0
  64. data/test/conv_network/test.expected.73 +213 -0
  65. data/test/conv_network/test.expected.74 +237 -0
  66. data/test/conv_network/test.expected.80 +237 -0
  67. data/test/conv_network/test.expected.81 +237 -0
  68. data/test/conv_network/test.expected.82 +237 -0
  69. data/test/conv_network/test.expected.83 +237 -0
  70. data/test/conv_network/test.expected.84 +237 -0
  71. data/test/conv_network/test.out +237 -0
  72. data/test/conv_network/test_mklang.sql +8 -0
  73. data/test/conv_network/test_queries.sql +60 -0
  74. data/test/conv_network/test_queries.sql.in +60 -0
  75. data/test/plp/b.rb +34 -0
  76. data/test/plp/runtest +29 -0
  77. data/test/plp/test.expected.73 +472 -0
  78. data/test/plp/test.expected.74 +472 -0
  79. data/test/plp/test.expected.75 +472 -0
  80. data/test/plp/test.expected.80 +472 -0
  81. data/test/plp/test.expected.81 +472 -0
  82. data/test/plp/test.expected.82 +472 -0
  83. data/test/plp/test.expected.83 +472 -0
  84. data/test/plp/test.expected.84 +472 -0
  85. data/test/plp/test.out +472 -0
  86. data/test/plp/test_mklang.sql +8 -0
  87. data/test/plp/test_queries.sql +273 -0
  88. data/test/plp/test_setup.sql +931 -0
  89. data/test/plp/test_setup.sql.in +931 -0
  90. data/test/plt/b.rb +34 -0
  91. data/test/plt/runtest +29 -0
  92. data/test/plt/test.expected.73 +178 -0
  93. data/test/plt/test.expected.74 +178 -0
  94. data/test/plt/test.expected.75 +178 -0
  95. data/test/plt/test.expected.80 +178 -0
  96. data/test/plt/test.expected.81 +178 -0
  97. data/test/plt/test.expected.82 +178 -0
  98. data/test/plt/test.expected.83 +164 -0
  99. data/test/plt/test.expected.84 +168 -0
  100. data/test/plt/test.out +168 -0
  101. data/test/plt/test_mklang.sql +8 -0
  102. data/test/plt/test_queries.sql +72 -0
  103. data/test/plt/test_setup.sql +252 -0
  104. data/test/plt/test_setup.sql.in +252 -0
  105. data/test/range/b.rb +45 -0
  106. data/test/range/runtest +26 -0
  107. data/test/range/test.expected.73 +396 -0
  108. data/test/range/test.expected.73.in +396 -0
  109. data/test/range/test.expected.74 +396 -0
  110. data/test/range/test.expected.74.in +396 -0
  111. data/test/range/test.expected.75 +396 -0
  112. data/test/range/test.expected.75.in +396 -0
  113. data/test/range/test.expected.80 +396 -0
  114. data/test/range/test.expected.81 +397 -0
  115. data/test/range/test.expected.82 +397 -0
  116. data/test/range/test.expected.83 +397 -0
  117. data/test/range/test.expected.84 +399 -0
  118. data/test/range/test.out +399 -0
  119. data/test/range/test_mklang.sql +8 -0
  120. data/test/range/test_queries.sql +249 -0
  121. data/test/range/test_queries.sql.in +249 -0
  122. metadata +207 -0
@@ -0,0 +1,1676 @@
1
+ /*
2
+ * plruby.c - ruby as a procedural language for PostgreSQL
3
+ * copied from pltcl.c by Guy Decoux <ts@moulon.inra.fr>
4
+ *
5
+ * You can redistribute it and/or modify it under the same term as
6
+ * Ruby.
7
+ *
8
+ * Original copyright from pltcl.c
9
+ */
10
+ /**********************************************************************
11
+ * pltcl.c - PostgreSQL support for Tcl as
12
+ * procedural language (PL)
13
+ *
14
+ * IDENTIFICATION
15
+ * $Header: /usr/local/cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.12 1999/05/26 12:57:23 momjian Exp $
16
+ *
17
+ * This software is copyrighted by Jan Wieck - Hamburg.
18
+ *
19
+ * The author hereby grants permission to use, copy, modify,
20
+ * distribute, and license this software and its documentation
21
+ * for any purpose, provided that existing copyright notices are
22
+ * retained in all copies and that this notice is included
23
+ * verbatim in any distributions. No written agreement, license,
24
+ * or royalty fee is required for any of the authorized uses.
25
+ * Modifications to this software may be copyrighted by their
26
+ * author and need not follow the licensing terms described
27
+ * here, provided that the new terms are clearly indicated on
28
+ * the first page of each file where they apply.
29
+ *
30
+ * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
31
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
32
+ * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
33
+ * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
34
+ * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
35
+ * DAMAGE.
36
+ *
37
+ * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY
38
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
39
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
40
+ * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON
41
+ * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO
42
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
43
+ * ENHANCEMENTS, OR MODIFICATIONS.
44
+ *
45
+ **********************************************************************/
46
+
47
+ #include "plruby.h"
48
+
49
+ PG_FUNCTION_INFO_V1(PLRUBY_CALL_HANDLER);
50
+
51
+ static Datum pl_func_handler(struct pl_thread_st *);
52
+ static HeapTuple pl_trigger_handler(struct pl_thread_st *);
53
+
54
+ #if PG_PL_VERSION >= 81
55
+ static Datum pl_validator_handler(struct pl_thread_st *);
56
+ #endif
57
+
58
+ #if PG_PL_VERSION >= 82
59
+ PG_MODULE_MAGIC;
60
+ #endif
61
+
62
+ #ifdef PLRUBY_TIMEOUT
63
+ int plruby_in_progress = 0;
64
+ int plruby_interrupted = 0;
65
+ #endif
66
+
67
+ static ID id_to_s, id_raise, id_kill, id_alive, id_value, id_call, id_thr;
68
+
69
+ static int pl_firstcall = 1;
70
+ static int pl_call_level = 0;
71
+ static VALUE pl_ePLruby, pl_eCatch;
72
+ static VALUE pl_mPLtemp, pl_sPLtemp;
73
+ static VALUE PLruby_hash;
74
+
75
+ VALUE
76
+ plruby_s_new(int argc, VALUE *argv, VALUE obj)
77
+ {
78
+ VALUE res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
79
+ rb_obj_call_init(res, argc, argv);
80
+ return res;
81
+ }
82
+
83
+ static void
84
+ pl_proc_free(proc)
85
+ pl_proc_desc *proc;
86
+ {
87
+ if (proc->proname) {
88
+ free(proc->proname);
89
+ }
90
+ free(proc);
91
+ }
92
+
93
+ #define GetProcDesc(value_, procdesc_) do { \
94
+ if (TYPE(value_) != T_DATA || \
95
+ RDATA(value_)->dfree != (RUBY_DATA_FUNC)pl_proc_free) { \
96
+ rb_raise(pl_ePLruby, "expected a proc object"); \
97
+ } \
98
+ Data_Get_Struct(value_, pl_proc_desc, procdesc_); \
99
+ } while (0)
100
+
101
+ VALUE
102
+ plruby_to_s(VALUE obj)
103
+ {
104
+ if (TYPE(obj) != T_STRING) {
105
+ obj = rb_obj_as_string(obj);
106
+ }
107
+ if (TYPE(obj) != T_STRING || !RSTRING_PTR(obj)) {
108
+ rb_raise(pl_ePLruby, "Expected a String");
109
+ }
110
+ return obj;
111
+ }
112
+
113
+ static void
114
+ perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
115
+ {
116
+ fmgr_info_cxt(functionId, finfo, TopMemoryContext);
117
+ }
118
+
119
+ #define fmgr_info perm_fmgr_info
120
+
121
+ static int pl_fatal = 0;
122
+
123
+ #ifdef PLRUBY_ENABLE_CONVERSION
124
+
125
+ VALUE plruby_classes;
126
+ VALUE plruby_conversions;
127
+
128
+ static VALUE
129
+ protect_require(VALUE name)
130
+ {
131
+ return rb_require((char *)name);
132
+ }
133
+
134
+ static void
135
+ plruby_require(char *name)
136
+ {
137
+ int status;
138
+
139
+ rb_protect(protect_require, (VALUE)name, &status);
140
+ if (status) {
141
+ pl_fatal = 1;
142
+ elog(ERROR, "can't find %s : try first `make install'", name);
143
+ }
144
+ }
145
+
146
+ #ifndef HAVE_RB_INITIALIZE_COPY
147
+
148
+ VALUE
149
+ plruby_clone(VALUE obj)
150
+ {
151
+ VALUE res = rb_funcall2(rb_obj_class(obj), rb_intern("allocate"), 0, 0);
152
+ CLONESETUP(res, obj);
153
+ rb_funcall(res, rb_intern("initialize_copy"), 1, obj);
154
+ return res;
155
+ }
156
+
157
+ #endif
158
+
159
+ #if !defined(RUBY_CAN_USE_AUTOLOAD) || defined(PLRUBY_TIMEOUT)
160
+ static VALUE pl_require_thread = Qnil;
161
+ #endif
162
+
163
+ #ifndef RUBY_CAN_USE_AUTOLOAD
164
+
165
+ static VALUE file_to_load = Qnil;
166
+ static VALUE class_to_load = Qnil;
167
+ static VALUE exec_th = Qnil;
168
+
169
+ static VALUE
170
+ pl_require_th(VALUE th)
171
+ {
172
+ while (1) {
173
+ rb_thread_stop();
174
+ if (RTEST(exec_th)) {
175
+ if (TYPE(file_to_load) == T_STRING &&
176
+ RSTRING_PTR(file_to_load)) {
177
+ rb_undef_method(CLASS_OF(class_to_load), "method_missing");
178
+ rb_protect((VALUE(*)(VALUE))rb_require,
179
+ (VALUE)RSTRING_PTR(file_to_load), 0);
180
+ file_to_load = Qnil;
181
+ }
182
+ rb_thread_wakeup(exec_th);
183
+ }
184
+ }
185
+ return Qnil;
186
+ }
187
+
188
+ #ifndef HAVE_RB_BLOCK_CALL
189
+ static VALUE pl_each(VALUE *);
190
+ #endif
191
+
192
+ static VALUE
193
+ pl_conversions_missing(int argc, VALUE *argv, VALUE obj)
194
+ {
195
+ VALUE file;
196
+ ID id;
197
+
198
+ if (argc <= 0) {
199
+ rb_raise(rb_eArgError, "no id given");
200
+ }
201
+ id = SYM2ID(argv[0]);
202
+ file = rb_hash_aref(plruby_conversions, obj);
203
+ if (TYPE(file) != T_STRING || !RSTRING_PTR(file) ||
204
+ !RTEST(pl_require_thread)) {
205
+ rb_raise(pl_ePLruby, "undefined method %s", rb_id2name(id));
206
+ }
207
+ file_to_load = file;
208
+ class_to_load = obj;
209
+ exec_th = rb_thread_current();
210
+ PLRUBY_BEGIN(1);
211
+ rb_thread_wakeup(pl_require_thread);
212
+ rb_thread_stop();
213
+ PLRUBY_END;
214
+ exec_th = Qnil;
215
+ id = SYM2ID(argv[0]);
216
+ argc--; argv++;
217
+ if (rb_block_given_p()) {
218
+ #ifdef HAVE_RB_BLOCK_CALL
219
+ return rb_block_call(obj, id, argc, argv, rb_yield, 0);
220
+ #else
221
+ VALUE tmp[4];
222
+
223
+ tmp[0] = obj;
224
+ tmp[1] = (VALUE)id;
225
+ tmp[2] = (VALUE)argc;
226
+ tmp[3] = (VALUE)argv;
227
+ return rb_iterate((VALUE(*)(VALUE))pl_each, (VALUE)tmp, rb_yield, 0);
228
+ #endif
229
+ }
230
+ return rb_funcall2(obj, id, argc, argv);
231
+ }
232
+
233
+ VALUE
234
+ plruby_define_void_class(char *name, char *path)
235
+ {
236
+ VALUE klass;
237
+
238
+ klass = rb_define_class(name, rb_cObject);
239
+ #ifdef HAVE_RB_DEFINE_ALLOC_FUNC
240
+ rb_undef_alloc_func(klass);
241
+ #else
242
+ rb_undef_method(CLASS_OF(klass), "allocate");
243
+ #endif
244
+ rb_undef_method(CLASS_OF(klass), "new");
245
+ rb_undef_method(CLASS_OF(klass), "from_string");
246
+ rb_undef_method(CLASS_OF(klass), "from_datum");
247
+ rb_undef_method(CLASS_OF(klass), "_load");
248
+ rb_define_singleton_method(klass, "method_missing", pl_conversions_missing, -1);
249
+ rb_hash_aset(plruby_conversions, klass, rb_str_new2(path));
250
+ return klass;
251
+ }
252
+
253
+ #endif
254
+
255
+ #ifndef RUBY_CAN_USE_MARSHAL_LOAD
256
+
257
+ VALUE
258
+ plruby_s_load(VALUE obj, VALUE a)
259
+ {
260
+ VALUE res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
261
+ rb_funcall(res, rb_intern("marshal_load"), 1, a);
262
+ return res;
263
+ }
264
+
265
+ #endif
266
+
267
+ #endif
268
+
269
+ Datum
270
+ plruby_dfc0(PGFunction func)
271
+ {
272
+ FunctionCallInfoData fcinfo;
273
+ Datum result;
274
+
275
+ PLRUBY_BEGIN_PROTECT(1);
276
+ fcinfo.flinfo = NULL;
277
+ fcinfo.context = NULL;
278
+ fcinfo.resultinfo = NULL;
279
+ fcinfo.isnull = false;
280
+ fcinfo.nargs = 0;
281
+ result = (*func)(&fcinfo);
282
+ if (fcinfo.isnull)
283
+ result = 0;
284
+ PLRUBY_END_PROTECT;
285
+ return result;
286
+ }
287
+
288
+ Datum
289
+ plruby_dfc1(PGFunction func, Datum arg1)
290
+ {
291
+ Datum result;
292
+
293
+ PLRUBY_BEGIN_PROTECT(1);
294
+ result = DirectFunctionCall1(func, arg1);
295
+ PLRUBY_END_PROTECT;
296
+ return result;
297
+ }
298
+
299
+ Datum
300
+ plruby_dfc2(PGFunction func, Datum arg1, Datum arg2)
301
+ {
302
+ Datum result;
303
+
304
+ PLRUBY_BEGIN_PROTECT(1);
305
+ result = DirectFunctionCall2(func, arg1, arg2);
306
+ PLRUBY_END_PROTECT;
307
+ return result;
308
+ }
309
+
310
+ Datum
311
+ plruby_dfc3(PGFunction func, Datum arg1, Datum arg2, Datum arg3)
312
+ {
313
+ Datum result;
314
+
315
+ PLRUBY_BEGIN_PROTECT(1);
316
+ result = DirectFunctionCall3(func, arg1, arg2, arg3);
317
+ PLRUBY_END_PROTECT;
318
+ return result;
319
+ }
320
+
321
+ static void
322
+ pl_init_conversions()
323
+ {
324
+ #if PLRUBY_ENABLE_CONVERSION
325
+ #ifndef RUBY_CAN_USE_AUTOLOAD
326
+ pl_require_thread = rb_thread_create(pl_require_th, 0);
327
+ #endif
328
+ plruby_classes = rb_hash_new();
329
+ rb_global_variable(&plruby_classes);
330
+ plruby_conversions = rb_hash_new();
331
+ rb_global_variable(&plruby_conversions);
332
+ #include "conversions.h"
333
+ #endif
334
+ }
335
+
336
+ static void pl_result_mark(VALUE obj) {}
337
+
338
+ static VALUE
339
+ pl_protect(plth)
340
+ struct pl_thread_st *plth;
341
+ {
342
+ Datum retval;
343
+ VALUE result;
344
+
345
+ #ifdef PG_PL_TRYCATCH
346
+ PG_TRY();
347
+ #else
348
+ if (sigsetjmp(Warn_restart, 1) != 0) {
349
+ return pl_eCatch;
350
+ }
351
+ #endif
352
+ {
353
+ #if PG_PL_VERSION >= 81
354
+ if (plth->validator) {
355
+ retval = pl_validator_handler(plth);
356
+ }
357
+ else
358
+ #endif
359
+ {
360
+ if (CALLED_AS_TRIGGER(plth->fcinfo)) {
361
+ retval = PointerGD(pl_trigger_handler(plth));
362
+ }
363
+ else {
364
+ retval = pl_func_handler(plth);
365
+ }
366
+ }
367
+ }
368
+ #ifdef PG_PL_TRYCATCH
369
+ PG_CATCH();
370
+ {
371
+ return pl_eCatch;
372
+ }
373
+ PG_END_TRY();
374
+ #endif
375
+ result = Data_Wrap_Struct(rb_cObject, pl_result_mark, 0, (void *)retval);
376
+ return result;
377
+ }
378
+
379
+ #ifdef PLRUBY_TIMEOUT
380
+
381
+ static VALUE
382
+ pl_thread_raise(VALUE th)
383
+ {
384
+ VALUE exc = rb_exc_new2(pl_ePLruby, "timeout");
385
+ return rb_funcall(th, id_raise, 1, exc);
386
+ }
387
+
388
+ static VALUE
389
+ pl_thread_kill(VALUE th)
390
+ {
391
+ return rb_funcall2(th, id_kill, 0, 0);
392
+ }
393
+
394
+ static VALUE
395
+ pl_timer(VALUE th)
396
+ {
397
+ struct timeval time;
398
+
399
+ rb_thread_sleep(PLRUBY_TIMEOUT);
400
+ plruby_interrupted = 1;
401
+ time.tv_sec = 0;
402
+ time.tv_usec = 50000;
403
+ while (1) {
404
+ if (!RTEST(rb_funcall2(th, id_alive, 0, 0))) {
405
+ return Qnil;
406
+ }
407
+ if (!plruby_in_progress) {
408
+ rb_protect(pl_thread_raise, th, 0);
409
+ }
410
+ rb_thread_wait_for(time);
411
+ }
412
+ return Qnil;
413
+ }
414
+
415
+ static VALUE
416
+ pl_thread_value(VALUE th)
417
+ {
418
+ return rb_funcall2(th, id_value, 0, 0);
419
+ }
420
+
421
+ #endif
422
+
423
+ static VALUE
424
+ pl_error(VALUE v)
425
+ {
426
+ VALUE result;
427
+
428
+ result = rb_gv_get("$!");
429
+ if (rb_obj_is_kind_of(result, pl_eCatch)) {
430
+ result = pl_eCatch;
431
+ }
432
+ else if (rb_obj_is_kind_of(result, rb_eException)) {
433
+ result = plruby_to_s(result);
434
+ }
435
+ return result;
436
+ }
437
+
438
+ #if defined(PLRUBY_TIMEOUT)
439
+ struct extra_args {
440
+ VALUE result;
441
+ struct Node *context;
442
+ SetFunctionReturnMode returnMode;
443
+ Tuplestorestate *setResult;
444
+ ExprDoneCond isDone;
445
+ };
446
+
447
+ static void
448
+ extra_args_mark(struct extra_args *exa)
449
+ {
450
+ rb_gc_mark(exa->result);
451
+ }
452
+ #endif
453
+
454
+ static VALUE
455
+ pl_real_handler(struct pl_thread_st *plth)
456
+ {
457
+ VALUE result = Qnil;
458
+ int state;
459
+
460
+ #ifdef PLRUBY_TIMEOUT
461
+ if (plth->timeout) {
462
+ VALUE curr = rb_thread_current();
463
+ rb_thread_create(pl_timer, (void *)curr);
464
+ rb_funcall(curr, rb_intern("priority="), 1, INT2NUM(0));
465
+ rb_set_safe_level(SAFE_LEVEL);
466
+ }
467
+ #endif
468
+
469
+ state = 0;
470
+ pl_call_level++;
471
+ #ifdef PG_PL_TRYCATCH
472
+ PG_TRY();
473
+ #endif
474
+ {
475
+ result = rb_protect(pl_protect, (VALUE)plth, &state);
476
+ }
477
+ #ifdef PG_PL_TRYCATCH
478
+ PG_END_TRY();
479
+ #endif
480
+ pl_call_level--;
481
+ if (state) {
482
+ state = 0;
483
+ result = rb_protect(pl_error, 0, &state);
484
+ if (state || (result != pl_eCatch && TYPE(result) != T_STRING)) {
485
+ result = rb_str_new2("Unknown Error");
486
+ }
487
+ }
488
+ #if defined(PLRUBY_TIMEOUT)
489
+ if (!plth->validator) {
490
+ VALUE res;
491
+ struct extra_args *exa;
492
+ ReturnSetInfo *rsi;
493
+
494
+ res = Data_Make_Struct(rb_cData, struct extra_args, extra_args_mark, free, exa);
495
+ exa->context = plth->fcinfo->context;
496
+ rsi = (ReturnSetInfo *)plth->fcinfo->resultinfo;
497
+ if (rsi) {
498
+ exa->setResult = rsi->setResult;
499
+ exa->returnMode = rsi->returnMode;
500
+ exa->isDone = rsi->isDone;
501
+ }
502
+ exa->result = result;
503
+ return res;
504
+ }
505
+ #endif
506
+ return result;
507
+ }
508
+
509
+ static void pl_init_all _(());
510
+
511
+ MemoryContext plruby_spi_context;
512
+
513
+
514
+ Datum
515
+ pl_internal_call_handler(struct pl_thread_st *plth)
516
+ {
517
+ VALUE result;
518
+ #ifndef PG_PL_TRYCATCH
519
+ sigjmp_buf save_restart;
520
+ #endif
521
+ volatile VALUE *tmp;
522
+ MemoryContext orig_context;
523
+ volatile VALUE orig_id;
524
+
525
+ if (pl_firstcall) {
526
+ pl_init_all();
527
+ }
528
+ if (!pl_call_level) {
529
+ extern void Init_stack();
530
+ Init_stack((VALUE *)&tmp);
531
+ }
532
+
533
+ orig_context = CurrentMemoryContext;
534
+ orig_id = rb_thread_local_aref(rb_thread_current(), id_thr);
535
+ rb_thread_local_aset(rb_thread_current(), id_thr, Qnil);
536
+ if (SPI_connect() != SPI_OK_CONNECT) {
537
+ if (pl_call_level) {
538
+ rb_raise(pl_ePLruby, "cannot connect to SPI manager");
539
+ }
540
+ else {
541
+ elog(ERROR, "cannot connect to SPI manager");
542
+ }
543
+ }
544
+ plruby_spi_context = MemoryContextSwitchTo(orig_context);
545
+
546
+ #ifndef PG_PL_TRYCATCH
547
+ memcpy(&save_restart, &Warn_restart, sizeof(save_restart));
548
+ #endif
549
+ #ifdef PLRUBY_TIMEOUT
550
+ if (!pl_call_level) {
551
+ VALUE th;
552
+ int state;
553
+
554
+ plruby_interrupted = plruby_in_progress = 0;
555
+ plth->timeout = 1;
556
+ th = rb_thread_create(pl_real_handler, (void *)plth);
557
+ result = rb_protect(pl_thread_value, th, &state);
558
+ plruby_interrupted = plruby_in_progress = pl_call_level = 0;
559
+ if (state) {
560
+ result = rb_str_new2("Unknown error");
561
+ }
562
+ }
563
+ else
564
+ #endif
565
+ {
566
+ PLRUBY_BEGIN(0);
567
+ result = pl_real_handler(plth);
568
+ PLRUBY_END;
569
+ }
570
+ #if defined(PLRUBY_TIMEOUT)
571
+ if (TYPE(result) == T_DATA &&
572
+ RDATA(result)->dmark == (RUBY_DATA_FUNC)extra_args_mark) {
573
+ ReturnSetInfo *rsi;
574
+ struct extra_args *exa;
575
+
576
+ Data_Get_Struct(result, struct extra_args, exa);
577
+ fcinfo->context = exa->context;
578
+ rsi = (ReturnSetInfo *)fcinfo->resultinfo;
579
+ if (rsi) {
580
+ rsi->setResult = exa->setResult;
581
+ rsi->returnMode = exa->returnMode;
582
+ rsi->isDone = exa->isDone;
583
+ }
584
+ result = exa->result;
585
+ }
586
+ #endif
587
+ #ifndef PG_PL_TRYCATCH
588
+ memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));
589
+ #endif
590
+
591
+ #ifdef PLRUBY_TIMEOUT
592
+ if (!pl_call_level) {
593
+ int i, in_progress;
594
+ VALUE thread, threads;
595
+ int ntpth;
596
+ VALUE main_th = rb_thread_main();
597
+
598
+ if (RTEST(pl_require_thread)) ntpth = 2;
599
+ else ntpth = 1;
600
+ in_progress = plruby_in_progress;
601
+ plruby_in_progress = 1;
602
+ while (1) {
603
+ threads = rb_thread_list();
604
+ if (RARRAY_LEN(threads) <= ntpth) break;
605
+ for (i = 0; i < RARRAY_LEN(threads); i++) {
606
+ thread = RARRAY_PTR(threads)[i];
607
+ if (thread != main_th && thread != pl_require_thread) {
608
+ rb_protect(pl_thread_kill, thread, 0);
609
+ }
610
+ }
611
+ }
612
+ pl_call_level = 0;
613
+ plruby_in_progress = in_progress;
614
+ }
615
+ #endif
616
+
617
+ rb_thread_local_aset(rb_thread_current(), id_thr, orig_id);
618
+
619
+ if (result == pl_eCatch) {
620
+ if (pl_call_level) {
621
+ rb_raise(pl_eCatch, "SPI ERROR");
622
+ }
623
+ else {
624
+ #ifdef PG_PL_TRYCATCH
625
+ PG_RE_THROW();
626
+ #else
627
+ siglongjmp(Warn_restart, 1);
628
+ #endif
629
+ }
630
+ }
631
+ if (TYPE(result) == T_STRING && RSTRING_PTR(result)) {
632
+ if (pl_call_level) {
633
+ rb_raise(pl_ePLruby, "%.*s",
634
+ (int)RSTRING_LEN(result), RSTRING_PTR(result));
635
+ }
636
+ else {
637
+ elog(ERROR, "%.*s",
638
+ (int)RSTRING_LEN(result), RSTRING_PTR(result));
639
+ }
640
+ }
641
+ if (TYPE(result) == T_DATA &&
642
+ RDATA(result)->dmark == (RUBY_DATA_FUNC)pl_result_mark) {
643
+ return ((Datum)DATA_PTR(result));
644
+ }
645
+ if (pl_call_level) {
646
+ rb_raise(pl_ePLruby, "Invalid return value %d", TYPE(result));
647
+ }
648
+ else {
649
+ elog(ERROR, "Invalid return value %d", TYPE(result));
650
+ }
651
+ return ((Datum)0);
652
+ }
653
+
654
+ #if PG_PL_VERSION >= 81
655
+
656
+ PG_FUNCTION_INFO_V1(PLRUBY_VALIDATOR);
657
+
658
+ Datum
659
+ PLRUBY_VALIDATOR(PG_FUNCTION_ARGS)
660
+ {
661
+ struct pl_thread_st plth;
662
+
663
+ plth.fcinfo = fcinfo;
664
+ plth.timeout = 0;
665
+ plth.validator = PG_GETARG_OID(0);
666
+ pl_internal_call_handler(&plth);
667
+ PG_RETURN_VOID();
668
+ }
669
+
670
+ static VALUE pl_compile(struct pl_thread_st *plth, int istrigger);
671
+ extern bool check_function_bodies;
672
+
673
+ static Datum
674
+ pl_validator_handler(struct pl_thread_st *plth)
675
+ {
676
+ Oid funcoid;
677
+ HeapTuple tuple;
678
+ Form_pg_proc proc;
679
+ char functyptype;
680
+ bool istrigger = false;
681
+
682
+ funcoid = plth->validator;
683
+ tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcoid), 0, 0, 0);
684
+ if (!HeapTupleIsValid(tuple)) {
685
+ rb_raise(pl_ePLruby, "cache lookup failed for function %u", funcoid);
686
+ }
687
+ proc = (Form_pg_proc) GETSTRUCT(tuple);
688
+ functyptype = get_typtype(proc->prorettype);
689
+ if (functyptype == 'p' &&
690
+ (proc->prorettype == TRIGGEROID ||
691
+ (proc->prorettype == OPAQUEOID && proc->pronargs == 0))) {
692
+ istrigger = true;
693
+ }
694
+ ReleaseSysCache(tuple);
695
+ if (check_function_bodies) {
696
+ pl_compile(plth, istrigger);
697
+ }
698
+ PG_RETURN_VOID();
699
+ }
700
+
701
+ #endif
702
+
703
+ Datum
704
+ PLRUBY_CALL_HANDLER(PG_FUNCTION_ARGS)
705
+ {
706
+ struct pl_thread_st plth;
707
+
708
+ plth.fcinfo = fcinfo;
709
+ plth.timeout = 0;
710
+ plth.validator = 0;
711
+ return pl_internal_call_handler(&plth);
712
+ }
713
+
714
+ static char *definition = "def PLtemp.%s(%s)\n%s\nend";
715
+
716
+ #if PG_PL_VERSION >= 82
717
+
718
+ static VALUE
719
+ pl_arg_names(HeapTuple procTup, pl_proc_desc *prodesc)
720
+ {
721
+ Oid *argtypes;
722
+ char **argnames;
723
+ char *argmodes;
724
+ int nargs, i;
725
+ VALUE result;
726
+
727
+ PLRUBY_BEGIN_PROTECT(1);
728
+ nargs = get_func_arg_info(procTup, &argtypes, &argnames, &argmodes);
729
+ PLRUBY_END_PROTECT;
730
+ if (argnames == NULL) {
731
+ return rb_str_new2("args");
732
+ }
733
+ prodesc->named_args = 1;
734
+ result = rb_str_new2("");
735
+ if (argmodes != NULL) {
736
+ int begin = 1;
737
+ for (i = 0; i < nargs; i++) {
738
+ if (argmodes[i] != PROARGMODE_OUT) {
739
+ if (!begin) {
740
+ rb_str_cat2(result, ",");
741
+ }
742
+ rb_str_cat2(result, argnames[i]);
743
+ begin = 0;
744
+ }
745
+ }
746
+ }
747
+ else {
748
+ for (i = 0; i < nargs; i++) {
749
+ rb_str_cat2(result, argnames[i]);
750
+ if (i != (nargs - 1)) {
751
+ rb_str_cat2(result, ",");
752
+ }
753
+ }
754
+ }
755
+ return result;
756
+ }
757
+
758
+ #else
759
+
760
+ static VALUE
761
+ pl_arg_names(HeapTuple procTup, pl_proc_desc *prodesc)
762
+ {
763
+ #if PG_PL_VERSION < 75
764
+ return rb_str_new2("args");
765
+ #else
766
+ Datum argnamesDatum;
767
+ char *name;
768
+ bool isNull;
769
+ Datum *elems;
770
+ int nelems;
771
+ VALUE result;
772
+ int i;
773
+ int nargs = prodesc->nargs;
774
+
775
+ prodesc->named_args = 0;
776
+ if (nargs == 0) {
777
+ return rb_str_new2("args");
778
+ }
779
+ argnamesDatum = SysCacheGetAttr(PROCOID, procTup,
780
+ Anum_pg_proc_proargnames, &isNull);
781
+ if (isNull) {
782
+ return rb_str_new2("args");
783
+ }
784
+ PLRUBY_BEGIN_PROTECT(1);
785
+ deconstruct_array(DatumGetArrayTypeP(argnamesDatum), TEXTOID, -1, false,
786
+ 'i', &elems, &nelems);
787
+ if (nelems != nargs) {
788
+ result = Qnil;
789
+ }
790
+ else {
791
+ prodesc->named_args = 1;
792
+ result = rb_str_new2("");
793
+ for (i = 0; i < nargs; i++) {
794
+ name = DatumGetCString(DFC1(textout, elems[i]));
795
+ rb_str_cat2(result, name);
796
+ pfree(name);
797
+ if (i != nargs - 1) {
798
+ rb_str_cat2(result, ",");
799
+ }
800
+ }
801
+ }
802
+ PLRUBY_END_PROTECT;
803
+ if (NIL_P(result)) {
804
+ rb_raise(pl_ePLruby, "invalid number of arguments for proargnames");
805
+ }
806
+ return result;
807
+ #endif
808
+ }
809
+
810
+ #endif
811
+
812
+ static VALUE
813
+ pl_compile(struct pl_thread_st *plth, int istrigger)
814
+ {
815
+ int i;
816
+ char internal_proname[512];
817
+ int proname_len;
818
+ HeapTuple procTup;
819
+ Form_pg_proc procStruct;
820
+ pl_proc_desc *prodesc;
821
+ VALUE value_proc_desc;
822
+ VALUE value_proname;
823
+ Oid result_oid, arg_type[FUNC_MAX_ARGS];
824
+ int nargs = 0;
825
+ static char *argt = "new, old, args, tg";
826
+ PG_FUNCTION_ARGS;
827
+
828
+ fcinfo = plth->fcinfo;
829
+ if (istrigger) {
830
+ sprintf(internal_proname, "proc_%u_trigger", fcinfo->flinfo->fn_oid);
831
+ }
832
+ else {
833
+ sprintf(internal_proname, "proc_%u", fcinfo->flinfo->fn_oid);
834
+ }
835
+ proname_len = strlen(internal_proname);
836
+ value_proname = rb_tainted_str_new(internal_proname, proname_len);
837
+ value_proc_desc = rb_hash_aref(PLruby_hash, value_proname);
838
+
839
+ PLRUBY_BEGIN(1);
840
+ procTup = SearchSysCache(PROCOID, OidGD(fcinfo->flinfo->fn_oid), 0, 0, 0);
841
+ PLRUBY_END;
842
+ if (!HeapTupleIsValid(procTup)) {
843
+ rb_raise(pl_ePLruby, "cache lookup from pg_proc failed");
844
+ }
845
+ procStruct = (Form_pg_proc) GETSTRUCT(procTup);
846
+
847
+ if (!istrigger) {
848
+ #if PG_PL_VERSION >= 74
849
+ if (procStruct->prorettype == ANYARRAYOID ||
850
+ procStruct->prorettype == ANYELEMENTOID) {
851
+ result_oid = get_fn_expr_rettype(fcinfo->flinfo);
852
+ if (result_oid == InvalidOid) {
853
+ result_oid = procStruct->prorettype;
854
+ }
855
+ }
856
+ else
857
+ #endif
858
+ {
859
+ result_oid = procStruct->prorettype;
860
+ }
861
+
862
+ nargs = procStruct->pronargs;
863
+ for (i = 0; i < nargs; ++i) {
864
+ #if PG_PL_VERSION >= 74
865
+ #if PG_PL_VERSION >= 81
866
+ if (procStruct->proargtypes.values[i] == ANYARRAYOID ||
867
+ procStruct->proargtypes.values[i] == ANYELEMENTOID) {
868
+ arg_type[i] = get_fn_expr_argtype(fcinfo->flinfo, i);
869
+ if (arg_type[i] == InvalidOid) {
870
+ arg_type[i] = procStruct->proargtypes.values[i];
871
+ }
872
+ }
873
+ #else
874
+ if (procStruct->proargtypes[i] == ANYARRAYOID ||
875
+ procStruct->proargtypes[i] == ANYELEMENTOID) {
876
+ arg_type[i] = get_fn_expr_argtype(fcinfo->flinfo, i);
877
+ if (arg_type[i] == InvalidOid) {
878
+ arg_type[i] = procStruct->proargtypes[i];
879
+ }
880
+ }
881
+ #endif
882
+ else
883
+ #endif
884
+ {
885
+ #if PG_PL_VERSION >= 81
886
+ arg_type[i] = procStruct->proargtypes.values[i];
887
+ #else
888
+ arg_type[i] = procStruct->proargtypes[i];
889
+ #endif
890
+ }
891
+ }
892
+ }
893
+
894
+ if (!NIL_P(value_proc_desc)) {
895
+ int uptodate;
896
+
897
+ GetProcDesc(value_proc_desc, prodesc);
898
+ uptodate =
899
+ (prodesc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data)) &&
900
+ (prodesc->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data));
901
+ #if PG_PL_VERSION >= 74
902
+ if (!istrigger) {
903
+ if (uptodate) {
904
+ uptodate = result_oid == prodesc->result_oid;
905
+ }
906
+ if (uptodate) {
907
+ int i;
908
+
909
+ for (i = 0; i < nargs; ++i) {
910
+ if (arg_type[i] != prodesc->arg_type[i]) {
911
+ uptodate = 0;
912
+ break;
913
+ }
914
+ }
915
+ }
916
+ }
917
+ #endif
918
+ if (!uptodate) {
919
+ rb_remove_method(pl_sPLtemp, internal_proname);
920
+ value_proc_desc = Qnil;
921
+ }
922
+ }
923
+
924
+ if (NIL_P(value_proc_desc)) {
925
+ HeapTuple typeTup;
926
+ Form_pg_type typeStruct;
927
+ char *proc_source, *proc_internal_def;
928
+ int status;
929
+ MemoryContext oldcontext;
930
+
931
+ value_proc_desc = Data_Make_Struct(rb_cObject, pl_proc_desc, 0, pl_proc_free, prodesc);
932
+ if (!istrigger) {
933
+ prodesc->result_oid = result_oid;
934
+ }
935
+ PLRUBY_BEGIN(1);
936
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
937
+ prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
938
+ prodesc->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);
939
+ if (!istrigger) {
940
+ typeTup = SearchSysCache(TYPEOID, OidGD(result_oid), 0, 0, 0);
941
+ }
942
+ PLRUBY_END;
943
+ if (!istrigger) {
944
+ if (!HeapTupleIsValid(typeTup)) {
945
+ rb_raise(pl_ePLruby, "cache lookup for return type failed");
946
+ }
947
+ typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
948
+
949
+ if (typeStruct->typtype == 'p') {
950
+ switch (result_oid) {
951
+ case RECORDOID:
952
+ case VOIDOID:
953
+ break;
954
+ default:
955
+ rb_raise(pl_ePLruby, "functions cannot return type %s",
956
+ format_type_be(result_oid));
957
+ break;
958
+ }
959
+ }
960
+
961
+ prodesc->result_is_setof = procStruct->proretset;
962
+ if (procStruct->proretset) {
963
+ Oid funcid, functypeid;
964
+ char functyptype;
965
+
966
+ funcid = fcinfo->flinfo->fn_oid;
967
+ PLRUBY_BEGIN(1);
968
+ functypeid = get_func_rettype(funcid);
969
+ functyptype = get_typtype(functypeid);
970
+ PLRUBY_END;
971
+ if (functyptype == 'c' || functyptype == 'b' ||
972
+ (functyptype == 'p' && functypeid == RECORDOID)) {
973
+ prodesc->result_type = functyptype;
974
+ }
975
+ else {
976
+ rb_raise(pl_ePLruby, "Invalid kind of return type");
977
+ }
978
+ }
979
+ else {
980
+ if (result_oid == REFCURSOROID) {
981
+ prodesc->result_type = 'x';
982
+ }
983
+ else {
984
+ Oid funcid, functypeid;
985
+ char functyptype;
986
+
987
+ funcid = fcinfo->flinfo->fn_oid;
988
+ PLRUBY_BEGIN(1);
989
+ functypeid = get_func_rettype(funcid);
990
+ functyptype = get_typtype(functypeid);
991
+ PLRUBY_END;
992
+ if (functyptype == 'c' ||
993
+ (functyptype == 'p' && functypeid == RECORDOID)) {
994
+ prodesc->result_type = 'y';
995
+ }
996
+ }
997
+ }
998
+
999
+ prodesc->result_elem = (Oid)typeStruct->typelem;
1000
+ prodesc->result_is_array = 0;
1001
+ PLRUBY_BEGIN(1);
1002
+ if (NameStr(typeStruct->typname)[0] == '_') {
1003
+ FmgrInfo inputproc;
1004
+ HeapTuple typeTuple;
1005
+ Form_pg_type typeStruct;
1006
+
1007
+ typeTuple = SearchSysCache(TYPEOID, OidGD(prodesc->result_elem),
1008
+ 0, 0, 0);
1009
+ if (!HeapTupleIsValid(typeTuple)) {
1010
+ rb_raise(pl_ePLruby, "cache lookup failed for type %u",
1011
+ prodesc->result_elem);
1012
+ }
1013
+ typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1014
+ fmgr_info(typeStruct->typinput, &inputproc);
1015
+ prodesc->result_is_array = 1;
1016
+ prodesc->result_func = inputproc;
1017
+ prodesc->result_val = typeStruct->typbyval;
1018
+ prodesc->result_len = typeStruct->typlen;
1019
+ prodesc->result_align = typeStruct->typalign;
1020
+ ReleaseSysCache(typeTuple);
1021
+ }
1022
+ else {
1023
+ fmgr_info(typeStruct->typinput, &(prodesc->result_func));
1024
+ prodesc->result_len = typeStruct->typlen;
1025
+ }
1026
+ PLRUBY_END;
1027
+ ReleaseSysCache(typeTup);
1028
+
1029
+ prodesc->nargs = nargs;
1030
+ for (i = 0; i < prodesc->nargs; i++) {
1031
+
1032
+ PLRUBY_BEGIN(1);
1033
+ typeTup = SearchSysCache(TYPEOID, OidGD(arg_type[i]), 0, 0, 0);
1034
+ PLRUBY_END;
1035
+
1036
+ if (!HeapTupleIsValid(typeTup)) {
1037
+ rb_raise(pl_ePLruby, "cache lookup for argument type failed");
1038
+ }
1039
+ typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
1040
+ prodesc->arg_type[i] = arg_type[i];
1041
+
1042
+ if (typeStruct->typtype == 'p') {
1043
+ rb_raise(pl_ePLruby, "argument can't have the type %s",
1044
+ format_type_be(arg_type[i]));
1045
+ }
1046
+ prodesc->arg_elem[i] = (Oid) (typeStruct->typelem);
1047
+ prodesc->arg_is_rel[i] = (typeStruct->typrelid != InvalidOid);
1048
+
1049
+ PLRUBY_BEGIN(1);
1050
+ prodesc->arg_is_array[i] = 0;
1051
+ if (NameStr(typeStruct->typname)[0] == '_') {
1052
+ FmgrInfo outputproc;
1053
+ HeapTuple typeTuple;
1054
+ Form_pg_type typeStruct;
1055
+
1056
+ typeTuple = SearchSysCache(TYPEOID,
1057
+ OidGD(prodesc->arg_elem[i]),
1058
+ 0, 0, 0);
1059
+ if (!HeapTupleIsValid(typeTuple)) {
1060
+ rb_raise(pl_ePLruby, "cache lookup failed for type %u",
1061
+ prodesc->arg_elem[i]);
1062
+ }
1063
+ typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1064
+ fmgr_info(typeStruct->typoutput, &outputproc);
1065
+ prodesc->arg_is_array[i] = 1;
1066
+ prodesc->arg_func[i] = outputproc;
1067
+ prodesc->arg_val[i] = typeStruct->typbyval;
1068
+ prodesc->arg_len[i] = typeStruct->typlen;
1069
+ prodesc->arg_align[i] = typeStruct->typalign;
1070
+ ReleaseSysCache(typeTuple);
1071
+ }
1072
+ else {
1073
+ fmgr_info(typeStruct->typoutput, &(prodesc->arg_func[i]));
1074
+ prodesc->arg_len[i] = typeStruct->typlen;
1075
+ }
1076
+ ReleaseSysCache(typeTup);
1077
+ PLRUBY_END;
1078
+ }
1079
+ }
1080
+
1081
+ {
1082
+ Datum prosrc;
1083
+ VALUE argname = Qnil;
1084
+ #if PG_PL_VERSION >= 75
1085
+ bool isnull;
1086
+
1087
+ PLRUBY_BEGIN_PROTECT(1);
1088
+ prosrc = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_prosrc, &isnull);
1089
+ PLRUBY_END_PROTECT;
1090
+ if (isnull) {
1091
+ rb_raise(pl_ePLruby, "null source");
1092
+ }
1093
+ #else
1094
+ prosrc = PointerGD(&procStruct->prosrc);
1095
+ #endif
1096
+ if (!istrigger) {
1097
+ argname = plruby_to_s(pl_arg_names(procTup, prodesc));
1098
+ }
1099
+ PLRUBY_BEGIN_PROTECT(1);
1100
+ proc_source = DatumGetCString(DFC1(textout, prosrc));
1101
+ if (istrigger) {
1102
+ proc_internal_def = ALLOCA_N(char, strlen(definition) + proname_len +
1103
+ strlen(argt) + strlen(proc_source) + 1);
1104
+ sprintf(proc_internal_def, definition, internal_proname,
1105
+ argt, proc_source);
1106
+ }
1107
+ else {
1108
+ proc_internal_def = ALLOCA_N(char, strlen(definition) +
1109
+ proname_len + RSTRING_LEN(argname) +
1110
+ strlen(proc_source) + 1);
1111
+ sprintf(proc_internal_def, definition, internal_proname,
1112
+ RSTRING_PTR(argname), proc_source);
1113
+ }
1114
+ pfree(proc_source);
1115
+ PLRUBY_END_PROTECT;
1116
+ }
1117
+
1118
+ rb_eval_string_protect(proc_internal_def, &status);
1119
+ if (status) {
1120
+ VALUE s = plruby_to_s(rb_gv_get("$!"));
1121
+ rb_hash_delete(PLruby_hash, value_proname);
1122
+ rb_raise(pl_ePLruby, "cannot create internal procedure\n%s\n<<===%s\n===>>",
1123
+ RSTRING_PTR(s), proc_internal_def);
1124
+ }
1125
+ prodesc->proname = ALLOC_N(char, strlen(internal_proname) + 1);
1126
+ strcpy(prodesc->proname, internal_proname);
1127
+ rb_hash_aset(PLruby_hash, value_proname, value_proc_desc);
1128
+ PLRUBY_BEGIN(1);
1129
+ MemoryContextSwitchTo(oldcontext);
1130
+ PLRUBY_END;
1131
+ }
1132
+ ReleaseSysCache(procTup);
1133
+ return value_proname;
1134
+ }
1135
+
1136
+ static Datum
1137
+ pl_func_handler(struct pl_thread_st *plth)
1138
+ {
1139
+ VALUE value_proc_desc, ary;
1140
+ VALUE value_proname;
1141
+ pl_proc_desc *prodesc;
1142
+
1143
+ value_proname = pl_compile(plth, 0);
1144
+ value_proc_desc = rb_hash_aref(PLruby_hash, value_proname);
1145
+ if (NIL_P(value_proc_desc)) {
1146
+ rb_raise(pl_ePLruby, "cannot create internal procedure");
1147
+ }
1148
+ GetProcDesc(value_proc_desc, prodesc);
1149
+ ary = plruby_create_args(plth, prodesc);
1150
+ return plruby_return_value(plth, prodesc, value_proname, ary);
1151
+ }
1152
+
1153
+ struct foreach_fmgr {
1154
+ TupleDesc tupdesc;
1155
+ int *modattrs;
1156
+ Datum *modvalues;
1157
+ char *modnulls;
1158
+ };
1159
+
1160
+ #ifndef VARLENA_FIXED_SIZE
1161
+
1162
+ #define VARLENA_FIXED_SIZE(a) (1)
1163
+
1164
+ #endif
1165
+
1166
+ static VALUE
1167
+ for_numvals(obj, argobj)
1168
+ VALUE obj, argobj;
1169
+ {
1170
+ int attnum;
1171
+ HeapTuple typeTup;
1172
+ FmgrInfo finfo;
1173
+ Form_pg_type fpg;
1174
+ VALUE key, value;
1175
+ struct foreach_fmgr *arg;
1176
+
1177
+ Data_Get_Struct(argobj, struct foreach_fmgr, arg);
1178
+ key = plruby_to_s(rb_ary_entry(obj, 0));
1179
+ value = rb_ary_entry(obj, 1);
1180
+ if (RSTRING_PTR(key)[0] == '.' || NIL_P(value)) {
1181
+ return Qnil;
1182
+ }
1183
+ attnum = SPI_fnumber(arg->tupdesc, RSTRING_PTR(key));
1184
+ if (attnum == SPI_ERROR_NOATTRIBUTE) {
1185
+ rb_raise(pl_ePLruby, "invalid attribute '%s'", RSTRING_PTR(key));
1186
+ }
1187
+ attnum -= 1;
1188
+ if (arg->tupdesc->attrs[attnum]->attisdropped) {
1189
+ return Qnil;
1190
+ }
1191
+
1192
+ PLRUBY_BEGIN(1);
1193
+ typeTup = SearchSysCache(TYPEOID,
1194
+ OidGD(arg->tupdesc->attrs[attnum]->atttypid),
1195
+ 0, 0, 0);
1196
+ if (!HeapTupleIsValid(typeTup)) {
1197
+ rb_raise(pl_ePLruby, "Cache lookup for attribute '%s' type %ld failed",
1198
+ RSTRING_PTR(key), OidGD(arg->tupdesc->attrs[attnum]->atttypid));
1199
+ }
1200
+ fpg = (Form_pg_type) GETSTRUCT(typeTup);
1201
+ ReleaseSysCache(typeTup);
1202
+ arg->modnulls[attnum] = ' ';
1203
+ fmgr_info(fpg->typinput, &finfo);
1204
+ PLRUBY_END;
1205
+ if (fpg->typelem != 0 && fpg->typlen == -1) {
1206
+ pl_proc_desc prodesc;
1207
+
1208
+ MEMZERO(&prodesc, pl_proc_desc, 1);
1209
+ prodesc.result_oid = fpg->typelem;
1210
+ PLRUBY_BEGIN(1);
1211
+ typeTup = SearchSysCache(TYPEOID, OidGD(prodesc.result_oid), 0, 0, 0);
1212
+ if (!HeapTupleIsValid(typeTup)) {
1213
+ rb_raise(pl_ePLruby, "cache lookup failed for type %u",
1214
+ prodesc.result_elem);
1215
+ }
1216
+ fpg = (Form_pg_type) GETSTRUCT(typeTup);
1217
+ fmgr_info(fpg->typinput, &finfo);
1218
+ prodesc.result_func = finfo;
1219
+ prodesc.result_elem = prodesc.result_oid;
1220
+ prodesc.result_val = fpg->typbyval;
1221
+ prodesc.result_len = fpg->typlen;
1222
+ prodesc.result_align = fpg->typalign;
1223
+ ReleaseSysCache(typeTup);
1224
+ PLRUBY_END;
1225
+ arg->modvalues[attnum] = plruby_return_array(value, &prodesc);
1226
+ }
1227
+ else {
1228
+ arg->modvalues[attnum] =
1229
+ plruby_to_datum(value, &finfo,
1230
+ arg->tupdesc->attrs[attnum]->atttypid,
1231
+ fpg->typelem,
1232
+ (!VARLENA_FIXED_SIZE(arg->tupdesc->attrs[attnum]))
1233
+ ? arg->tupdesc->attrs[attnum]->attlen
1234
+ : arg->tupdesc->attrs[attnum]->atttypmod);
1235
+ }
1236
+ return Qnil;
1237
+ }
1238
+
1239
+
1240
+ #define rb_str_freeze_new2(a) rb_str_freeze(rb_tainted_str_new2(a))
1241
+
1242
+ static HeapTuple
1243
+ pl_trigger_handler(struct pl_thread_st *plth)
1244
+ {
1245
+ TriggerData *trigdata;
1246
+ char *stroid;
1247
+ HeapTuple rettup;
1248
+ TupleDesc tupdesc;
1249
+ int i, rc;
1250
+ int *modattrs;
1251
+ Datum *modvalues;
1252
+ char *modnulls;
1253
+ VALUE tg_new, tg_old, args, TG, c, tmp;
1254
+ VALUE value_proname, value_proc_desc;
1255
+ PG_FUNCTION_ARGS;
1256
+
1257
+ value_proname = pl_compile(plth, 1);
1258
+ value_proc_desc = rb_hash_aref(PLruby_hash, value_proname);
1259
+ if (NIL_P(value_proc_desc)) {
1260
+ rb_raise(pl_ePLruby, "cannot create internal procedure");
1261
+ }
1262
+ fcinfo = plth->fcinfo;
1263
+ trigdata = (TriggerData *) fcinfo->context;
1264
+ tupdesc = trigdata->tg_relation->rd_att;
1265
+ TG = rb_hash_new();
1266
+
1267
+ rb_hash_aset(TG, rb_str_freeze_new2("name"),
1268
+ rb_str_freeze_new2(trigdata->tg_trigger->tgname));
1269
+
1270
+ {
1271
+ char *s;
1272
+
1273
+ PLRUBY_BEGIN_PROTECT(1);
1274
+ s = DatumGetCString(
1275
+ DFC1(nameout, NameGD(&(trigdata->tg_relation->rd_rel->relname))));
1276
+ rb_hash_aset(TG, rb_str_freeze_new2("relname"),rb_str_freeze_new2(s));
1277
+ pfree(s);
1278
+ PLRUBY_END_PROTECT;
1279
+ }
1280
+ PLRUBY_BEGIN_PROTECT(1);
1281
+ stroid = DatumGetCString(DFC1(oidout, OidGD(trigdata->tg_relation->rd_id)));
1282
+ rb_hash_aset(TG, rb_str_freeze_new2("relid"), rb_str_freeze_new2(stroid));
1283
+ pfree(stroid);
1284
+ PLRUBY_END_PROTECT;
1285
+
1286
+ tmp = rb_ary_new2(tupdesc->natts);
1287
+ for (i = 0; i < tupdesc->natts; i++) {
1288
+ if (tupdesc->attrs[i]->attisdropped) {
1289
+ rb_ary_push(tmp, rb_str_freeze_new2(""));
1290
+ }
1291
+ else {
1292
+ rb_ary_push(tmp, rb_str_freeze_new2(NameStr(tupdesc->attrs[i]->attname)));
1293
+ }
1294
+ }
1295
+ rb_hash_aset(TG, rb_str_freeze_new2("relatts"), rb_ary_freeze(tmp));
1296
+
1297
+ if (TRIGGER_FIRED_BEFORE(trigdata->tg_event)) {
1298
+ rb_hash_aset(TG, rb_str_freeze_new2("when"), INT2FIX(TG_BEFORE));
1299
+ }
1300
+ else if (TRIGGER_FIRED_AFTER(trigdata->tg_event)) {
1301
+ rb_hash_aset(TG, rb_str_freeze_new2("when"), INT2FIX(TG_AFTER));
1302
+ }
1303
+ else {
1304
+ rb_raise(pl_ePLruby, "unknown WHEN event (%u)", trigdata->tg_event);
1305
+ }
1306
+
1307
+ if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) {
1308
+ rb_hash_aset(TG, rb_str_freeze_new2("level"),INT2FIX(TG_ROW));
1309
+ }
1310
+ else if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event)) {
1311
+ rb_hash_aset(TG, rb_str_freeze_new2("level"), INT2FIX(TG_STATEMENT));
1312
+ }
1313
+ else {
1314
+ rb_raise(pl_ePLruby, "unknown LEVEL event (%u)", trigdata->tg_event);
1315
+ }
1316
+
1317
+ tg_old = Qnil;
1318
+ tg_new = Qnil;
1319
+ rettup = NULL;
1320
+ if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) {
1321
+ rb_hash_aset(TG, rb_str_freeze_new2("op"), INT2FIX(TG_INSERT));
1322
+ if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) {
1323
+ tg_new = plruby_build_tuple(trigdata->tg_trigtuple, tupdesc, RET_HASH);
1324
+ tg_old = rb_hash_new();
1325
+ rettup = trigdata->tg_trigtuple;
1326
+ }
1327
+ }
1328
+ else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) {
1329
+ rb_hash_aset(TG, rb_str_freeze_new2("op"), INT2FIX(TG_DELETE));
1330
+ if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) {
1331
+ tg_old = plruby_build_tuple(trigdata->tg_trigtuple, tupdesc, RET_HASH);
1332
+ tg_new = rb_hash_new();
1333
+ rettup = trigdata->tg_trigtuple;
1334
+ }
1335
+ }
1336
+ else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) {
1337
+ rb_hash_aset(TG, rb_str_freeze_new2("op"), INT2FIX(TG_UPDATE));
1338
+ if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) {
1339
+ tg_new = plruby_build_tuple(trigdata->tg_newtuple, tupdesc, RET_HASH);
1340
+ tg_old = plruby_build_tuple(trigdata->tg_trigtuple, tupdesc, RET_HASH);
1341
+ rettup = trigdata->tg_newtuple;
1342
+ }
1343
+ }
1344
+ else {
1345
+ rb_raise(pl_ePLruby, "unknown OP event (%u)", trigdata->tg_event);
1346
+ }
1347
+ rb_hash_freeze(TG);
1348
+
1349
+ args = rb_ary_new2(trigdata->tg_trigger->tgnargs);
1350
+ for (i = 0; i < trigdata->tg_trigger->tgnargs; i++) {
1351
+ rb_ary_push(args, rb_str_freeze_new2(trigdata->tg_trigger->tgargs[i]));
1352
+ }
1353
+ rb_ary_freeze(args);
1354
+
1355
+ c = rb_funcall(pl_mPLtemp, rb_intern(RSTRING_PTR(value_proname)),
1356
+ 4, tg_new, tg_old, args, TG);
1357
+
1358
+ PLRUBY_BEGIN_PROTECT(1);
1359
+ MemoryContextSwitchTo(plruby_spi_context);
1360
+ if ((rc = SPI_finish()) != SPI_OK_FINISH) {
1361
+ elog(ERROR, "SPI_finish() failed : %d", rc);
1362
+ }
1363
+ PLRUBY_END_PROTECT;
1364
+
1365
+ switch (TYPE(c)) {
1366
+ case T_TRUE:
1367
+ return rettup;
1368
+ break;
1369
+ case T_FALSE:
1370
+ return (HeapTuple) NULL;
1371
+ break;
1372
+ case T_FIXNUM:
1373
+ if (NUM2INT(c) == TG_OK) {
1374
+ return rettup;
1375
+ }
1376
+ if (NUM2INT(c) == TG_SKIP) {
1377
+ return (HeapTuple) NULL;
1378
+ }
1379
+ rb_raise(pl_ePLruby, "Invalid return code");
1380
+ break;
1381
+ case T_STRING:
1382
+ c = plruby_to_s(c);
1383
+ if (strcmp(RSTRING_PTR(c), "OK") == 0) {
1384
+ return rettup;
1385
+ }
1386
+ if (strcmp(RSTRING_PTR(c), "SKIP") == 0) {
1387
+ return (HeapTuple) NULL;
1388
+ }
1389
+ rb_raise(pl_ePLruby, "unknown response %s", RSTRING_PTR(c));
1390
+ break;
1391
+ case T_HASH:
1392
+ break;
1393
+ default:
1394
+ rb_raise(pl_ePLruby, "Invalid return value");
1395
+ break;
1396
+ }
1397
+
1398
+ if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) {
1399
+ rb_raise(pl_ePLruby, "Invalid return value for per-statement trigger");
1400
+ }
1401
+
1402
+ modattrs = ALLOCA_N(int, tupdesc->natts);
1403
+ modvalues = ALLOCA_N(Datum, tupdesc->natts);
1404
+ for (i = 0; i < tupdesc->natts; i++) {
1405
+ modattrs[i] = i + 1;
1406
+ modvalues[i] = (Datum) NULL;
1407
+ }
1408
+
1409
+ modnulls = ALLOCA_N(char, tupdesc->natts + 1);
1410
+ memset(modnulls, 'n', tupdesc->natts);
1411
+ modnulls[tupdesc->natts] = '\0';
1412
+ {
1413
+ struct foreach_fmgr *mgr;
1414
+ VALUE res;
1415
+
1416
+ res = Data_Make_Struct(rb_cObject, struct foreach_fmgr, 0, free, mgr);
1417
+ mgr->tupdesc = tupdesc;
1418
+ mgr->modattrs = modattrs;
1419
+ mgr->modvalues = modvalues;
1420
+ mgr->modnulls = modnulls;
1421
+ rb_iterate(rb_each, c, for_numvals, res);
1422
+ }
1423
+
1424
+ PLRUBY_BEGIN_PROTECT(1);
1425
+ rettup = SPI_modifytuple(trigdata->tg_relation, rettup, tupdesc->natts,
1426
+ modattrs, modvalues, modnulls);
1427
+ PLRUBY_END_PROTECT;
1428
+
1429
+ if (rettup == NULL) {
1430
+ rb_raise(pl_ePLruby, "SPI_modifytuple() failed - RC = %d\n", SPI_result);
1431
+ }
1432
+
1433
+ return rettup;
1434
+ }
1435
+
1436
+ static int pl_convert_function = 0;
1437
+
1438
+ static int
1439
+ pl_exist_singleton()
1440
+ {
1441
+ int spi_rc;
1442
+
1443
+ pl_convert_function = 0;
1444
+ spi_rc = SPI_exec("select 1 from pg_class where relname = 'plruby_singleton_methods'", 1);
1445
+ SPI_freetuptable(SPI_tuptable);
1446
+ if (spi_rc != SPI_OK_SELECT || SPI_processed == 0) {
1447
+ return 0;
1448
+ }
1449
+ spi_rc = SPI_exec("select name from plruby_singleton_methods", 0);
1450
+ SPI_freetuptable(SPI_tuptable);
1451
+ if (spi_rc != SPI_OK_SELECT || SPI_processed == 0) {
1452
+ return 0;
1453
+ }
1454
+ #ifdef PLRUBY_ENABLE_CONVERSION
1455
+ spi_rc = SPI_exec("select name from plruby_singleton_methods where name = '***'", 1);
1456
+ if (spi_rc == SPI_OK_SELECT && SPI_processed != 0) {
1457
+ pl_convert_function = 1;
1458
+ }
1459
+ #endif
1460
+ return 1;
1461
+ }
1462
+
1463
+ static char *recherche =
1464
+ "select name, args, body from plruby_singleton_methods where name = '%s'";
1465
+
1466
+ static char *singleton = "select prosrc from pg_proc,pg_language,pg_type"
1467
+ " where proname = '%s' and pg_proc.prolang = pg_language.oid"
1468
+ " and pg_language.lanname = 'plruby'"
1469
+ " and prorettype = pg_type.oid and typname != 'trigger'";
1470
+
1471
+ static char *def_singleton = "def PLtemp.%s(*args)\n%s\nend";
1472
+
1473
+ #ifndef HAVE_RB_BLOCK_CALL
1474
+ static VALUE
1475
+ pl_each(tmp)
1476
+ VALUE *tmp;
1477
+ {
1478
+ return rb_funcall2(tmp[0], (ID)tmp[1], (int)tmp[2], (VALUE *)tmp[3]);
1479
+ }
1480
+ #endif
1481
+
1482
+ static VALUE
1483
+ pl_load_singleton(argc, argv, obj)
1484
+ int argc;
1485
+ VALUE *argv;
1486
+ VALUE obj;
1487
+ {
1488
+ int spi_rc, status;
1489
+ ID id;
1490
+ char *nom, *buff;
1491
+ int fname, fargs, fbody;
1492
+ char *name, *args, *body;
1493
+ char *sinm;
1494
+ int in_singleton = 0;
1495
+
1496
+ if (argc <= 0) {
1497
+ rb_raise(rb_eArgError, "no id given");
1498
+ }
1499
+ id = SYM2ID(argv[0]);
1500
+ argc--; argv++;
1501
+ nom = (char *)rb_id2name(id);
1502
+ buff = ALLOCA_N(char, 1 + strlen(recherche) + strlen(nom));
1503
+ sprintf(buff, recherche, nom);
1504
+
1505
+ PLRUBY_BEGIN_PROTECT(1);
1506
+ spi_rc = SPI_exec(buff, 0);
1507
+ PLRUBY_END_PROTECT;
1508
+
1509
+ if (spi_rc != SPI_OK_SELECT || SPI_processed == 0) {
1510
+ SPI_freetuptable(SPI_tuptable);
1511
+ if (pl_convert_function) {
1512
+ buff = ALLOCA_N(char, 1 + strlen(singleton) + strlen(nom));
1513
+ sprintf(buff, singleton, nom);
1514
+
1515
+ PLRUBY_BEGIN_PROTECT(1);
1516
+ spi_rc = SPI_exec(buff, 1);
1517
+ PLRUBY_END_PROTECT;
1518
+ if (spi_rc != SPI_OK_SELECT || SPI_processed == 0) {
1519
+ SPI_freetuptable(SPI_tuptable);
1520
+ rb_raise(rb_eNameError,
1521
+ "undefined method `%s' for PLtemp:Module", nom);
1522
+ }
1523
+ in_singleton = 1;
1524
+ }
1525
+ else {
1526
+ rb_raise(rb_eNameError, "undefined method `%s' for PLtemp:Module", nom);
1527
+ }
1528
+ }
1529
+ if (!in_singleton) {
1530
+ fname = SPI_fnumber(SPI_tuptable->tupdesc, "name");
1531
+ fargs = SPI_fnumber(SPI_tuptable->tupdesc, "args");
1532
+ fbody = SPI_fnumber(SPI_tuptable->tupdesc, "body");
1533
+ name = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, fname);
1534
+ args = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, fargs);
1535
+ body = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, fbody);
1536
+ SPI_freetuptable(SPI_tuptable);
1537
+ sinm = ALLOCA_N(char, 1 + strlen(definition) + strlen(name) +
1538
+ strlen(args) + strlen(body));
1539
+ sprintf(sinm, definition, name, args, body);
1540
+ }
1541
+ else {
1542
+ fbody = SPI_fnumber(SPI_tuptable->tupdesc, "prosrc");
1543
+ body = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, fbody);
1544
+ SPI_freetuptable(SPI_tuptable);
1545
+ sinm = ALLOCA_N(char, 1 + strlen(def_singleton) + strlen(nom) + strlen(body));
1546
+ sprintf(sinm, def_singleton, nom, body);
1547
+ }
1548
+ rb_eval_string_protect(sinm, &status);
1549
+ if (status) {
1550
+ VALUE s = plruby_to_s(rb_gv_get("$!"));
1551
+ rb_raise(pl_ePLruby, "cannot create internal procedure\n%s\n<<===%s\n===>>",
1552
+ RSTRING_PTR(s), sinm);
1553
+ }
1554
+ if (rb_block_given_p()) {
1555
+ #ifdef HAVE_RB_BLOCK_CALL
1556
+ return rb_block_call(obj, id, argc, argv, rb_yield, 0);
1557
+ #else
1558
+ VALUE tmp[4];
1559
+
1560
+ tmp[0] = obj;
1561
+ tmp[1] = (VALUE)id;
1562
+ tmp[2] = (VALUE)argc;
1563
+ tmp[3] = (VALUE)argv;
1564
+ return rb_iterate((VALUE(*)(VALUE))pl_each, (VALUE)tmp, rb_yield, 0);
1565
+ #endif
1566
+ }
1567
+ return rb_funcall2(pl_mPLtemp, id, argc, argv);
1568
+ }
1569
+
1570
+ static VALUE plans;
1571
+
1572
+ extern void Init_plruby_pl();
1573
+ extern void Init_plruby_trans();
1574
+
1575
+ static void
1576
+ pl_init_all(void)
1577
+ {
1578
+ VALUE pl_mPL;
1579
+
1580
+ if (pl_fatal) {
1581
+ elog(ERROR, "initialization not possible");
1582
+ }
1583
+ if (!pl_firstcall) {
1584
+ return;
1585
+ }
1586
+ pl_fatal = 1;
1587
+ ruby_init();
1588
+ #if PLRUBY_ENABLE_CONVERSION || MAIN_SAFE_LEVEL < 3
1589
+ ruby_init_loadpath();
1590
+ #endif
1591
+ pl_init_conversions();
1592
+ #ifdef DEBUG
1593
+ rb_define_global_const("DEBUG", INT2FIX(DEBUG));
1594
+ #else
1595
+ #ifdef DEBUG1
1596
+ rb_define_global_const("DEBUG", INT2FIX(DEBUG1));
1597
+ #endif
1598
+ #endif
1599
+ #ifdef DEBUG1
1600
+ rb_define_global_const("DEBUG1", INT2FIX(DEBUG1));
1601
+ #endif
1602
+ #ifdef DEBUG2
1603
+ rb_define_global_const("DEBUG2", INT2FIX(DEBUG2));
1604
+ #endif
1605
+ #ifdef DEBUG3
1606
+ rb_define_global_const("DEBUG3", INT2FIX(DEBUG3));
1607
+ #endif
1608
+ #ifdef DEBUG4
1609
+ rb_define_global_const("DEBUG4", INT2FIX(DEBUG4));
1610
+ #endif
1611
+ #ifdef DEBUG5
1612
+ rb_define_global_const("DEBUG5", INT2FIX(DEBUG5));
1613
+ #endif
1614
+ #ifdef INFO
1615
+ rb_define_global_const("INFO", INT2FIX(INFO));
1616
+ #endif
1617
+ #ifdef NOTICE
1618
+ rb_define_global_const("NOTICE", INT2FIX(NOTICE));
1619
+ #endif
1620
+ #ifdef WARNING
1621
+ rb_define_global_const("WARNING", INT2FIX(WARNING));
1622
+ #endif
1623
+ #ifdef WARN
1624
+ rb_define_global_const("WARN", INT2FIX(WARN));
1625
+ #endif
1626
+ #ifdef FATAL
1627
+ rb_define_global_const("FATAL", INT2FIX(FATAL));
1628
+ #endif
1629
+ #ifdef ERROR
1630
+ rb_define_global_const("ERROR", INT2FIX(ERROR));
1631
+ #endif
1632
+ #ifdef NOIND
1633
+ rb_define_global_const("NOIND", INT2FIX(NOIND));
1634
+ #endif
1635
+ if (rb_const_defined_at(rb_cObject, rb_intern("PL")) ||
1636
+ rb_const_defined_at(rb_cObject, rb_intern("PLtemp"))) {
1637
+ elog(ERROR, "module already defined");
1638
+ }
1639
+ id_to_s = rb_intern("to_s");
1640
+ Init_plruby_pl();
1641
+ Init_plruby_trans();
1642
+ pl_mPL = rb_const_get(rb_cObject, rb_intern("PL"));
1643
+ pl_ePLruby = rb_const_get(pl_mPL, rb_intern("Error"));
1644
+ pl_eCatch = rb_const_get(pl_mPL, rb_intern("Catch"));
1645
+ pl_mPLtemp = rb_const_get(rb_cObject, rb_intern("PLtemp"));
1646
+ pl_sPLtemp = rb_singleton_class(pl_mPLtemp);
1647
+ id_raise = rb_intern("raise");
1648
+ id_kill = rb_intern("kill");
1649
+ id_alive = rb_intern("alive?");
1650
+ id_value = rb_intern("value");
1651
+ id_call = rb_intern("call");
1652
+ id_thr = rb_intern("__functype__");
1653
+ #ifdef PLRUBY_TIMEOUT
1654
+ rb_funcall(rb_thread_main(), rb_intern("priority="), 1, INT2NUM(10));
1655
+ rb_undef_method(CLASS_OF(rb_cThread), "new");
1656
+ rb_undef_method(CLASS_OF(rb_cThread), "start");
1657
+ rb_undef_method(CLASS_OF(rb_cThread), "fork");
1658
+ rb_undef_method(CLASS_OF(rb_cThread), "critical=");
1659
+ #endif
1660
+ rb_set_safe_level(MAIN_SAFE_LEVEL);
1661
+ PLruby_hash = rb_hash_new();
1662
+ rb_global_variable(&PLruby_hash);
1663
+ plans = rb_hash_new();
1664
+ rb_define_variable("$Plans", &plans);
1665
+ if (SPI_connect() != SPI_OK_CONNECT) {
1666
+ elog(ERROR, "plruby_singleton_methods : SPI_connect failed");
1667
+ }
1668
+ if (pl_exist_singleton()) {
1669
+ rb_define_module_function(pl_mPLtemp, "method_missing", pl_load_singleton, -1);
1670
+ }
1671
+ if (SPI_finish() != SPI_OK_FINISH) {
1672
+ elog(ERROR, "plruby_singleton_methods : SPI_finish failed");
1673
+ }
1674
+ pl_fatal = pl_firstcall = 0;
1675
+ return;
1676
+ }