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.
- data/Changes +121 -0
- data/README.markdown +155 -0
- data/Rakefile +48 -0
- data/docs/plruby.rb +1931 -0
- data/ex_trans.sql +33 -0
- data/extconf.rb +267 -0
- data/plruby.html +1454 -0
- data/plruby.rd +1571 -0
- data/postgresql-plruby.gemspec +56 -0
- data/src/conversions.h +5 -0
- data/src/conversions/basic/conversions.h +25 -0
- data/src/conversions/basic/extconf.rb +8 -0
- data/src/conversions/basic/plruby_basic.c +357 -0
- data/src/conversions/bitstring/bitstring.sql +75 -0
- data/src/conversions/bitstring/conversions.h +15 -0
- data/src/conversions/bitstring/extconf.rb +8 -0
- data/src/conversions/bitstring/plruby_bitstring.c +579 -0
- data/src/conversions/convcommon.h +129 -0
- data/src/conversions/datetime/conversions.h +13 -0
- data/src/conversions/datetime/extconf.rb +8 -0
- data/src/conversions/datetime/plruby_datetime.c +269 -0
- data/src/conversions/geometry/conversions.h +37 -0
- data/src/conversions/geometry/extconf.rb +8 -0
- data/src/conversions/geometry/geometry.sql +196 -0
- data/src/conversions/geometry/plruby_geometry.c +2494 -0
- data/src/conversions/network/conversions.h +21 -0
- data/src/conversions/network/extconf.rb +8 -0
- data/src/conversions/network/network.sql +63 -0
- data/src/conversions/network/plruby_network.c +537 -0
- data/src/package.h +20 -0
- data/src/plpl.c +1708 -0
- data/src/plplan.c +893 -0
- data/src/plruby.c +1676 -0
- data/src/plruby.h +324 -0
- data/src/pltrans.c +388 -0
- data/test/conv_bitstring/b.rb +45 -0
- data/test/conv_bitstring/runtest +26 -0
- data/test/conv_bitstring/test.expected.73 +148 -0
- data/test/conv_bitstring/test.expected.74 +148 -0
- data/test/conv_bitstring/test.expected.80 +148 -0
- data/test/conv_bitstring/test.expected.81 +148 -0
- data/test/conv_bitstring/test.expected.82 +148 -0
- data/test/conv_bitstring/test.expected.83 +148 -0
- data/test/conv_bitstring/test.expected.84 +148 -0
- data/test/conv_bitstring/test.out +148 -0
- data/test/conv_bitstring/test_mklang.sql +8 -0
- data/test/conv_bitstring/test_queries.sql +63 -0
- data/test/conv_bitstring/test_queries.sql.in +63 -0
- data/test/conv_geometry/b.rb +45 -0
- data/test/conv_geometry/runtest +26 -0
- data/test/conv_geometry/test.expected.73 +265 -0
- data/test/conv_geometry/test.expected.74 +265 -0
- data/test/conv_geometry/test.expected.80 +265 -0
- data/test/conv_geometry/test.expected.81 +265 -0
- data/test/conv_geometry/test.expected.82 +265 -0
- data/test/conv_geometry/test.expected.83 +265 -0
- data/test/conv_geometry/test.expected.84 +265 -0
- data/test/conv_geometry/test.out +265 -0
- data/test/conv_geometry/test_mklang.sql +8 -0
- data/test/conv_geometry/test_queries.sql +194 -0
- data/test/conv_geometry/test_queries.sql.in +194 -0
- data/test/conv_network/b.rb +45 -0
- data/test/conv_network/runtest +26 -0
- data/test/conv_network/test.expected.73 +213 -0
- data/test/conv_network/test.expected.74 +237 -0
- data/test/conv_network/test.expected.80 +237 -0
- data/test/conv_network/test.expected.81 +237 -0
- data/test/conv_network/test.expected.82 +237 -0
- data/test/conv_network/test.expected.83 +237 -0
- data/test/conv_network/test.expected.84 +237 -0
- data/test/conv_network/test.out +237 -0
- data/test/conv_network/test_mklang.sql +8 -0
- data/test/conv_network/test_queries.sql +60 -0
- data/test/conv_network/test_queries.sql.in +60 -0
- data/test/plp/b.rb +34 -0
- data/test/plp/runtest +29 -0
- data/test/plp/test.expected.73 +472 -0
- data/test/plp/test.expected.74 +472 -0
- data/test/plp/test.expected.75 +472 -0
- data/test/plp/test.expected.80 +472 -0
- data/test/plp/test.expected.81 +472 -0
- data/test/plp/test.expected.82 +472 -0
- data/test/plp/test.expected.83 +472 -0
- data/test/plp/test.expected.84 +472 -0
- data/test/plp/test.out +472 -0
- data/test/plp/test_mklang.sql +8 -0
- data/test/plp/test_queries.sql +273 -0
- data/test/plp/test_setup.sql +931 -0
- data/test/plp/test_setup.sql.in +931 -0
- data/test/plt/b.rb +34 -0
- data/test/plt/runtest +29 -0
- data/test/plt/test.expected.73 +178 -0
- data/test/plt/test.expected.74 +178 -0
- data/test/plt/test.expected.75 +178 -0
- data/test/plt/test.expected.80 +178 -0
- data/test/plt/test.expected.81 +178 -0
- data/test/plt/test.expected.82 +178 -0
- data/test/plt/test.expected.83 +164 -0
- data/test/plt/test.expected.84 +168 -0
- data/test/plt/test.out +168 -0
- data/test/plt/test_mklang.sql +8 -0
- data/test/plt/test_queries.sql +72 -0
- data/test/plt/test_setup.sql +252 -0
- data/test/plt/test_setup.sql.in +252 -0
- data/test/range/b.rb +45 -0
- data/test/range/runtest +26 -0
- data/test/range/test.expected.73 +396 -0
- data/test/range/test.expected.73.in +396 -0
- data/test/range/test.expected.74 +396 -0
- data/test/range/test.expected.74.in +396 -0
- data/test/range/test.expected.75 +396 -0
- data/test/range/test.expected.75.in +396 -0
- data/test/range/test.expected.80 +396 -0
- data/test/range/test.expected.81 +397 -0
- data/test/range/test.expected.82 +397 -0
- data/test/range/test.expected.83 +397 -0
- data/test/range/test.expected.84 +399 -0
- data/test/range/test.out +399 -0
- data/test/range/test_mklang.sql +8 -0
- data/test/range/test_queries.sql +249 -0
- data/test/range/test_queries.sql.in +249 -0
- metadata +207 -0
data/src/plruby.c
ADDED
|
@@ -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
|
+
}
|