globegit-postgresql-plruby 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }